james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Bernd Fondermann <bf_...@brainlounge.de>
Subject Central class for service injection
Date Wed, 12 Jul 2006 10:34:33 GMT
Having setters to inject service components (Store, DNSServer and all 
the others) into the respective objects creates a new chance to take 
another step to dramatically lower the dependency on Avalon and 
centralize the service lookup code.

A utility class "AvalonServiceInjector" could automatically inject all 
needed services. The manual lookup code would become obsolete.

This yields the chance to remove dependencies on Avalon's ServiceManager 
  from all components.

It further yields the chance to replace the lookup with the use of "your 
favorite ServiceManager".

This is how for example RemoteManager would look now and then:

public void service( final ServiceManager componentManager )
         throws ServiceException {
         super.service(componentManager);

         MailServer mailServer = 
(MailServer)componentManager.lookup(MailServer.ROLE );
         setMailServer(mailServer);
         Store store = (Store)componentManager.lookup( 
org.apache.avalon.cornerstone.services.store.Store" );
         setStore(store);
         UsersStore usersStore = 
(UsersStore)componentManager.lookup(UsersStore.ROLE );
         setUsersStore(usersStore);
         UsersRepository users = 
(UsersRepository)componentManager.lookup(UsersRepository.ROLE);
         if (users == null) {
             throw new ServiceException("","The user repository could 
not be found.");
         }
         setUsers(users);
         SpoolManagementService spoolManagement =
(SpoolManagementService)componentManager.lookup(SpoolManagementService.ROLE);
         setSpoolManagement(spoolManagement);
}

=====>

public void service( final ServiceManager componentManager )
         throws ServiceException {
         super.service(componentManager);

         new AvalonServiceInjector(componentManager).canoncialInject(this);

}


Note: the whole injection line could even be moved out to the caller of 
service() and make service() redundant in most of the cases.

This is how the utility works:

public class AvalonServiceInjector extends ServiceInjector {

     private ServiceManager serviceManager;

     public AvalonServiceInjector(ServiceManager serviceManager) {
         this.serviceManager = serviceManager;
     }

     protected Object lookup(String typeFQName) {
         try {
             return serviceManager.lookup(typeFQName);
         } catch (ServiceException e) {
             return null;
         }
     }
}

Note: the lookup could easily be replaced by JNDI lookups or anything else.

The beef happens to happen in all-purpose ServiceInjector which is 
already totally independent of Avalon. It uses reflection to gather all 
setters and tries to find fitting objects in ServiceManager:


public abstract class ServiceInjector {

   protected abstract Object lookup(String fullyQualifiedType);

   public int canoncialInject(Object injectionReceiver) {

     Class injecteeClass = injectionReceiver.getClass();
     Method[] methods = injecteeClass.getMethods();
     int injectionCount = 0;

     for (int i = 0; i < methods.length; i++) {

       Method method = methods[i];
       String methodName = method.getName();
       if (!methodName.startsWith("set")) continue; // is it a setter?

       Class[] parameterTypes = method.getParameterTypes();
       // is it a one parameter setter?
       if (parameterTypes == null || parameterTypes.length != 1) continue;

       Class parameterType = parameterTypes[0];
       String injectionClassCandidate = methodName.substring(3);

       // does setter parameter match the setter name?
       String typeFQName = parameterType.getName();
       if (!typeFQName.endsWith(injectionClassCandidate)) {
         System.out.println("setter name/param mismatch: " + 
injectionClassCandidate + " <> " + parameterType);
         continue;
       }

       Object injected = lookup(typeFQName);
       if (injected == null) {
         System.out.println("setter parameter lookup failed: " + 
typeFQName);
         continue;
       }

       try {
         method.invoke(injectionReceiver, new Object[] {injected});
         System.out.println("setter injection successfull: " + 
injectionClassCandidate);
         injectionCount++;
       } catch (IllegalAccessException e) {
         e.printStackTrace();
       } catch (InvocationTargetException e) {
         e.printStackTrace();
       }
     }
     return injectionCount;
   }

}

This works perfectly after renaming those setters not already strictly 
following the setter naming convention.

By evaluating the canoncialInject() return code the component has full 
control to check whether all of its components have been injected.

   Bernd



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Mime
View raw message