In a project I was tinkering with lately I found the complexity getting to the point where I could use component dependency injection. There are in fact a number of techniques to do this in “plain” Scala, but they generally seem more painful to me than just dropping in a lightweight DI framework, so I went with Guice.
As it happens, Guice works with Scala very nicely, and is very unobtrusive. There’s a few minor things I haven’t quite figured out yet, but I’d like to share what I’ve discovered so far.
After adding this section to my project POM:
com.google.inject guice 2.0
I had all I needed of Guice embedded in my app. Now I can scratch up a series of tests that exercise all of the different ways use Guice from Scala. Let’s start with the simplest, and work our way up:
@Test def basicDependencyInjection { class ScalaModule extends AbstractModule { @Override protected def configure() { bind(classOf[AService]).to(classOf[SomeService]) } } class ScalaModule2 extends AbstractModule { @Override protected def configure() { bind(classOf[AService]).to(classOf[SomeOtherService]) } } val injector = Guice.createInjector(new ScalaModule) val component = injector.getInstance(classOf[MyComponent]) assertEquals("someService", component.callTheService) val injector2 = Guice.createInjector(new ScalaModule2) val component2 = injector2.getInstance(classOf[MyComponent]) assertEquals("someOtherService", component2.callTheService) }
So let’s explore the test a bit. I’m using Scala to build a JUnit test, as shown by the annotation on line 1. One of the advantages of this is that it’s easy to use Scala’s namespace capabilities to build test classes that are only visible within the test itself, which is what I’m doing starting line 3. I create a class call ScalaModule with extends Guice’s base class AbstractModule. I override one method called “configure”, which sets up the bindings of interfaces to implementations for this Guice module. (This is all covered in detail in Guice’s doc).
On line 6 I bind the interface “AService” to an implementation of AService called “SomeService”. Here’s what they look like (these classes are defined later in the file – I don’t embed them inside the test class as Guice didn’t let me).
Here’s the trait for the service:
trait AService { def service: String }
And a simple implementation:
class SomeService extends AService { def service(): String = "someService" }
Now I have a component that uses that service, called MyComponent. It looks like this:
class MyComponent @Inject()(val service: AService) { def callTheService(): String = service.service }
Note the annotation on the first line. This is how you put an annotation on the constructor in Scala, Annoyingly, the () is apparently required. This Inject annotation indicates that when this component is requested from Guice, it should have the appropriate implementation of Service injected.
So now to return to our test, on line 10 you’ll see we are building a second module, this time binding the AService interface (trait, actually) to the SomeOtherService implementation, which looks like this:
class SomeOtherService extends AService { def service(): String = "someOtherService" }
Then we get into the meat of the test in line 17. First, we ask Guice for our injector, the “god object” for Guice, from which you get all the other object you’ll need. In the first case, we use our ScalaModule class. Then we ask this injector for our component, and it constructs the component for us, injecting the dependency as necessary. In this situation, we have not told Guice that MyComponent is a singleton (we’ll deal with that later – in several different ways), so it builds a new one for us every time.
On line 18, we make the assertion that proves that our MyComponent instance has in fact been built with the “SomeService” instance, as opposed to any other instance, by verifying our string that SomeService responds with.
Then we do the whole thing again, except this time asking for the ScalaModule2. ScalaModule2 is where we have the SomeOtherService implementation of AService wired up, so when we assert on line 23, we now see the “someOtherService” string returned instead, which means that we’re properly wired, as expected.
Now let’s give Guice a little harder work, exploring some scenarios we’ll see in more sophisticated applications.
In many situations, we’ll want to avoid creating a new instance of our service object every time we use it. There are a couple of ways to do this with Guice.
@Test def instanceBindingExample { // if you want to bind to a specific instance of a class... class InstanceExampleModule extends AbstractModule { @Override protected def configure() { val instance1 = new InstanceService("instance1") bind(classOf[AService]).toInstance(instance1) } } val injector = Guice.createInjector(new InstanceExampleModule) val service = injector.getInstance(classOf[AService]) assertEquals("instance1", service.service) }
In the code above, we’re configuring our module, called InstanceExampleModule, with a binding that specifies our AService trait uses a specific instance of the class called InstanceService.
Here’s InstanceService:
class InstanceService(val value: String) extends AService { def service(): String = value }
Back in our test, line 13 ensures that we’re actually talking to the right service, as we fed the service it’s return string (“instance1″) when it was created in the module.
Ok, so now we can inject services, and specify an instance of a service instead of a newly-created one every time. That’s a good start, but we want to do more.
What if we have to do some more work to instantiate our singleton instance? E.g. what happens if it takes a whole method to create the service?
Guice has that covered as well, like so:
Here you see a new module being built, but this time we don’t actually say anything in the “configure” method. Instead, we annotate another method in the module with the @Provides annotation – this means to Guice “whenever you need a thing of the type this method returns, call this method”. Then we verify that that’s in fact what’s happening by creating the injector and asking for the service. Ok, so now we can create instances of services however we want, but we’ve still only created a single instance of a given trait. What if we’ve got a whole whack of services that implement our interface? Ok, that’s also easy: @Test def bindingWithNameAnnotationExample { // what if I have two implementations of the same interface, how do I say which one I want? class ScalaModule extends AbstractModule { @Override protected def configure() { bind(classOf[AService]).annotatedWith(Names.named("foo")).to(classOf[SomeServiceNamedFoo]) bind(classOf[AService]).annotatedWith(Names.named("bar")).to(classOf[SomeServiceNamedBar]) } } val injector = Guice.createInjector(new ScalaModule) val barComponent = injector.getInstance(classOf[MyBarComponent]) val fooComponent = injector.getInstance(classOf[MyFooComponent]) assertEquals("bar", barComponent.callTheService) assertEquals("foo", fooComponent.callTheService) } Now we’ve got a couple of services to declare: class SomeServiceNamedFoo extends AService { def service(): String = "foo" } class SomeServiceNamedBar extends AService { def service(): String = "bar" } The services themselves both implement our trait, of course, but now we have two different components, one which needs the Foo service, other other one needs the Bar: class SomeServiceNamedFoo extends AService { def service(): String = "foo" } class SomeServiceNamedBar extends AService { def service(): String = "bar" } In our test, you can see we ask the injector for the two components. What’s very interesting to me is that the component themselves are not listed in the module. Why that’s important is that unlike Spring (to pick an example many people know), you don’t need any configuration provided at all for stuff that Guice can work out on it’s own. This is a good thing. Anyway, you can see by our asserts that in this situation the Foo service gets the Foo implementation of the AService (SomeServiceNamedFoo), and the Bar service gets SomeServiceNamedBar instead. Now that we can handle multiple implementations, let’s go back and consider the singleton vs. new instance issue from another angle: Scala has no concept of the idea of “static” classes, but it does have companion objects, which are, in all cases I’ve seen, better. If we declare a service like so: object SingletonService extends AService { def service(): String = "singleton" } and another (non-singleton) implementation, like so: class NonSingletonService extends AService { def service(): String = "nonsingleton" } Now we can write a test that tries this out like so: @Test def singletonOrPrototype { class ScalaModuleSingleton extends AbstractModule { @Override protected def configure() { bind(classOf[AService]).toInstance(SingletonService) } } class ScalaModuleNonSingleton extends AbstractModule { @Override protected def configure() { bind(classOf[AService]).to(classOf[NonSingletonService]) } } val singletonInjector = Guice.createInjector(new ScalaModuleSingleton) val singleton = singletonInjector.getInstance(classOf[AService]) assertEquals("singleton", singleton.service) val secondInstance = singletonInjector.getInstance(classOf[AService]) assertSame(singleton, secondInstance) val nonSingletonInjector = Guice.createInjector(new ScalaModuleNonSingleton) val nonsingleton = nonSingletonInjector.getInstance(classOf[AService]) assertEquals("nonsingleton", nonsingleton.service) val secondNonSingletonInstance = nonSingletonInjector.getInstance(classOf[AService]) assertNotSame(nonsingleton, secondNonSingletonInstance) } The money here comes at the line that binds the classOf[AService] to a singleton – in this case, the SingletonService. This isn’t a class, so we don’t use to(classOf[SingletonService]), we say toInstance(SingletonService) instead. As you can see from the test, this works very nicely, and gives us a much more Scala-canonical way to do singleton. However, there are times when we want to declare a regular Scala class, and have Guice only instantiate one of em for us, and handle it as a singleton that way (some examples might be when we’re using a constructor to inject other dependencies – although we can use field injection for this, which we’ll look at later). We can annotate our class explicitly to tell Guice it’s a singleton like so: @com.google.inject.Singleton class SingletonClassService extends AService { def service(): String = "singletonClass" } Now we can write a test like so to prove that we get the same instance of our service, even if we ask the injector for it multiples times: @Test def singletonClassExample { class ScalaModuleSingleton extends AbstractModule { @Override protected def configure() { bind(classOf[AService]).to(classOf[SingletonClassService]) } } val singletonInjector = Guice.createInjector(new ScalaModuleSingleton) val singleton = singletonInjector.getInstance(classOf[AService]) assertEquals("singletonClass", singleton.service) val secondInstance = singletonInjector.getInstance(classOf[AService]) assertSame(singleton, secondInstance) } The assertSame in JUnit asserts that we have the exact same instance of an object, not that they’re only equal. One last scenario: What is the service isn’t the singleton, but the component is? E.g. what if we have an object instead of class that needs a service injected into it? Turns out Guice can handle that nicely as well. The only extra work we need is to define a trait for the binding of our component, like so, with the service injected into the object: trait SingletonComponentInterface { def callTheService:String } object SingletonComponent extends SingletonComponentInterface { @Inject val service:AService = null def callTheService(): String = service.service } Now we can write a test to make sure this is doing what we want: @Test def injectIntoSingletonExample { // if you want to inject into an object instead of a class class InstanceExampleModule extends AbstractModule { @Override protected def configure() { val instance1 = new InstanceService("instance1") bind(classOf[AService]).toInstance(instance1) bind(classOf[SingletonComponentInterface]).toInstance(SingletonComponent) } } val injector = Guice.createInjector(new InstanceExampleModule) val component = injector.getInstance(classOf[SingletonComponentInterface]) assertEquals("instance1", component.callTheService) } That’s it for my experiments so far. Here’s my conclusions, please comment with your experiences: The Good, The Bad, and the Ugly The Good There was a lot I liked about Guice in Scala. First, no XML was injured in the making of these examples – everything was code, and fully type-safe (I mentioned it was Scala, right?) I always find myself writing a “smoke test” for my Spring apps to verify I haven’t made a typo in my “beans.xml” file – here I didn’t need to. Yes, I know you can do XML-free Spring as well, but it’s the norm with Guice, and it feels a lot lighter weight. I don’t need to configure anything for classes that just get injected. This means that the configuration I do need to write is very short, and because it’s a class, it’s extensible. In my “real” project, for instance, I was able to write a module that created services that use static lists for their data (instead of reading and writing to a real database, for instance), then extend that class with an OSGi-aware version that used the “real” services from other modules. No repeated work, no wiring, no config – it just worked. Auto-handling of singletons, both with companion objects and classes, as I prefer: It was nice to be able to write Scala in a very Scala-like way, and just have the DI framework slot right in whichever way I needed it to, as described above. The Bad I have to annotate my classes with Guice-specific annotations, although there is a JSR on the way to standardize these, which makes it a bit less objectionable. What happens if I need to inject to a class I don’t have source for (e.g. something in an existing Java library that I’m calling? I also haven’t tried this in a Servlet environment, although I understand there’s a Guice extension for that, so I don’t expect any trouble there. The Ugly I have to (it seems) use the @Inject() format, not just @Inject, and I have to insert it in what looks like an odd place in the declaration. Not a big deal, and I suspect I’ll get used to it.
Here you see a new module being built, but this time we don’t actually say anything in the “configure” method. Instead, we annotate another method in the module with the @Provides annotation – this means to Guice “whenever you need a thing of the type this method returns, call this method”. Then we verify that that’s in fact what’s happening by creating the injector and asking for the service.
Ok, so now we can create instances of services however we want, but we’ve still only created a single instance of a given trait. What if we’ve got a whole whack of services that implement our interface? Ok, that’s also easy:
@Test def bindingWithNameAnnotationExample { // what if I have two implementations of the same interface, how do I say which one I want? class ScalaModule extends AbstractModule { @Override protected def configure() { bind(classOf[AService]).annotatedWith(Names.named("foo")).to(classOf[SomeServiceNamedFoo]) bind(classOf[AService]).annotatedWith(Names.named("bar")).to(classOf[SomeServiceNamedBar]) } } val injector = Guice.createInjector(new ScalaModule) val barComponent = injector.getInstance(classOf[MyBarComponent]) val fooComponent = injector.getInstance(classOf[MyFooComponent]) assertEquals("bar", barComponent.callTheService) assertEquals("foo", fooComponent.callTheService) }
Now we’ve got a couple of services to declare:
class SomeServiceNamedFoo extends AService { def service(): String = "foo" } class SomeServiceNamedBar extends AService { def service(): String = "bar" }
The services themselves both implement our trait, of course, but now we have two different components, one which needs the Foo service, other other one needs the Bar:
In our test, you can see we ask the injector for the two components. What’s very interesting to me is that the component themselves are not listed in the module. Why that’s important is that unlike Spring (to pick an example many people know), you don’t need any configuration provided at all for stuff that Guice can work out on it’s own. This is a good thing.
Anyway, you can see by our asserts that in this situation the Foo service gets the Foo implementation of the AService (SomeServiceNamedFoo), and the Bar service gets SomeServiceNamedBar instead.
Now that we can handle multiple implementations, let’s go back and consider the singleton vs. new instance issue from another angle: Scala has no concept of the idea of “static” classes, but it does have companion objects, which are, in all cases I’ve seen, better.
If we declare a service like so:
object SingletonService extends AService { def service(): String = "singleton" }
and another (non-singleton) implementation, like so:
class NonSingletonService extends AService { def service(): String = "nonsingleton" }
Now we can write a test that tries this out like so:
@Test def singletonOrPrototype { class ScalaModuleSingleton extends AbstractModule { @Override protected def configure() { bind(classOf[AService]).toInstance(SingletonService) } } class ScalaModuleNonSingleton extends AbstractModule { @Override protected def configure() { bind(classOf[AService]).to(classOf[NonSingletonService]) } } val singletonInjector = Guice.createInjector(new ScalaModuleSingleton) val singleton = singletonInjector.getInstance(classOf[AService]) assertEquals("singleton", singleton.service) val secondInstance = singletonInjector.getInstance(classOf[AService]) assertSame(singleton, secondInstance) val nonSingletonInjector = Guice.createInjector(new ScalaModuleNonSingleton) val nonsingleton = nonSingletonInjector.getInstance(classOf[AService]) assertEquals("nonsingleton", nonsingleton.service) val secondNonSingletonInstance = nonSingletonInjector.getInstance(classOf[AService]) assertNotSame(nonsingleton, secondNonSingletonInstance) }
The money here comes at the line that binds the classOf[AService] to a singleton – in this case, the SingletonService. This isn’t a class, so we don’t use to(classOf[SingletonService]), we say toInstance(SingletonService) instead.
As you can see from the test, this works very nicely, and gives us a much more Scala-canonical way to do singleton.
However, there are times when we want to declare a regular Scala class, and have Guice only instantiate one of em for us, and handle it as a singleton that way (some examples might be when we’re using a constructor to inject other dependencies – although we can use field injection for this, which we’ll look at later).
We can annotate our class explicitly to tell Guice it’s a singleton like so:
@com.google.inject.Singleton class SingletonClassService extends AService { def service(): String = "singletonClass" }
Now we can write a test like so to prove that we get the same instance of our service, even if we ask the injector for it multiples times:
@Test def singletonClassExample { class ScalaModuleSingleton extends AbstractModule { @Override protected def configure() { bind(classOf[AService]).to(classOf[SingletonClassService]) } } val singletonInjector = Guice.createInjector(new ScalaModuleSingleton) val singleton = singletonInjector.getInstance(classOf[AService]) assertEquals("singletonClass", singleton.service) val secondInstance = singletonInjector.getInstance(classOf[AService]) assertSame(singleton, secondInstance) }
The assertSame in JUnit asserts that we have the exact same instance of an object, not that they’re only equal.
One last scenario: What is the service isn’t the singleton, but the component is? E.g. what if we have an object instead of class that needs a service injected into it? Turns out Guice can handle that nicely as well. The only extra work we need is to define a trait for the binding of our component, like so, with the service injected into the object:
trait SingletonComponentInterface { def callTheService:String } object SingletonComponent extends SingletonComponentInterface { @Inject val service:AService = null def callTheService(): String = service.service }
Now we can write a test to make sure this is doing what we want:
@Test def injectIntoSingletonExample { // if you want to inject into an object instead of a class class InstanceExampleModule extends AbstractModule { @Override protected def configure() { val instance1 = new InstanceService("instance1") bind(classOf[AService]).toInstance(instance1) bind(classOf[SingletonComponentInterface]).toInstance(SingletonComponent) } } val injector = Guice.createInjector(new InstanceExampleModule) val component = injector.getInstance(classOf[SingletonComponentInterface]) assertEquals("instance1", component.callTheService) }
That’s it for my experiments so far. Here’s my conclusions, please comment with your experiences:
The Good There was a lot I liked about Guice in Scala. First, no XML was injured in the making of these examples – everything was code, and fully type-safe (I mentioned it was Scala, right?) I always find myself writing a “smoke test” for my Spring apps to verify I haven’t made a typo in my “beans.xml” file – here I didn’t need to. Yes, I know you can do XML-free Spring as well, but it’s the norm with Guice, and it feels a lot lighter weight.
I don’t need to configure anything for classes that just get injected. This means that the configuration I do need to write is very short, and because it’s a class, it’s extensible. In my “real” project, for instance, I was able to write a module that created services that use static lists for their data (instead of reading and writing to a real database, for instance), then extend that class with an OSGi-aware version that used the “real” services from other modules. No repeated work, no wiring, no config – it just worked.
Auto-handling of singletons, both with companion objects and classes, as I prefer: It was nice to be able to write Scala in a very Scala-like way, and just have the DI framework slot right in whichever way I needed it to, as described above.
The Bad I have to annotate my classes with Guice-specific annotations, although there is a JSR on the way to standardize these, which makes it a bit less objectionable. What happens if I need to inject to a class I don’t have source for (e.g. something in an existing Java library that I’m calling? I also haven’t tried this in a Servlet environment, although I understand there’s a Guice extension for that, so I don’t expect any trouble there.
The Ugly I have to (it seems) use the @Inject() format, not just @Inject, and I have to insert it in what looks like an odd place in the declaration. Not a big deal, and I suspect I’ll get used to it.
In Part 1 of our OSGi adventures, we described how to build a nice Ajax-aware Vaadin UI app, and couple it to a generic back-end OSGi service we called the service dispatcher.
Now we’ll take the adventure to the next step, show how to deploy that webapp into our OSGi container and get it up and running, then go through the functionality of the Dispatch Service, and show how it routes requires through to the first of our domain-specific application services.
In our UI, we built a form that allowed the user to enter and save a “Dealer”, with some fields like name, phone number, etc., so the first service we’ll build for the service dispatcher to talk to will be our “dealer” service.
First, though, let’s see how to get our webapp into our OSGi container.
As we’re building our Vaadin app with Maven, we can easily add the small bits of additional configuration to turn our project into an OSGi-friendly WAR file.
OSGi deploys “bundles”, but a bundle is just a jar file (or a war, which is after all just a special kind of jar) with a bit of extra meta-data. The META-INF/MANIFEST.MF file is where the magic happens. We add the following to our POM:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.0</version> <configuration> <archive> org.springframework.osgi.web.context.support,\ org.springframework.web.servlet,\ org.springframework.web.servlet.handler,\ org.springframework.web.servlet.mvc,\ org.springframework.web.servlet.view,\ dwmj.domain,\ org.springframework.web.servlet.mvc.annotation,\ org.springframework.web.context <manifestEntries> <Bundle-ManifestVersion>2</Bundle-ManifestVersion> <Bundle-SymbolicName>com.point2.Admin</Bundle-SymbolicName> <Bundle-Name>Admin</Bundle-Name> <Bundle-Version>1.0.0</Bundle-Version> <Bundle-Activator>com.point2.ServiceClient</Bundle-Activator> <Import-Package>org.osgi.framework,com.point2.services.dispatch,javax.servlet;version="2.4.0", javax.servlet.http;version="2.4.0",org.osgi.service.http;version="1.2.0", org.osgi.util.tracker;version="1.3.2"</Import-Package> <Webapp-Context>admin</Webapp-Context> <Bundle-ClassPath>WEB-INF/classes, WEB-INF/lib/service-dispatch-api-1.0.0.jar, WEB-INF/lib/vaadin-6.1.3.jar</Bundle-ClassPath> </manifestEntries> </archive> </configuration> </plugin>
This bit of magic allows Maven to build us a MANIFEST.MF like this:
Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Created-By: Apache Maven Built-By: mnash Build-Jdk: 1.6.0_15 Extension-Name: admin Implementation-Title: admin Implementation-Version: 1.0-SNAPSHOT Bundle-Activator: com.point2.ServiceClient Bundle-ClassPath: WEB-INF/classes, WEB-INF/lib/service-dispatch-api-1. 0.0.jar, WEB-INF/lib/vaadin-6.1.3.jar Bundle-ManifestVersion: 2 Bundle-Name: Admin Bundle-SymbolicName: com.point2.Admin Bundle-Version: 1.0.0 Import-Package: org.osgi.framework,com.point2.services.dispatch,javax. servlet;version="2.4.0",javax.servlet.http;version="2.4.0",org.osgi.s ervice.http;version="1.2.0",org.osgi.util.tracker;version="1.3.2" Webapp-Context: cadmin
Now we have our OSGi-friendly .war file, sitting in our target directory. We can then connect to the console of our OSGi container (in this case, ServiceMix), and say:
install war:file:/Users/mnash/experiments/admin/target/admin-1.0.0-SNAPSHOT.war
Our container honors the “Webapp-Context” tag in our manifest, so we can then surf to http://localhost:8181/admin/ to see our application. 8181 is the default port for the Jetty HTTP service in ServiceMix – it can easily be changed to another number as required, of course.
Dispatch Service Now that we can see how to get the wepapp into ServiceMix, let’s look at the Dispatch Service in detail.
Our Dispatch Service is going to be a regular OSGi bundle, so we have a separate Maven project that produces a .jar file in this case, not a WAR file.
Our MANIFEST.MF needs the following magic for this project:
Bundle-ManifestVersion: 2 Bundle-SymbolicName: com.point2.services.dispatch.DispatchService Bundle-Name: DispatchService Bundle-Version: 1.0.0 Bundle-Classpath: .,lib/commons-beanutils-1.8.0.jar,lib/commons-collections-3.2.1.jar Bundle-Activator: com.point2.services.dispatch.impl.DispatchServicePublisher Import-Package: org.osgi.framework Export-Package: com.point2.services.dispatch
You can see we’re again specifying a “Bundle-Activator” class, which, much like the ServiceClient class in our webapp, is called by the OSGi framework when the bundle containing this service is started.
One slight oddity: The dispatch service needs the two jars listed under “Bundle-Classpath:” to do it’s business – because we are building an OSGi bundle, we “embed” these jars in our bundle (which is, yes, another jar) by putting them in the src/main/resources/lib directory. We refer to them in that location in the POM, and Maven automatically includes them in the finished jar, where they’re available when our bundle needs them. The other alternative is to install the dependencies as their own bundles, but that’s a whole ‘nother post
In the case of DispatchService, we’ve got an activator like this:
public class DispatchServicePublisher implements BundleActivator { private ServiceRegistration registration; public void start(BundleContext context) throws Exception { registration = context.registerService(DispatchService.class.getName(), new DispatchServiceImpl(), null); DispatchServiceImpl.setBundleContext(context); System.out.println("Dispatch Service registered"); } public void stop(BundleContext context) throws Exception { registration.unregister(); System.out.println("Dispatch Service unregistered"); } }
Which simply takes a reference to the BundleContext on startup and passes it to the DispatchServiceImpl, which implements the DispatchService interface, like so:
public interface DispatchService { List<Map<String, Object>> call(String serviceName, String serviceOperation, Map<String, Object> parameters, String versionPattern, String securityToken) throws Exception; }
The big JuJu with OSGi is that only this interface is “exposed” from the bundle. No other service can see the innards of our service, unlike Jars on a classpath.
The implementation of the DispatchService is equally straightforward:
public class DispatchServiceImpl implements DispatchService { private static BundleContext context; public List<Map<String, Object>> call(String serviceName, String serviceOperation, Map<String, Object> parameters, String versionPattern, String securityToken) throws Exception { ServiceReference reference = getServiceNamed(serviceName); if (reference == null) throw new RuntimeException("There is no service with service-name " + serviceName); Object service = context.getService(reference); Adapter adapter = new Adapter(service); List<Map<String, Object>> response = adapter.callList(serviceName, serviceOperation, parameters); context.ungetService(reference); return response; } private ServiceReference getServiceNamed(String serviceName) throws Exception { ServiceReference[] references = context.getAllServiceReferences(null, null); System.out.println("There are " + references.length + " services available"); for (int i = 0; i < references.length; i++) { ServiceReference reference = references[i]; Object serviceNameValue = reference.getProperty("service-name"); if (serviceNameValue != null) { System.out.println("I see service with name " + serviceNameValue); if (serviceNameValue.toString().equalsIgnoreCase(serviceName)) return reference; } } throw new RuntimeException("There is no service available with service-name " + serviceName); } public static void setBundleContext(BundleContext newContext) { context = newContext; } }
The dispatch service implementation simply looks through the “published” services in the OSGi context, and looks at the “service-name” property of each service to find the one specified in the call. Assuming it finds an appropriate service, it then uses another class, Adapter, to do the type conversion of the generic Map of parameters to the specific types needed for the service being called, then uses Java reflection to actually make the call and return the response as a List of Maps, again converting the service-specific types to a generic Map in order to pass the response back to the user interface.
Why do we go through those gyrations, instead of just having access to the domain-specific beans in our UI? If we want a full decoupling, and the advantages that come with it, the type-independence of this approach gives us that. It also allows parallel development of the UI and the back-end services without an ever-increasing number of binary dependencies as well – for that matter, with the static data adapter in the Vaadin app allows us to develop on our UI entirely without the back-end services. That’s pretty decoupled.
The Dispatch Service by itself, though, doesn’t give us any functionality. It acts much like a router on a network, simply moving the request from the client to the proper service on the back-end, so let’s build such a service – in this case, a service for handling Dealers.
Dealer Service The bulk of our application-specific code will be prepared as independent OSGi services, just like this one. In later postings, I’ll describe how to set up dependencies between services (and how to use Spring DM to make doing that kind of thing far simpler).
First, let’s look at our MANIFEST.MF for our new service (again, we can use Maven to produce this for us, but the result is the same):
Bundle-ManifestVersion: 2 Bundle-SymbolicName: com.point2.services.dealer.DealerService Bundle-Name: DealerService Bundle-Version: 1.0.0 Bundle-Activator: com.point2.services.dealer.impl.DealerServicePublisher Import-Package: org.osgi.framework Export-Package: com.point2.services.dealer
The two key elements above are the Bundle-Activator, a class called DealerServicePublisher, and the Export-Package.
OSGi best practices dictate that the package that is exported should only contain the interface for the class (or classes) you wish to make available from your service. In our case, that comprises a bean class, called “Dealer”, and the interface to our actual service, DealerService.
The Dealer bean is very simple, just your basic property-holding JavaBean:
public class Dealer { private String name; private String phone; private String contactLast; private String contactFirst; private String address1; private String address2; public String getContactLast() { return contactLast; } public void setContactLast(String contactLast) { this.contactLast = contactLast; } public String getContactFirst() { return contactFirst; } .....
I’ve ommitted the rest of the getters and setters here for brevity (in case you’re wondering, yes, this is much easier to express in Scala, and yes, OSGi works just fine with Scala…)
The interface for our service is even simpler:
public interface DealerService { public void save(Dealer dealer); public Dealer findById(int id); }
Of course, a fully fleshed-out service might in fact have more methods, but again, you get the idea.
I won’t bore you with the actual implementation of the DealerServiceImpl class, but it’s important to note that it’s not in the same package as the Dealer bean and the DealerService implementation. They are the only two classes (well, one class, one interface) in that package, as the entire package is “exported” by OSGi, and therefore visible to other services and clients.
The DealerServicePublisher is the last piece to examine, and it’s pretty straightforward as well:
package com.point2.services.dealer.impl; import com.point2.services.dealer.DealerService; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import java.util.Dictionary; import java.util.Hashtable; public class DealerServicePublisher implements BundleActivator { private ServiceRegistration registration; public void start(BundleContext context) throws Exception { System.out.println("Registering dealer service"); Dictionary dictionary = new Hashtable(); dictionary.put("service-name", "dealer"); registration = context.registerService(DealerService.class.getName(), new DealerServiceImpl(), dictionary); } public void stop(BundleContext context) throws Exception { System.out.println("Unregistering dealer service"); registration.unregister(); } }
Essentially all we do in this activator is “register” our service, making it visible to the OSGi container and other services or clients that need it. We add an extra property via the “Dictionary” object, which allows us to specify arbitrary properties to be associated with our service. Because we want to look up our services from the dispatcher by name, rather than by class or interface name, we use the string “dealer” and associate it with the key “service-name”. If you examine the code for our DispatchService, you’ll see that it uses this property to find services.
Now we can build our new service with a simple “mvn package” command, and install the resulting jar into our OSGi runtime with “install file:/Users/mnash/experiments/dealer/target/dealer-1.0.0.jar” (again, you can do an install directly from the Maven repository, or from a URL, as opposed to a file).
That’s it – our “dealer” service is now available, and our “dispatch” service is fired up and ready to locate it.
If we deploy our Vaadin application in our OSGi container (as described in the previous post), you’ll find that calls to the “call” method of the ServiceClient now return the “real” data from our service.
In the next few posts we’ll examine an even easier way to define new services, and explore the power of OSGi for updating and working with our decoupled services. Then we’ll look at how to hook services together, allowing services to call other services to do their jobs as required.
Apache Maven is a lot more than a “build tool”, and one of it’s major strengths is it’s ability to manage dependencies.
Maven’s not just for external dependency management, though – it can help us work faster and more easily with our own modules as well as those written by others. In fact, it’s “internal” dependency management is actually far more powerful for most development shops.
Every dependency Maven manages is identified with 3 pieces of information – it’s group id, it’s artifact id, and it’s version. Group id is often some sub-domain of the company it’s working on, e.g. com.point2.somemodule, and the artifact id helps identify the specific module with that group, like rest-api or such.
Possibly the most interesting part is the version number, though, as this is where the real power of Maven comes to the fore. Versions allow us to maximize the opportunity for parallel development without descending into unversioned chaos. Each version represents a specific point in time in a library’s development – and, most importantly, allows us to “re-assemble” our application to a known state at any time (not re-build it).
Let’s take a for-instance to see how this might work…
Component-Based Application “Assembly” For example, let’s say I’ve got a few teams working on different modules for my new application, let’s call them “persistence”, “rest-api” and the user-interface, “ui”. Each of these modules depends on a set of common utility classes in “util”.
We can represent this through a set of triples like so:
rest-api depends-on persistence rest-api depends-on util ui depends-on rest-api persistence depends-on util (directly, and not only on the transitive dependency through persistence)
The unseen aspect here is the versioning. If we include versions in our triples, we see the picture is a bit more sophisticated:
rest-api-1.0 depends on persistence-3.1 rest-api-1.0 depends-on util-1.1 ui-1.0 depends-on rest-api-1.0 persistence-3.1 depends-on util-1.0
Now we have a fully defined dependency graph that we can assemble into an application, say app-1.0. At any time, if we want a copy of the app in 1.0 state, we re-construct it from this deployed modules, no need to build any source code, and we’ve got the exact same app, every time.
Get it in motion… Now let’s look at this in a dynamic development environment, where we’re trying to maximize sustainable velocity:
Although there are dependencies between each module, we don’t want to hold up one team by forcing them to build the other teams modules unnecessarily. We also want each team to choose if they want to work with the very latest version of the other modules, or working against a fixed and stable version for a time instead.
The “ui” team, for example, might be refactoring JavaScript code that’s relying on version 1.0.3 of “rest-api”, while “rest-api” in turn is already working on 1.0.4 – and it uses 1.1.0 of “persistence”… it can get tangled in a hurry without a way to manage it, and we don’t want to be artificially discouraged from writing modular code just because it’s hard to keep version numbers straight.
Enter Maven again. Instead of forcing everyone to just always work with the latest version of every other module (which can bring productivity to a screeching halt in some situations), we allow each time to decide what dependency they will include in their POM (Project Object Model) file.
What if I want the very latest version of “persistence” while I work on “rest-api”, with changes checked in by other developers while I’m still working? This is where the SNAPSHOT version comes into play. Instead of declaring a dependency on 1.1.0, I declare a dependency on 1.1.1-SNAPSHOT. This represents the latest “edge” code for the referenced dependency.
Now we have a graph that looks like this:
app-1.0-SNAPSHOT depends on ui-1.1-SNAPSHOT rest-api-1.1-SNAPSHOT depends on persistence-3.1-SNAPSHOT rest-api-1.1-SNAPSHOT depends-on util-1.1 ui-1.1-SNAPSHOT depends-on rest-api-1.1-SNAPSHOT persistence-3.1-SNAPSHOT depends-on util-1.1
As you can see, we have a mix of stable versioned modules (util in this case), and “on the fly” versions. Yet at the same time we’re assured that major changes that break backwards compatibility will not be seen, as we indicate such changes with a change in our major version number (e.g. 1.X to 2.0).
Then we can set up a CI job (say on TeamCity, Bamboo, or whatever your CI system of choice is) to automatically build and deploy our SNAPSHOT version of “persistence” to our local Maven repository (within our company firewall). The SNAPSHOT version actually turns into a date/timestamped version when it’s deployed to Nexus, and Maven is clever enough to fetch for us the most recent of these SNAPSHOTs every time we build. The “persistence” team checks in some code, CI builds it and deploys the resulting SNAPSHOT jar to our repository, and we get it automagically the next time we build, even though we’re working on rest-api, not persistence.
When we’re ready to “stabilize” our dependencies, we simply switch from the SNAPSHOT to a specific version. Maven has a pre-defined “release” process that guarantees, among other things, that every released version has no remaining SNAPSHOT dependencies, is tagged to version control, and verified via all it’s tests. More than a build tool indeed…
We could of course just put all the modules we’re going to depend on in an aggregator POM, and build everything every time we make a change, but this is hardly efficient, and limits our development velocity unnecessarily (and of course we might not all be in the same source tree, or even the same version-control repository). We want to be building smaller pieces, not bigger ones.
A critical part of this process is our company-local Maven repository – here I mean not just the developer-local repository on each developers own workstation, but a product like Nexus that holds a company-wide copy of all required jars for a build. By doing this, we can guarantee a consistent copy of all our required dependencies without having to depend on the availability of outside repositories, such as ibiblio. It’s not a bad idea to in fact *only* permit access to the local repository for building releases, which ensures this policy is not violated accidentally – while at the same time keeping the “external” maven repo’s available to developers for experimenting and prototyping. Once something gets used in production code, however, it gets stored in the “inside the firewall” Nexus repo (and backed up from there). This avoids the bad practice of checking jar files into source control (it’s called “source” control for a reason).
Testing, Testing… To add a new aspect to the problem, let’s say that it’s not only production code we depend on, but helper classes for tests as well. If it’s difficult to set up a fixture for a certain kind of test, that might be a code smell in and of itself, but that’s also another story. If we have some test helpers that reside in our dependent modules, we won’t be able to see those helpers in our tests in another module, as we’re only depending on that module’s production code, not test code.
We can easily tell Maven to also bundle up the test code from a certain module, however, and make it available to us in a jar file, like so:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <executions> <execution> <goals> <goal>test-jar</goal> </goals> </execution> </executions> </plugin> ... </plugins> </build>
Now when we build, we’ll get a test jar as well as our regular jar, which we can depend on like so:
<dependency> <groupId>com.point2.core</groupId> <artifactId>somemodule</artifactId> <version>1.0</version> <scope>test</scope> <classifier>tests</classifier> </dependency>
Now our test classes in the module declaring the above dependency can see the test helpers in the somemodule module – but we’re still not including test code in our production jar.
Again, I have to emphasize that this level of coupling might indicate a deeper issue, but if you do need to do this, it’s good to know how
Maven also includes facilities to analyze and clean up a complex dependency tree, remove unnecessary dependencies, and keep the whole project manageable.
In summary, Maven can handle extremely complex dependency management for us in a fully declarative and versioned manner, allowing us at any moment to see exactly what our project depends on, both in production and test code. In conjunction with a CI system (like TeamCity) and repository server (like Nexus), we can automate the deployment of intermediary and full-release versions to the point where we save significant time, and never build code that we’re not actually working on, allowing us to concentrate on the task at hand and leaving the heavy lifting to Maven.
This allows us to only ever build the code we’re actually changing – never code that’s already available in another library, reducing our developer cycle time significantly. It also means we’re spending more time “assembling” software from re-usable components than re-compiling (and probably re-testing) code that’s already verified and available in object form.
Maven: not just for breakfast anymore.