Monday, 12 July 2010

Java Shindig: how to connect to real database (Updated July-2011)

I decided finally to switch to Java Shindig from PHP Shindig due to the better support and development of the first one. I had my working shindig installation for PHP with my own social database. I wanted to have the same with Java Shindig. It turned out to be much harder to set it up in Java (maybe because of my java and maven ignorance). In PHP I only changed the database settings and added my own PersonService, AppDataService implementations. In Java the concept is the same but the way it is done was not that obvious for me. So, here is what I did.

1) I downloaded the shindig trunk from here:


2) To use database in Shindig one could take advantage of existing in shindig "samples" project that uses JPA and EclipseLink to connect to the database from Java. This how I compile the project:
3) First of all we need to add JPASocialModule.java into Shindig's Guice modules. This module will provide real database implementations for PersonService, AppDataService, etc. One should add this module in java/server/src/main/webapp/WEB-INF/web.xml. Some default Guice modules should be removed from this file in order to avoid compilation problems. This is how this file looks for me.

I also had to change the SocialApiGuiceModule.java to add a sample OAuthDataStore. I also had to change the JPASocialModule.java to add a sample implementation for MediaItemService, MessageService, AlbumService. 4) We will have to recompile shindig with database support now. We have to change 3 files. trunk/pom.xml - add samples module to default "all" and "run" and to dependencyManagement.
trunk/java/server/pom.xml - add dependency on shindig-samples

trunk/java/samples/pom.xml - add dependency on mysql driver (since I use mysql database)


Now to compile the project with maven command as in 2)

5) Generate signing keys for oAuth with the following commands.
Add the keys information into java/common/conf/shindig.properties. Don't forget the full path to your oauthkey.pem!! 6) Add your database information to java/samples/src/main/resources/socialjpa.properties. I use mysql database, so my settings are mysql specific. 7) Create database shindig and give access to it for user "shindig" with password "shindig". 8) Compile now the project and run jetty server according to 2). The tables will be created in the database based on shindig's default database structure. 9) When database is created, add manually a row to the Person table with oid = 1, person_id = 1 and display_name = Shindig User 10) Run the jetty server as explained in 2) (Ignore errors that tables already exist). Now execute a social request in your browser. You should get back a json response (I had to reload page 3 times to get it) So, this is a proof-of-concept step on how to connect Shindig to a real database. Next will be how to change shindig classes to connect to my own database!

11 comments:

  1. Great job! I look forward to the rest of your blog as you go through this process. Keep up the good work!

    Andre

    ReplyDelete
  2. Hey, just read about this post, very useful things! Thanks for your work.

    I have a question that about the oauth token part.

    shindig.signing.key-name=mytestkey
    shindig.signing.key-file=/path_to_shindig_branch/ssl_keys/oauthkey.pem

    why would you need to create such key, and why "mytestky", and can you pls give a example for the path of oauthkey.pem?

    ReplyDelete
  3. "mytestkey" is any name

    example:
    /var/shindig/trunk/ssl_keys/oauthkey.pem

    I do not know what exactly it does, but I had to do this, since otherwise shindig didn't want to compile properly :)

    ReplyDelete
  4. Hey Evgeny, thank you for this quick response.

    So the path "path_to_shindig_branch" should be an absolute path to oauthkey.pem, right?

    If I am on Window, the path should be like "D:/shindig-project/ssl_keys/oauthkey.pem" and put in shindig.properties, right?

    Thanks.

    ReplyDelete
  5. Following the steps, I do see tables being created in my MySQL database. However when I try to go the URL, I get the following exception

    com.google.inject.ConfigurationException: Guice configuration errors:

    1) No implementation for org.apache.shindig.social.opensocial.spi.MediaItemService was bound.
    while locating org.apache.shindig.social.opensocial.spi.MediaItemService
    for parameter 0 at org.apache.shindig.social.opensocial.service.MediaItemHandler.(MediaItemHandler.java:53)
    while locating org.apache.shindig.social.opensocial.service.MediaItemHandler

    Any idea what am I doing incorrect?

    ReplyDelete
  6. You seem to be using Shindig 2.0 or later.

    You normally have to provide your own implementation for MediaItemService, MessageService, AlbumService (similarily to PersonServiceDb.java, ActivityServiceDb.java; see org.apache.shindig.graaasp.jpa.spi).

    If you just want example to work (and maybe provide implementation for this services later), you could add into file JPASocialModule.java the following import:
    import org.apache.shindig.social.sample.spi.JsonDbOpensocialService;

    and temporal JSON implementations for these services:

    protected void configure() {
    Names.bindProperties(this.binder(), properties);
    if (entityManager == null) {
    bind(EntityManager.class).toProvider(EclipseEntityManagerProvider.class)
    .in(Scopes.SINGLETON);
    } else {
    bind(EntityManager.class).toInstance(this.entityManager);
    }
    bind(ActivityService.class).to(ActivityServiceDb.class)
    .in(Scopes.SINGLETON);
    bind(PersonService.class).to(PersonServiceDb.class).in(Scopes.SINGLETON);
    bind(AppDataService.class).to(AppDataServiceDb.class).in(Scopes.SINGLETON);

    //Temporal
    bind(AlbumService.class).to(JsonDbOpensocialService.class);
    bind(MediaItemService.class).to(JsonDbOpensocialService.class);
    bind(MessageService.class).to(JsonDbOpensocialService.class);
    }

    ReplyDelete
  7. Hello Evgeny, i am new with shindig and i want to integrate my own database schema with shindig, i follow the above instructions, and when i run the jetty server as you mention in shindig's wiki and i get this error :

    java.lang.RuntimeException: java.lang.ClassNotFoundException: org.apache.shindig.social.opensocial.jpa.spi.JPASocialModule
    at org.apache.shindig.common.servlet.GuiceServletContextListener.contextInitialized(GuiceServletContextListener.java:74)
    at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:549)
    ..
    ..
    ..

    Could you help me and point what is going wrong?
    Thank you!

    ReplyDelete
    Replies
    1. Well, from your log I can see that shindig can't find JPASocialModule class. Compilation went successfully? Put full error log somewhere and send a link to it here.

      Delete
  8. Yes compilation was succesful! There were only some warnings like :

    [WARNING] Invalid POM for org.apache.shindig:shindig-common:jar:3.0.0-SNAPSHOT, transitive dependencies (if any) will not be available, enable debug logging for more details
    [WARNING] Invalid POM for org.apache.shindig:shindig-common:test-jar:tests:3.0.0-SNAPSHOT, transitive dependencies (if any) will not be available, enable debug logging for more details
    [WARNING] Invalid POM for org.apache.shindig:shindig-social-api:jar:3.0.0-SNAPSHOT, transitive dependencies (if any) will not be available, enable debug logging for more details
    [WARNING] Invalid project model for artifact [shindig-social-api:org.apache.shindig:3.0.0-SNAPSHOT]. It will be ignored by the remote resources Mojo.
    [WARNING] Invalid project model for artifact [shindig-common:org.apache.shindig:3.0.0-SNAPSHOT]. It will be ignored by the remote resources Mojo.

    ReplyDelete
  9. Here i continue...
    =============================
    And this is the full error log:

    java.lang.RuntimeException: java.lang.ClassNotFoundException: org.apache.shindig.social.opnesocial.jpa.spi.JPASocialModule
    at org.apache.shindig.common.servlet.GuiceServletContextListener.contextInitialized(GuiceServletContextListener.java:74)
    at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:549)
    at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
    at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1282)
    at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:518)
    at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:499)
    at org.mortbay.jetty.plugin.Jetty6PluginWebAppContext.doStart(Jetty6PluginWebAppContext.java:115)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152)
    at org.mortbay.jetty.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:156)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
    at org.mortbay.jetty.Server.doStart(Server.java:224)
    at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
    at org.mortbay.jetty.plugin.Jetty6PluginServer.start(Jetty6PluginServer.java:132)
    at org.mortbay.jetty.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:454)
    at org.mortbay.jetty.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:396)
    at org.mortbay.jetty.plugin.AbstractJettyRunMojo.execute(AbstractJettyRunMojo.java:210)
    at org.mortbay.jetty.plugin.Jetty6RunMojo.execute(Jetty6RunMojo.java:184)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:319)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)

    ReplyDelete