Google Wave’s Federation Protocol Under the Hood, Part 3

Posted Feb 12, 2010 by Anthony in Architecture, Blogs, Google Wave

Purpose [Updated 4/3/2010]

This is the third post in the series dedicated to the design of FedOne.  I am taking a quick aside to show the dependency object graph as managed by Guice.  I found it quite interesting to view a picture of how many of the components were associated.  There are dependencies that are not captured by Guice and are therefore not present in the graph, however, I would suggest that the areas where dependency injection was used are most likely suitable for alternative implementations (if you decide to develop your own wave server).

Dependency Object Graph

It became apparent upon creating the Activity Diagram that it would be helpful to illustrate the dependencies as resolved by Guice.  Guice 2.0 has a Grapher module that will produce a .dot file that can be visualized with GraphViz.  Read Instructions here.  However, Grapher is an extension that is NOT bundled with Wave or the pre-compiled Guice libraries, so you will have to download Guice src and build Grapher (located in extension/grapher).

Following is the complete image (click image to open new window at full-size) ran on my Wave Server.

Legend

Nodes:
  • Dashed Nodes are Interfaces or Abstract Classes
  • Black backgrounds denote Implementation types
  • Gray backgrounds denote Implementation Instances
Edges:
  • Solid edges represent dependencies (think the parameters of a constructor)
  • Dashed edges represent bindings from types to their implementations (think subclasses or implementation of an interface)
  • Double arrows represent that the binding or dependency is to a Provider (Provider is a Guice construct)
I will focus on one aspect of the object graph to demonstrate how Guice is utilized and why viewing the dependencies may not be straightforward at first glance.

The following image illustrates the instantiation of the ProtocolWaveClient interface.  I will only traverse to the 3rd dependency at ClientFrontEndImpl.

In the run() method of fedone.ServerMain you will find:

[code]
Injector injector = Guice.createInjector(new ServerModule(), flags);
    …
ProtocolWaveClientRpc.Interface rpcImpl = injector.getInstance(
        ProtocolWaveClientRpc.Interface.class);
[/code]

The injector.getInstance(ProtocolWaveClientRpc.Interface.class) requests Guice to find the associated dependency, which we can see from the graph is satisfied by WaveClientRpcImpl.  To see how this connection is made, we will examine the first line in the run() method that created the injector [Guice.createInjector(new ServerModule(), flags)].

In the configure() method of fedone.ServerModule(), we find:

[code]
 // Receive updates from the outside world, and push them into our local Wave Server.
    bind(WaveletFederationListener.Factory.class).annotatedWith(FederationRemoteBridge.class)
        .to(WaveServer.class);
    …
    install(new WaveServerModule());
    bind(String.class).annotatedWith(Names.named(”privateKey”)).toInstance(”");
    …
[/code]

Since we do not find a binding associated with ProtocolWaveClientRpc in this configure() method, we will step into the configure() method of fedone.waveserver.WaveServerModule() (note we are in a different package).  Here we find:

[code]
 bind(CertPathStore.class).to(DefaultCertPathStore.class).in(Singleton.class);
    …
    bind(ClientFrontend.class).to(ClientFrontendImpl.class).in(Singleton.class);
    bind(ProtocolWaveClientRpc.Interface.class).to(WaveClientRpcImpl.class).in(Singleton.class);
    …
[/code]

Now we see the bind statement that creates the actual dependency to the WaveClientRpcImpl class (which btw is a Singleton class).  The resolution does not end here since stepping into the constructor of the fedone.waveserver.WaveClientRpcImpl class reveals a dependency on ClientFrontend:

[code]
  /**
   * Constructor.
   *
   * @param frontend ClientFrontend that consumes the operations.
   */
  @Inject
  public WaveClientRpcImpl(ClientFrontend frontend) {
    this.frontend = frontend;
  }
[/code]

Since we see the @Inject annotation, we know that Guice will provide this value as well.  Since we are still in the path of the same Injector that was originally created I will look back into either the flag, ServerModule, or WaveServerModule modules.  Since ClientFrontend is a class in fedone.waveserver, we expect and do indeed find the binding in the configure() method of fedone.waveserver.WaveServerModule().  This is denoted above in the excerpt of that class [bind(ClientFrontend.class).to(ClientFrontendImpl.class).in(Singleton.class);]. I will stop here, but you will also note from the graph or if you explore ClientFrontendImpl that there is another dependency within the constructor that calls for a WaveletProvider, which Guice must also resolve.

I can hear some of you now saying “OMG, there are so many levels of indirection.  Why would you ever do this?”.  First I would point out that our dependencies exist regardless of using Guice.  Usually these dependencies are just littered throughout the code making it more difficult to locate and switch to different implementations.  Guice takes these bindings and places them in defined areas that, once you are familiar with Guice and the codebase, can be located fairly easily.  This makes testing more efficient as bindings can be switched without much effort.  As you have seen, object graphs can be created which will illustrate dependencies within your code managed by Guice giving you a better overall understanding of the structure of your project.  Guice is also typesafe such that at compile time you will know if a binding was left out or applied incorrectly.

If you are curious where the command line Flags are used within Wave, just take a look at the object graph.  Since they are instances they will be located in gray nodes and will tell you the java File and line number where it was resolved as well as the value passed in.  For instance, the ComponentPacketTransport uses several.

Next in Series

The next post investigates the XMPP to WaveServer communication methods.  All methods related to incoming or outgoing packets through XMPP will be covered as implemented in code (as opposed to what is documented).

Related posts:

  1. MongoWave: Persistence on Google FedOne Wave Server with mongoDB Purpose My company, SESI, has been working on applying...
  2. Google Wave’s Federation Protocol Under the Hood, Part 1 Purpose [Updated 4/3/2010] This post is the first in...
  3. Google Wave’s Federation Protocol Under the Hood, Part 2 Purpose [Updated 4/3/2010] This post is the second in a...
  4. Google Wave’s Federation Protocol Under the Hood, Part 5 Purpose [Updated 4/3/2010] This is the fifth and final post...
  5. Google Wave’s Federation Protocol Under the Hood, Part 4 Purpose [Updated 4/3/2010] This is the fourth post in...

Related posts brought to you by Yet Another Related Posts Plugin.

Tags: , , , ,

One Response to “Google Wave’s Federation Protocol Under the Hood, Part 3”

  1. [...] Google Wave’s Federation Protocol Under the Hood, Part 3 [...]

    Reply to this comment

Leave a Reply

Subscribe without commenting