Archive

Posts Tagged ‘ServiceLoader’

NoContainer Dependency Injection

August 6, 2009 Leave a comment

I recently needed to find out a way to define an interface on one side, and define the implementation on the other. I went to StackOverflow with a poorly written question and the overflowers there ended up giving me the answer.

One of the answers given mentioned the solution could be providing the implementation through the constructor(thx to palyndrom for the answer):

class A implements EventHandlerForB {
  ...
}
public class B {
  private EventHandlerForB eventHandler;
  public void registerEventHandler(EventHandlerForB eventHandler) {
     this.eventHandler = eventHandler;
  }
  ...
}
public interface EventHandlerForB {
  ...
}

This didn’t work for me since i had no intention of instantiating the class. Then dfa mentioned java.util.ServiceLoader(for JDK 6). This was a perfect fit. ServiceLoader involves creating an interface and then using a properties file to define the implementation on the client side.

For a ServiceLoader tutorial see Tim Boudreau’s Blog post.

Unfortunately for me i couldn’t use it since i wasn’t programming for jdk 6. I needed a custom solution. A little side note, another solution, also mentioned by an overflower, would be to use Guice or another Dependency Injection framework. I took a quick look at it but didn’t spend much time over it. It seem to be pretty powerfull, but by now i wanted a simpler solution than Guice.

I ended up looking up how ServiceLoader did things and found a link that gave me this solution.

Basicly you define your Interface A on Application A, and in there you call your interface using a simple factory. On application B you implement Interface A and create a property file in your classpath. And your done. The wizardry here is all done by the Factory object :

public class EventHandlerFactory {

 public EventHandler buildEventHandler() {

     try {
          InputStream propertyFile = getClass().getClassLoader().getResourceAsStream("handler.properties");
          Properties properties = new Properties();
          properties.load(propertyFile);
          Class eventImpl = Class.forName(properties.getProperty("EventHandler-Implementation"));
          if (EventHandler.class.isAssignableFrom(eventImpl)) {
             return (EventHandler) eventImpl.newInstance();
          } else
             throw new RuntimeException("No Implementation For EventHandler found!!!");
      } catch (IOException e) {
         throw new RuntimeException("Cannot Find propertyes File handler.properties");
      } catch (InstantiationException e) {
         throw new RuntimeException("Problem Instantiating class for EventHandler implementation",e);
      } catch (IllegalAccessException e) {
         throw new RuntimeException("Problem Instantiating class for EventHandler implementation",e);
      } catch (ClassNotFoundException e) {
         throw new RuntimeException("Problem Instantiating class for EventHandler implementation",e);
    }
 }
}

The code above is far from robust or reusable, first it forces the properties name file (ServiceLoader takes the property name file from the Interface complete name) and it forces you to use a hard coded property when that could’ve been infered from the interface name too. But changing the code to do as you please should be relatively trivial.

Another thing ServiceLoader does is allow you to define several different implementation classes for a given interface, then on the server side you can for through them all and call your method, the above code assumes there is only one implementation for that interface. Again changing this should be relatively trivial.

The property file should be located in your sourcepath and have the name : handler.properties, the following property should be defined

EventHandler-Implementation= com.clientside.events.impl.EventImpl

To call the object on the Application A side you do the following:

EventHandlerFactory factory = new EventHandlerFactory();
EventHandler evt = factory.buildEventHandler();

Hope this helps

Advertisements