Skip navigation links

Package com.mgnt.lifecycle.management

This package contains some small infrastructure that simplifies and automates working with Factories that provide concrete implementations of an Interface.

See: Description

Package com.mgnt.lifecycle.management Description

This package contains some small infrastructure that simplifies and automates working with Factories that provide concrete implementations of an Interface. The package contains just 2 classes: BaseEntityFactory and BaseEntity. In short what this infrastructure does is that if you create a factory that extends BaseEntityFactory and some Interface with all its concrete implementations extending BaseEntity then each your concrete implementation class instances will be automatically inserted into your factory. You won't have to worry about how and when to populate your factory. The infrastructure will do it for you when the constructor of your concrete implementation class is invoked. So all you will have to do is to create any number of concrete implementation classes and make sure that for each one constructor is invoked. After that you can use your factory to get any of your concrete implementation classes anywhere in your code. This is short explanation. There are few more details but not that many.

Lets show it with an example. This infrastructure has Package com.mgnt.lifecycle.management.example that has some sub-packages that contains source code example that demonstrate how this infrastructure is used. So in this javadoc the same classes will be used. Please see the source code of that package to get all the details. Say you have an Interface called InfoFormatter that has a single method InfoFormatter.formatMessage(java.lang.String). Obviously this method takes some text and formats it according some logic that would be implemented in each concrete implementation.

Next we need to create a factory for our concrete implementations. So we have a factory class InfoFormatterFactory that extends BaseEntityFactory This class look like this:

package com.mgnt.lifecycle.management.example;
import com.mgnt.lifecycle.management.BaseEntityFactory;
import java.util.Collection;

public class InfoFormatterFactory extends BaseEntityFactory<InfoFormatter> {
  private static InfoFormatterFactory FACTORY = new InfoFormatterFactory();

  private InfoFormatterFactory() {
  }

  public static InfoFormatterFactory getFactoryInstance() {
    return FACTORY;
  }

  public static InfoFormatter getInstance(String key) {
    return FACTORY.getEntity(key);
  }

  public static Collection<InfoFormatter> getAllInstances() {
    return FACTORY.getAllEntities();
  }
}

For the purposes of this infrastructure it is recommended that a single abstract parent class extending BaseEntity and implementing your interface is created. Then all your concrete implementations will extend this class. So in our case we will have BaseInfoFormatter that extends BaseEntity and implements InfoFormatter. This class should look like this:


   public abstract class BaseInfoFormatter extends BaseEntity<BaseInfoFormatter> implements InfoFormatter {

     // This is mandatory part of the code for the infrastructure to work
     private static final String FACTORY_TYPE = BaseInfoFormatter.class.getSimpleName();

     static {
       init(FACTORY_TYPE, InfoFormatterFactory.getFactoryInstance());
     }

     public BaseInfoFormatter() {
         super(FACTORY_TYPE);
     }

     public BaseInfoFormatter(String customName) {
       super(FACTORY_TYPE, customName);
     }

     // The end of mandatory part

     // Some business logic methods that are common to all concrete implementations
     //...

     //Implementation of interface declared method
     //...
   }

Then we have 2 concrete implementations: JsonInfoFormatter and XmlInfoFormatter (both of them extending their abstract parent class BaseInfoFormatter). Here is how one of them might look, (the second looks very similar so it is ommitted here)


   public class JsonInfoFormatter extends BaseInfoFormatter {
     private final static String CUSTOM_NAME = "JSON";

     public JsonInfoFormatter() {
       super(CUSTOM_NAME);
     }

     //Implementation of abstract method or overriding methods goes here
   }

So this is our row material so to speak. So lets see how this is used. Look at the class UsageExample and in particular its methods UsageExample.init() (that is invoked in the main() method) and looks as folllows


   private static void init() {
     new JsonInfoFormatter();
     new XmlInfoFormatter();
   }


and UsageExample.printFormattedGreetings() that looks as follows


   private static void printFormattedGreetings() {
     InfoFormatter formatter = InfoFormatterFactory.getInstance("JSON");
     System.out.println("JSON greeting: " + formatter.formatMessage(MESSAGE));
     formatter = InfoFormatterFactory.getInstance("XML");
     System.out.println("XML greeting: " + formatter.formatMessage(MESSAGE));
     List<String> allMessages = new ArrayList<>();
     for(InfoFormatter formattedMessage : InfoFormatterFactory.getAllInstances()) {
       allMessages.add(formattedMessage.formatMessage(MESSAGE));
     }
     System.out.println("All greetings: " + allMessages);
   }

Note that we simply use InfoFormatterFactory.getInstance(java.lang.String) to get ahold of our concrete implementations. This works because method init was invoked before. Note that in init method we simply instantiate our concrete implementations and not saving any references to them. Thanks to the infrastructure, during its instantiation each instance inserted itself into its factory and that allows it to be accessed through the factory. As for the names ("XML" and "JSON") they are in our case defined in each concrete class and passed to the factory through use of its parent constructor BaseInfoFormatter.BaseInfoFormatter(java.lang.String) which in turn will invoke its parent constructor BaseEntity.BaseEntity(java.lang.String, java.lang.String). However, BaseEntity provides another constructor BaseEntity.BaseEntity(java.lang.String) where custom name for entity is not required. And the entity would be registered in its factory by its class name.


That was about how this infrastructure works. Now where would it be convenient and beneficial to use it? Note that in order for infrastructure to work we had to invoke constructor for each concrete class. If only someone or something could have done that for us, that would be magical. Well, this could be done for us by Spring framework. Remember that Spring instantiate all it's defined beans during its initialization. So within Spring context if we simply declare our concrete implementations as Spring beans, Spring would instantiate them for us, thus initializing their factory automatically. This could be very convenient. Imagine that you have some bean that has a property of type InfoFormatter, but which actual implementation would be needed is determined at runtime. So at that moment you can use InfoFormatterFactory.getInstance(java.lang.String) to access needed implementation. This will allow you not to inject ALL your concrete instantiations into your bean and you won't have to use Spring BeanFactory to access a Spring defined bean as that would violate non-intrusiveness of Spring (meaning you can write components which have no dependency on Spring). Also, If at some later stage you will need to add more concrete implementations, all you will have to do is to add your implementation classes to you code and declare them to be Spring beans. The rest will be done by Spring and this infrastructure!

Skip navigation links