Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Protocol

Most of the communication between the client code (JavaScript) and the server code (Java) is done via JSON. A request is sent by the client code in the form of a single URL. The parameters to the call are in the URL as part of the path, not as HTTP parameters. The FrontController is a servlet, managed by Guice, which dispatches the request to the relevant Controller.

Client-side code

The FrontController object front-end code uses JQuery in order to execute AJAX requests. Although JQuery exposes $.get() as a suitable method for doing such calls, the STEP JavaScript library extends and wraps around this call to provide more flexibility and error handling. The recommended way of calling the server is through the following methods:

  • getSafe(url, argArray [optional], callback): other function signatures are available as well, and the developer is referred to the code for examples of this.
  • getPassageSafe({url: abc, callback: def, passageId: ghi, level: 'error' or 'info): this method will result in raising an info/error message on the specific column identified by passageId

FrontController

The FrontController object takes in a request URL, calls the relevant controller method and finally returns a serialised UTF-8 encoded response. The FrontController FrontController is configured by the web.xml descriptor to listen to all requests under /rest/.

For example,

http://localhost:8080/step-web/rest/timeline/getTimelineConfiguration

  1. Tomcat (or another container) passes the request to FrontController
  2. The FrontController looks at the remainder of the url /timeline/getTimelineConfiguration
  3. Identifies the controller based on the first portion: /timeline => TimelineController (simply suffixing the word Controller)
  4. Using Guice (see section on dependency injection), it retrieves the identified Controller singleton instance
  5. Reflectively calls the method called "getTimelineConfiguration" based  based on the next section
  6. finally if any parameters are passed in, these are passed to the method in order of appearance.

Dependency Injection & Guice

Description

Dependency injection or "Inversion of Control" are two design patterns whereby a service can be told what dependencies it will work with.

The following example does not use IoC:

...

In the above example, it is impossible to switch out the phonebook object for a different phonebook implementation. So, if PhonebookImpl was using a database backend and we wanted to switch to a Lucene backend, this would be hard. It is also hard to test, as to test the ''getPhoneNumber'' method, I will have to ensure that the creation of PhonebookImpl is possible (i.e. that it can create all its dependants, has a database, etc.). It is hard to mock out that object.

The example below decouples the implementation and creates an interface. It also allows an external service to inject the Phonebook service (whether that be a mock service or a real implementation)

...

public LookupService(Phonebook p) {
this.p = p;
}

...

In the above example, the object that instantiates LookupService is responsible for providing (injecting) the correct implementation using the constructor provided (constructor injection). You can also achieve the same thing using setters however the caller will then need to be careful to call all the relevant setters and private fields cannot be set to final.

Guice

  • Guice is a framework developed by Google to ease dependency injection
  • Dependency injection is done mostly through constructor injection using the @Inject annotation
  • A "Guice module" bind interfaces to classes (in Singletons or not), in our case ''StepCoreModule''
  • The ''StepCoreModule'' is also reads a property file (step.core.properties). These are available through the @Named annotation, e.g. @Named("app.db.driver")
  • Singletons can be created simply by adding an annotation to the object in question. (@Singleton)
  • Reference data is currently hard coded in the form of Providers (see ''com.tyndalehouse.step.core.guice.providers.DefaultVersionsProvider'' for an example)
  • The example above has been reworked to show the Guice injection. The only difference below is the constructor which is now annotated with @Inject.

...

@Inject
public LookupService(Phonebook p) {
this.p = p;
}

...

In addition to this, the developer needs to tell the ''StepCoreModule'' that ''Phonebook'' should use the ''PhoneBookImpl'' implementation:

...

  1. occurence.