Print
Custom Autowire Mode - EJB3 style

Except for the pre-defined "bytype", "byname", "byqualifiedname", "autodetect" modes, Nuts allow custom auto-wiring mode to be registered.

This is useful when a non-standard auto wiring mode is desired.

For example, as specified by EJB 3, a jndi naming service or EJBContext may be used to auto-wire dependencies, so that the "balance" property of "com.mycompany.BankAccount" class can look up "java:comp/env/com/mycompany/BankAccount/balance" from the jndi registry.

Further more, we may also check annotation on the properties so that explicitly specified lookup key overrides the default naming convention specified by EJB 3 specification.

The pseudo code to create such auto wiring rule is:

class Ejb3AutoWiring implements PropertyBinder{
  private final Context ctxt;
  public Ejb3AutoWiring(Context ctxt){
    this.ctxt = ctxt;
  }
  private String getLookupKey(Class clazz, Object key){
    if(annotation specifies a lookup key){
      return the annotation specified lookup key;
    }
    else{
      return (clazz.getName()+'.'+key).replace('.', '/');
    }
  }
  public Creator bind(Class clazz, Object key, Class prop_type){
    if(property "key" of clazz has "@EJB" annotation){
      final String lookup_key = "java:comp/env/"+getLookupKey(clazz, key);
      final Object obj = ctxt.lookup(lookup_key);
      return Components.value(obj);
    }
    else{
      return Components.useDefault();
    }
  }
}

An instance of this class can then be registered into the NutsProcessor object using the "registerAutoWiring()" method so that it can be used as an auto wiring mode:

NutsProcessor processor = new NutsProcessor();
Context ctxt = ...;
Ejb3AutoWiring jndi = new Ejb3AutoWiring(ctxt);
processor.registerAutoWiring("lookup", jndi);
processor.processFile(...);

This auto wiring mode can then be used in xml configuration file such that:

<module name="test">
  <body autowire="lookup">
    <bean id="account" class="com.mycompany.BankAccount" property-names="*"/>
  </body>
</module>

Each property of BankAccount will be examined, and those with "@injectMe" annotation will be injected using the value found in the jndi context.

It is also possible to have Nuts configure the jndi Context as well, for example, we could auto wire the Context object by type:

class Ejb3AutoWiring implements PropertyBinder{
  private Context ctxt = null;
  public Creator bind(final Class clazz, final Object key, final Class prop_type){
    if(ctxt!=null) return performLookup(clazz, key, prop_type);
    return Components.useType(Context.class)
      .bind(new Binder(){
        public Creator bind(Object c){
          ctxt = (Context)c;
          return performLookup(clazz, key, prop_type);
        }
      });
  }
  private String getLookupKey(Class clazz, Object key){
    if(annotation specifies a lookup key){
      return the annotation specified lookup key;
    }
    else{
      return (clazz.getName()+'.'+key).replace('.', '/');
    }
  }
  public Creator bind(Class clazz, Object key, Class prop_type){
    if(property "key" of clazz has "@EJB" annotation){
      final String lookup_key = "java:comp/env/"+getLookupKey(clazz, key);
      final Object obj = ctxt.lookup(lookup_key);
      return Components.value(obj);
    }
    else{
      return Components.useDefault();
    }
  }
}

Thus, we do not have to provide the Context object, it can be configured by the configuration file:

<module name="test">
  <body autowire="lookup">
    <bean id="jndi" class="javax.naming.ldap.InitialLdapContext" .../>
    <bean id="acct" class="com.mycompany.BankAccount" property-names="*"/>
  </body>
</module>

The code to register the auto wiring mode becomes:

NutsProcessor processor = new NutsProcessor();
processor.registerAutoWiring("lookup", new Ejb3AutoWiring());
processor.processFile(...);
Powered by Atlassian Confluence