Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

ano-prise MetaFactory

What is this about

MetaFactory is a dependency injection mechanism which is based on the assumption that each component has different implementation flavors. MetaFactory is meant for services, i.e. components which offers some methods via public interface. MetaFactory is based on linking and aliasing, consider following example.

Example

Lets say we have a CalculatorService that can add to numbers.

svn
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/CalculatorService.java
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/CalculatorService.java

We will have at least one real implementation:

svn
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/CalculatorServiceImpl.java
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/CalculatorServiceImpl.java

and a mock for testing:

svn
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/CalculatorServiceMock.java
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/CalculatorServiceMock.java

Usually, at least in our world, we would have more impls, but lets stick with two. So, if you are testing a construct like this in spring you will have to setup a real and a test context. Which also means that you'll have to add each new service to both contexts. Each time you add a new one.
Our approach is slightly different, we make the system know about all available implementations and switch the one used by using aliases. Another difference in our approach is that we configure factories, not implementation classes, allowing more complicated instantiation schemes. Here an example of a factory:

svn
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/CalculatorServiceFactory.java
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/CalculatorServiceFactory.java

So how does it work? Somewhere in your app you will have some initialization code, this code can be a context listener, a call from main method or whatever (for example reading a config file). This code will add the knowledge of available instances to the MetaFactory. Another piece of code will also setup the used aliases, therefor configuring the system, which of the implementations of a service should be used. This small test demonstrates it:

svn
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/VerySimpleTest.java
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/VerySimpleTest.java

Running this test will produce following output:

Code Block
On mock called 2 + 2
On impl called 2 + 2

ensuring you that both testcases resolved and instantiated different instances.

Using classes not strings.

So now we moved the config from xml into java, fine, but we are still using strings which are not refactoring-proof or compile safe. What have we won? Nothing. Therefore we added a better Example:

svn
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/VerySimpleTestWithExtensions.java
ano-prise/trunk/test/junit/net/anotheria/anoprise/metafactory/docs/VerySimpleTestWithExtensions.java

Now you see, that we only use classes for service factory registration and resolver and no strings anymore. The built-in enum Extension contains many useful constants but you are not limited to them. The real advantage of this method is the compiler will prevent you from configuring an instance of FooService as CalculatorService which could happen if you configure it in an xml file.

Extensions

Extensions modify the name of the class. They say stuff like if you need an instance of a CalculatorService use the Remote one. Following Extensions are supported by built-in classes:

svn
ano-prise/trunk/java/net/anotheria/anoprise/metafactory/Extension.java
ano-prise/trunk/java/net/anotheria/anoprise/metafactory/Extension.java