Implementing Strategy pattern to support different fingerprint device login system

In our ERP project one of the features of Human resource module is managing daily attendance of the employee using biometric authentication. Our client wants to use NAC 3000 as a fingerprint verification device.

The task is simple. The software of that device writes data in an access database and in a log file whenever an employee place finger on it. We just have to pull the data from the access file or the log file after certain interval. The problem is that as our ERP is generalized and can be customizable for any type of organization so we have to think about other devices that serve the same purpose.

We analyze that all the devices vary in one point and that is the format of the log file or the database file. That is only the file parsing algorithm varies from device to device. This motivates me to use Strategy pattern here as the Strategy pattern defines a family o algorithms, encapsulate each one and makes them interchangeable.

Class diagram


Details
LogInDevice is an abstract class which has an instance fileParser as the interface type not a concrete class implementation type. The LogInDevice objects will set the variable polymorphically to reference the specific file parser.

The FileParser is an interface which has four mehthods. The NAC300Parser, NAC2500Parser implements this interface. When we need to integrate a new device we just have to create a new class that will implement this interface. The code of parsing the logfile will be written in the parseFile() method.

Implementation of the doParsing() method of LogInDevice class

  
public void doParsing()
{
this.fileParser.parseFile();
userId = this.fileParser.getUserId();
purpose = this.fileParser.getPurpose();
time = this.fileParser.getTime();
//Code block for saving the data to database goes here.
}


In this part of the code we don't care about what kind of file parser it is.

Are you thinking of setting the fileParser instance variable? Let’s take a look at the NAC3000 class


public class NAC3000 extends LogInDevice
{
public NAC3000()
{
this.fileParser = new NAC3000Parser();
}
}



The NAC3000 uses the NAC3000Parser to handle its file parsing. So when the doParsing() is called the responsibility for the parsing is delegated to the NAC3000Parser object and we got our desired data.

Change the FileParser dynamically

To change the parsing algorithm dynamically you just need a setter method in LogInDevice class


public void setFileParser(FileParser fileParser)
{
this.fileParser = fileParser;
}



We can call this method anytime we want to change the file parsing algorithm on the fly.

With this design we can integrate a new Fingerprint or any other authentication device very easily in our system and obviously without modifying the existing code.

How to call a method dynamically using Java Reflection

In my previous post i have shown you how to create an instance dynamically using java reflection. Here i will show you how to call a method dynamically using reflection.

Let us start with a simple example. Assume that the method name is refreshForm and it has no argument. You can get the method using class.getMethod(methodName) method and then call the method using method.invoke(instance of the class) method.

 
String className = "com.commlink.cbs.appclient.gl.ChartsOfAccount"
String methodName = "refreshForm";

//get the Class
Class class = Class.forName(className);

// get the instance
Object obj = class.newInstance();

// get the method
Method method = class.getMethod(methodName );

//call the method
method.invoke(obj);


Things will be little complex if the method has some arguments. Suppose the refreshForm method takes two String values. To call this method using reflection first create an array of Class and then an array of Object. Use the class array in getMethod method and the Object array in invoke method in the following way.


String className = "com.commlink.cbs.appclient.gl.ChartsOfAccount"
String methodName = "refreshForm";
Class class = Class.forName(className );

Object obj = class.newInstance();

//create the class array
Class[] types = new Class[] { String.class,String.class};

//get the method
Method method = class.getMethod(methodName ,types);

//create the object array
Object[] args = new Object[]{new String("Hello"), new String("World")};

//call the method
method.invoke(obj,args);

How to create an instance of a class at runtime using Java Reflection

Java Reflection gives us the facility of creating an instance of any class at run time. In our ERP project it helps us a lot to solve some critical problems.

First create a class using the class name then use the class.newInstance method
to create an instance of that class.


javax.swing.JPanel newPanel = null;

String className= "com.commlinkinfotech.cbs.appclient.gl.ChartsOfAccount";

Class class = Class.forName(className);

//we know that the ChartsOfAccount is a JPanel class so cast this to JPanel
newPanel = (JPanel) class.newInstance();


But if the constructor of your class takes some parameters then what will you do?

You have to create an array of your argument class. Use this to create a constructor of your class using the class.getConstructor method. Now call the constructor.newInstance method with the value of the arguments and it gives you an instance of the class.


javax.swing.JPanel newPanel = null;

String className= "com.commlinkinfotech.cbs.appclient.gl.ChartsOfAccount";

//create an array of parameter classes
Class[] types = new Class[] { String.class };

Class class = Class.forName(className);
//create a constructor with the types array
Constructor constructor = class.getConstructor(types);

//create an array of argument values
Object[] args = new Object[] {new String("Hello")};

//now use ther args array to create an instance
newPanel = (JPanel) constructor .newInstance(args);

Total Pageviews

Tags

Twitter Updates
    follow me on Twitter

    Followers