Child pages
  • Providing your own data service implementation
Skip to end of metadata
Go to start of metadata

In this session I will show how to implement the following Shindig services to connect your own datastore.

PersonService
ActivityService
AppDataService

During my first steps I have created another sample implementation where all the social data is held in memory. It's just another sample, but I think it is perfect for debugging reasons, because you can any time inspect your whole data at once.

Description

The full code is available as attachement (SampleShindigIntegrator.zip) to this site.

1. Make an implementation for all three interfaces

public Future<Person> getPerson(UserId id, Set<String> fields, SecurityToken token) throws SocialSpiException {
 
  initDB();
 
  if (id != null) {
    Person currentPerson = db.findPerson(id.getUserId(token));
    if (currentPerson != null) {
      return ImmediateFuture.newInstance(currentPerson);
    } 
  }
  throw new SocialSpiException(ResponseError.BAD_REQUEST, "Person not found");
}

Snippet of org.apache.shindig.social.spi.ShindigIntegratorPersonService.class

This implementation looks similiar to the sample implementation provided with Shindig. The big difference is, that the db instance is a instance of a class that holds the data in memory.

public class ShindigIntegratorPersistenceAdapter {

private Map<String, Person> persons;.
.
.
private void init() {
  if (persons == null) {
    // create personlist
    persons = new HashMap<String, Person>();

    Name name = new NameImpl();
    name.setGivenName("James");
    name.setFamilyName("Bond");
    name.setFormatted("James Bond");
    Person john = new PersonImpl("john.doe", "007", name);
    .
    .
    persons.put(john.getId(), john);
    .
    .
  }
}
.
.
public Person findPerson(String id) {
  Person person = persons.get(id);
  return person;
}

Snippet of org.apache.shindig.social.spi.ShindigIntegratorPersistenceAdapter.class

2. Register these classes in your own guice module

@Override
protected void configure() {
  bind(PersonService.class).to(ShindigIntegratorPersonService.class);
  bind(AppDataService.class).to(ShindigIntegratorAppDataService.class);
  bind(ActivityService.class).to(ShindigIntegratorActivityService.class);

  bind(ParameterFetcher.class).annotatedWith(Names.named("DataServiceServlet")).to(
    DataServiceServletFetcher.class);

  bind(Boolean.class).annotatedWith(Names.named(AnonymousAuthenticationHandler.ALLOW_UNAUTHENTICATED))
    .toInstance(Boolean.TRUE);

  bind(BeanConverter.class).annotatedWith(Names.named("shindig.bean.converter.xml")).to(
    BeanXStreamConverter.class);
  bind(BeanConverter.class).annotatedWith(Names.named("shindig.bean.converter.json")).to(
    BeanJsonConverter.class);
  bind(BeanConverter.class).annotatedWith(Names.named("shindig.bean.converter.atom")).to(
    BeanXStreamAtomConverter.class);
		
  bind(new TypeLiteral<List<AuthenticationHandler>>(){}).toProvider(
    AuthenticationHandlerProvider.class);
}

Snippet of org.apache.shindig.social.core.config.ShindigIntegratorGuiceModule.class

This class binds the Shindig services to the new implementations. So they will be called instead of the sample coming with Shindig. Another way to tell Shindig which implementation to use is to change the @ImplementedBy annotation in for example PersonService.class. But to me the binding solution sounds better.

For unit tests I have registered the classes in a guice module specifically for unit tests. This is done the same way as in the upper guice module.

In the unit test itself this modul has to be called on setup. In the test methods the service can then be used directly.

@Before
public void setUp() throws Exception {
  Injector injector = Guice.createInjector(new ShindigIntegratorTestsGuiceModule());
  personService = injector.getInstance(ShindigIntegratorPersonService.class);
}
.
.
.
/**
 * Tests getPerson with a UserId typed as Userid. The Id string is set in the UserId.
 * 
 * @throws Exception
 */
@Test
public void testGetExpectedPersonByUserId() throws Exception {
  Future<Person> selectedObject = personService.getPerson(JOHN_DOE, Collections.<String> emptySet(),
    new FakeGadgetToken());
  Person person = selectedObject.get();
  assertEquals(JOHN_DOE.getUserId(), person.getId());
}

Snippet of ShindigIntegratorPersonServiceTest.class

3. Register the guice module in the web.xml

In the web.xml the param guice-modules has to be changed to reference the new implementation.

<context-param>
  <param-name>guice-modules</param-name>
  <param-value>
      org.apache.shindig.common.PropertiesModule:
      org.apache.shindig.gadgets.DefaultGuiceModule:
      org.apache.shindig.social.core.config.ShindigIntegratorGuiceModule:     
      org.apache.shindig.gadgets.oauth.OAuthModule:
      org.apache.shindig.common.cache.ehcache.EhCacheModule
  </param-value>
</context-param>

Snippet of web.xml

There are several web.xml files in the shindig installation. Comments in the web.xml files indicate what they're for:

  • web.gadgets.xml: just the gadget rendering server
  • web.social.xml: just the social data / RESTful server
  • web.full.xml: both servers in a single container

4. Rebuild Shindig and you are ready

After all maven has to be run with a clean install and things are done.

After this you can run the samplecontainer as before. Just things like a dump in the samplecontainer page doesn't work as I did not implement it.

Conclusion

This documentation shows how to implement the interfaces for Shindig. Next step would be to connect to a real database.

I think Implementing this services is very straightforward. The hardest thing is to get familiarized with Shindig.

  • No labels

3 Comments

  1. I think It is not fleshed, but it's pretty good
    Where can I find next step, or any other discussions?

  2. Harry,

    Can you please let me know where can i find the next tutorial to connect to a real database.

  3. i am getting error while accessing rest after deployed the sample code.please help me to resolve this.

    here is web.xml config

    <param-value>
    org.apache.shindig.common.PropertiesModule:
    org.apache.shindig.gadgets.DefaultGuiceModule:
    org.apache.shindig.social.core.config.ShindigIntegratorGuiceModule:
    org.apache.shindig.gadgets.oauth.OAuthModule:
    org.apache.shindig.common.cache.ehcache.EhCacheModule

    </param-value>

    error:

    HTTP Status 500 -

    type Exception report

    message

    description The server encountered an internal error () that prevented it from fulfilling this request.

    exception

    javax.servlet.ServletException: Servlet.init() for servlet restapiServlet threw exception
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
    org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    java.lang.Thread.run(Thread.java:595)

    root cause

    com.google.inject.ConfigurationException: Error at org.apache.shindig.social.opensocial.service.StandardHandlerDispatcher.<init>(StandardHandlerDispatcher.java:46) Error while injecting at org.apache.shindig.social.opensocial.service.ApiServlet.setHandlerDispatcher(ApiServlet.java:51): Error while injecting at org.apache.shindig.social.opensocial.service.ApiServlet.setHandlerDispatcher(ApiServlet.java:51): Binding to com.google.inject.Provider<org.apache.shindig.social.opensocial.service.PersonHandler> not found. No bindings to that type were found.
    com.google.inject.BinderImpl$RuntimeErrorHandler.handle(BinderImpl.java:426)
    com.google.inject.InjectorImpl$3.handle(InjectorImpl.java:294)
    com.google.inject.InjectorImpl$3.handle(InjectorImpl.java:294)
    com.google.inject.AbstractErrorHandler.handle(AbstractErrorHandler.java:30)
    com.google.inject.ErrorMessages.handleMissingBinding(ErrorMessages.java:46)
    com.google.inject.InjectorImpl.getInternalFactory(InjectorImpl.java:192)
    com.google.inject.InjectorImpl.createParameterInjector(InjectorImpl.java:524)
    com.google.inject.InjectorImpl.getParametersInjectors(InjectorImpl.java:515)
    com.google.inject.ConstructorInjector.createParameterInjector(ConstructorInjector.java:57)
    com.google.inject.ConstructorInjector.<init>(ConstructorInjector.java:38)
    com.google.inject.InjectorImpl$7.create(InjectorImpl.java:601)
    com.google.inject.InjectorImpl$7.create(InjectorImpl.java:594)
    com.google.inject.util.ReferenceCache.create(ReferenceCache.java:53)
    com.google.inject.util.AbstractReferenceCache.internalCreate(AbstractReferenceCache.java:59)
    com.google.inject.util.AbstractReferenceCache.get(AbstractReferenceCache.java:116)
    com.google.inject.InjectorImpl.getConstructor(InjectorImpl.java:765)
    com.google.inject.InjectorImpl.getImplicitBinding(InjectorImpl.java:973)
    com.google.inject.InjectorImpl.getInternalFactory(InjectorImpl.java:300)
    com.google.inject.InjectorImpl.getImplicitBinding(InjectorImpl.java:898)
    com.google.inject.InjectorImpl.getInternalFactory(InjectorImpl.java:300)
    com.google.inject.InjectorImpl.createParameterInjector(InjectorImpl.java:524)
    com.google.inject.InjectorImpl.getParametersInjectors(InjectorImpl.java:515)
    com.google.inject.InjectorImpl$SingleMethodInjector.<init>(InjectorImpl.java:567)
    com.google.inject.InjectorImpl$5.create(InjectorImpl.java:360)
    com.google.inject.InjectorImpl$5.create(InjectorImpl.java:358)
    com.google.inject.InjectorImpl.addInjectorsForMembers(InjectorImpl.java:384)
    com.google.inject.InjectorImpl.addSingleInjectorsForMethods(InjectorImpl.java:356)
    com.google.inject.InjectorImpl.addInjectors(InjectorImpl.java:351)
    com.google.inject.InjectorImpl.addInjectors(InjectorImpl.java:347)
    com.google.inject.InjectorImpl$4.create(InjectorImpl.java:332)
    com.google.inject.InjectorImpl$4.create(InjectorImpl.java:329)
    com.google.inject.util.ReferenceCache.create(ReferenceCache.java:53)
    com.google.inject.util.AbstractReferenceCache.internalCreate(AbstractReferenceCache.java:59)
    com.google.inject.util.AbstractReferenceCache.get(AbstractReferenceCache.java:116)
    com.google.inject.InjectorImpl.injectMembers(InjectorImpl.java:672)
    com.google.inject.InjectorImpl$8.call(InjectorImpl.java:682)
    com.google.inject.InjectorImpl$8.call(InjectorImpl.java:681)
    com.google.inject.InjectorImpl.callInContext(InjectorImpl.java:747)
    com.google.inject.InjectorImpl.injectMembers(InjectorImpl.java:680)
    org.apache.shindig.common.servlet.InjectedServlet.init(InjectedServlet.java:46)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
    org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
    org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
    java.lang.Thread.run(Thread.java:595)

    note The full stack trace of the root cause is available in the Apache Tomcat/6.0.18 logs.