Description

AchimHuegen, May 16 2006

Proposed Solution

A module is a plain java class that annotates its methods. Each annotated method corresponds with a service point, configuration point or contribution.

The first example demonstrates the definition of three services and their wiring.

  
public class ExampleModule1
{
  @Service(id = "Calculator", serviceModel="singleton")
  public Calculator getCalculator()
  {
    return new CalculatorImpl(service(Adder.class), service(Subtracter.class));
  }

  @Service(id = "Subtracter", serviceModel="singleton")
  private Subtracter getSubtracter()
  {
    return new SubtracterImpl();
  }

  @Service(id = "Adder", serviceModel="singleton")
  private Adder getAdder()
  {
    return new AdderImpl();
  }
}

The method body of a service point method is at the same time factory method, responsible for the service construction and its wiring. Note, that the service-Method offers a typed access to other services!

Autowiring Properties:

  
public class ExampleModule
{
  public Calculator getCalculator()
  {
    CalculatorImpl calculator = new CalculatorImpl();
    autowireProperties(calculator);
    return calculator;
  }
}

Autowiring Construction:

  
public class ExampleModule
{
  public Calculator getCalculator()
  {
    Calculator calculator = autowireConstruct(CalculatorImpl.class);
    return calculator;
  }
}

Define configuration points with default values:

  
public class ExampleModule
{
 
  @Configuration(id = "Translators")
  public List getTranslators()
  {
    List translators = new ArrayList();
    translators.add(new StringTranslator());
    translators.add(new IntegerTranslator());
    return translators;
  }
}

Contribute to a configuration point:

  
public class ExampleModule
{
 
  @Contribution(configuration-id = "Translators")
  public void getTranslators(List translators)
  {
    translators.add(new SmartTranslator());
  }
}

Wiring of configurations:

  
public class ExampleModule
{
  public TranslatorManager getTranslatorManager()
  {
    TranslatorManagerImpl manager = new TranslatorManagerImpl();
    manager.setTranslators(configuration("translators", List.class);
    return manager;
  }
}

Configurations can be any POJO:

  
public class ExampleModule
{
  @Configuration(id = "strutsModule")
  public ModuleConfig getStrutsModule()
  {
    return new ModuleConfigImpl();
  }

  @Contribution(configuration-id = "strutsModule")
  public void contributeToStrutsModule(ModuleConfig config)
  {
    config.addActionConfig(new ActionConfig());
    config.addFormBeanConfig(new MyFormBeanConfig());
  }
}

Add an interceptor:
... to be specified

Details

The methods service, configuration, autowireConstruction, addInterceptor etc. could be inherited from an ancestor. They make use of java 5 generics get rid of casting.

Convention over configuration

Most annotations could be replaced by conventions in the default case:
For example the method name getServiceCalculator would be sufficient to define a new service point with the name calculator. contributeToStrutsModule could indicate a contribution to the configuration strutsModule which is defined by getConfigurationStrutsModule.

  • No labels