ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Achieving Inversion of Control with Eclipse RCP
Pages: 1, 2, 3, 4

We will adopt a variation of type 2, providing services via annotated methods. (The source code for the following sample application is available in the Resources section.) One way to declare a dependency can be expressed as:



@Injected public void aServicingMethod(
  Service s1, 
  AnotherService s2) {

  // save s1 and s2 into class variables
  // to use them when needed
}

The Inversion of Control container will look up the Injected annotation and invoke the method with the required parameters. In our effort to bring IoC into the Eclipse platform, the code that performs the binding between services and serviceable objects will be packaged as an Eclipse plugin. The plugin defines an extension point (named com.onjava.servicelocator.servicefactory) that can be used to contribute service factories to the application. The plugin will request service instances to a factory whenever a serviceable object needs to be configured. The ServiceLocator class will do all the work, as described in the following snippet (we will skip the code that handles the parsing of the extension points since it is quite straightforward):

/**
 * Injects the requested dependencies into the 
 * parameter object. It scans the serviceable 
 * object looking for methods tagged with the 
 * {@link Injected} annotation.Parameter types are 
 * extracted from the matching method. An instance
 * of each type is created from the registered 
 * factories (see {@link IServiceFactory}). When
 * instances for all the parameter types have been
 * created the method is invoked and the next one 
 * is examined.  
 *  
 * @param serviceable the object to be serviced
 * @throws ServiceException
 */
public static void service(Object serviceable)
  throws ServiceException {
        
  ServiceLocator sl = getInstance();
    if (sl.isAlreadyServiced(serviceable))    {    
    // prevent multiple initializations due to 
    // constructor hierarchies
   System.out.println(
      "Object " +
      serviceable + 
      " has already been configured ");
        return;
    }
        
    System.out.println("Configuring " + 
        serviceable);

    // Parse the class for the requested services
    for (Method m : 
        serviceable.getClass().getMethods()) {

    boolean skip=false;
    Injected ann=m.getAnnotation(Injected.class);
        if (ann != null) {                
            Object[] services = 
                new Object[m.getParameterTypes().length];
            int i = 0;
                
        for(Class<?> klass :m.getParameterTypes()){
        IServiceFactory factory = 
          sl.getFactory(klass,ann.optional());
                if (factory == null) {
                    skip = true;
                    break;
                }
          Object service =  
          factory.getServiceInstance();
                    
        // sanity check: verify that the returned
        // service's class is the expected one
        // from the method
                assert(service.getClass().equals(klass) || 
                  klass.isAssignableFrom(service.getClass()));
                    
                services[i++]  = service ;
       }
            
        try {
            if (!skip) 
                m.invoke(serviceable, services);
        }
        catch(IllegalAccessException iae) {
        if (!ann.optional())
               throw new ServiceException(
          "Unable to initialize services on " +
          serviceable + 
          ": " + iae.getMessage(),iae);
            }
            catch(InvocationTargetException ite) {
                if (!ann.optional())
                    throw new ServiceException(
            "Unable to initialize services on " + 
            serviceable + 
            ": " + ite.getMessage(),ite);
            }
        }
    }
        
    sl.setAsServiced(serviceable);
}

Since the services returned by the service factories may also be serviceable, this strategy allows the definition of service hierarchies (however, circular dependencies are not supported at the moment).

Pages: 1, 2, 3, 4

Next Pagearrow