Tuesday, February 24, 2015

Factory Pattern using Spring injection

In this article, let us see how to use Spring injection to use the factory design pattern.

What is factory design pattern?

From wikipedia, the factory design pattern is:"In class-based programming, the factory method pattern is a creational pattern which uses factory methods to deal with the problem of creating objects without specifying the exact class of object that will be created. This is done by creating objects via calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor."

The advantage of the factory pattern is the caller just sends the information about which class the caller would like to execute based on the runtime scenario.  A typical example is when you want to encrypt a string based on different RSA algorithms, you can write the encrytion methods in individual classes and at run time, the caller can choose to call the factory method to specify which algorithm he needs to encrypt the data.

To implement the above example, I have created an interface called ICrypto which has two methods: encrypt and decrypt:



           public interface ICrypto{
             public byte[] encrypt(byte[] plaintext);
             public byte[] decrypt(byte[] encryptedText);
           }


The implementation of the above interface for AES will be:


           public class AESCrypto implements ICrypto {
             public AESCrypto() {}
             public byte[] encrypt(byte[] plaintext){
               ...
               //your code here
               ...
               return encryptedBytes;
             }

             public byte[] decrypt(byte[] encryptedtext){
               ...
               //your code here
               ...
               return plainTextInBytes;
             }
           }

Similarly, for RC2, the implementation is:

           public class RC2Crypto implements ICrypto {
             public RC2Crypto() {}
             public byte[] encrypt(byte[] plaintext){
               ...
               //your code here
               ...
               return encryptedBytes;
             }

             public byte[] decrypt(byte[] encryptedtext){
               ...
               //your code here
               ...
               return plainTextInBytes;
             }
           }

Define the crypto types enum:

           public enum CryptoTypes{
             AES_CRYPTO_TYPE,
             RC2_CRYPTO_TYPE;
           }


Now we need a factory class which is going to create the instance of one of the implementations above:

           public final class CryptoFactory {
             //make sure the constructor is not accessible.
             private CryptoFactory(){}
             //factory method
             public final static ICrypto getCryptoInstance(CryptoTypes type) {
               switch(type){
                case AES_CRYPTO_TYPE:
                 return new AESCrypto();
                case RC2_CRYPTO_TYPE:
                 return RC2Crypto();
               }
             }
           }

Now the caller can call the CryptoFactory.getCryptoInstance() with the enum value as a parameter and get the instance,

The above is a typical example of the factory pattern in non-spring world.

In Spring, all of the above are the same except the factory class.  Using the injection mechanism, the factory class need not go through the switch() statement.  Lets see how this can be achieved:

  1.  First define all the implemented beans in the spring bean definition XML.For example:
    <bean id="crypto.rc2crypto" class="com.example.RC2Crypto"></bean>
  2. Then define the enum constants also as a bean instance.  For example:                               <bean id="ctyptotype.enum.rc2" class="com.example.CryptoTypes" factory-method="valueOf"            <constructor-arg value="RC2_CRYPTO_TYPE"/>                                                                 </bean>
  3. Now wire up the crypto type bean definitions with the implementation bean definitions as a map.  For example:                                                                                                                                    <util:map id="cryptoMap" map-class="java.util.LinkedHashMap">
    <entry key-ref="ctyptotype.enum.rc2" value-ref="crypto.rc2crypto" />
    <entry key-ref="ctyptotype.enum.aes" value-ref="crypto.aescrypto" />
       </util:map>
  4. Wire the factory bean instance with the map we created in 3.  For example:                    <bean id="crypto.factory" class="com.example.CryptoFactory">                                                            <property name="cryptoTypes" ref="cryptoMap" />                                                   </bean>

With the above implementation, the same CryptoFactory will look like this:


           public final class CryptoFactory {
             private Map cryptoTypes;

             public Map getCryptoTypes() {
               return cryptoTypes;
             }

             public void setcryptoTypes(Map cryptoTypes) {
               this.cryptoTypes = cryptoTypes;
             }

             public ICrypto createCryptoFactory(CryptoTypes cryptoType){
               return cryptoTypes.get(cryptoType);
             }
           }

Now the caller can inject the instance of the crypto factory bean in their bean class and call createCryptoFactory(CryptoType.AES_CRYPTO_TYPE).

Even better way is the caller bean can define allowed crypto types for that bean (for example, the bean can use only AES_CRYPTO_TYPE) and use that variable instance to call createCryptoFactory().   It is now boiled down to the bean implementor's design.

Advantages of using Spring injection

As I mentioned above, once we defined all the possible types as enum, the caller bean can control which subset of enum types it can use to get the crypto implmentation's instance.  This adds more security as module X in the application can use only AES crypto type whereas module Y can use only RC2 crypto type.

Also, turning on or off of any crypto type is going to be only in the spring context XML files rather than in the code.  The factory class is encapsulated from which crypto types it is using.

And that is all folks,,,,