JavaEJBBuilding Reusable Components Using a StateChangeListener Pattern

Building Reusable Components Using a StateChangeListener Pattern

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Introduction

Today, server-side Java development has become simpler because of component models using EJBs. The fundamental concept behind these component models is to allow components to do only business logic and let the application server manage the non-functional features such as threading, performance and so forth. However, these components still do logging, billing, and other functionalities, which vary based on the deployment scenarios. If a framework or an application server could either provide these functionalities or allow plugging of components providing these functionalities, the reuse of these components would attain a much higher level. This article talks about obtaining such a reuse of components using the StateChangeListener design pattern, which is an extension of the Observer-Observable pattern.

Scenario Illustrated

Consider a Java component that does some useful business logic: It may talk to a database, interface with EAI like SAP, and so forth. The component owner inserts log statements into his component for varying purposes such as debugging, auditing, billing, and the like. The “debugging” reason is valid to be owned by the component owner because it helps him fix bugs in the component. However, the other aspects such as auditing, billing, and so forth, the component owner cannot decide by himself. Rather, it depends upon the situation/environment where the component is deployed. For example, some scenarios may require audit logs to directly go into their ERP system, whereas for some other scenarios, it may have to be logged in a database. Though logging packages such as log4j allow a flexible configuration for file formats, storage (file or database) into a file or database as well as allowing custom appenders, it may not cover all the unforeseen circumstances that would arise during application deployment. So, instead of a component doing audit logging and billing by itself, it can express its intention by raising events about it.

Why Express State Change

Typically, a component does audit logging or generates billing information when there is a change in the component’s state. If it raises an event about its state change, it allows listeners to be plugged to take care of these events. These listeners can be pre-built and could be provided by the Application Server itself as pre-packaged listeners. This allows custom handling of state change events and hence gives full flexibility during deployment. This also removes the burden on the component developers from doing audit logging and billing, and allows them to concentrate on business logic alone.

Illustrated with Example

The following code snippets throw light on possibility of development of frameworks based on StateChangeListener pattern. Note that the intention of the code snippets is to make the readers understand the requirement of such frameworks and is not, by any means, the only way of achieving the requirements.

//AbstractComponent.java

package statechangepattern;
import java.util.Vector;
public abstract class AbstractComponent
{
  private Vector listeners = new Vector(0,1);
  public void addListener(StateChangeListener listener)
  {
    listeners.add(listener);
  }
  public void removeListener(StateChangeListener listener)
  {
    listeners.remove(listener);
  }
  public void stateChanged(StateChangeEvent x)
  {
    int size = listeners.size();
    for(int i=0;i<size;i++)
    {
      ((StateChangeListener)listeners.elementAt(i)).
        stateChanged(x);
    }
  }
  public abstract void doBusinessLogic();

}

//StateChangeListener.java
package statechangepattern;
public interface StateChangeListener
{
  public void stateChanged(StateChangeEvent x);

}

//StateChangeEvent.java

package statechangepattern;
import java.util.HashMap;
public interface StateChangeEvent
{
  public String getFromState();
  public String getToState();
  public HashMap getCurrentStateParams();
}

//SampleStateChangeEvent,java
package statechangepattern;
import java.util.HashMap;
public class SampleStateChangeEvent implements StateChangeEvent
{
  private String fromState,toState;
  private HashMap params;
  public SampleStateChangeEvent(String fromState, String toState,
                                HashMap params)
  {
    this.fromState = fromState;
    this.toState = toState;
    this.params = params;
  }
  public String getFromState()
  {
    return fromState;
  }
  public String getToState()
  {
    return toState;
  }
  public HashMap getCurrentStateParams()
  {
    return params;
  }
}
//SampleStateChangeListener
package statechangepattern;
public class SampleStateChangeListener
       implements StateChangeListener
{
  String lName;
  boolean ignore;
  public SampleStateChangeListener(String listenerName,
                                   boolean ignore)
  {
      this.lName = listenerName;
      this.ignore = ignore;
   }
  public void stateChanged(StateChangeEvent x)
  {
      System.out.println("Listener Name:"+lName);
      if(ignore)
      {
          System.out.println(lName+":Ignoring event..");
      }
      else
      {
        System.out.println("State Changed from:"+x.getFromState()+"
                            to "+x.getToState());
        System.out.println("State Params are:"+
                            x.getCurrentStateParams());
     }
  }

}


//SampleComponent.java
package statechangepattern;
import java.util.Vector;
import java.util.HashMap;
public class SampleComponent extends AbstractComponent
{

  public void doBusinessLogic()
  {
    System.out.println("I am here..");
    String fromState="Before DB";
    String toState="After DB";
    HashMap params = new HashMap();
    params.put("Result","DB Result");
    SampleStateChangeEvent x =
          new SampleStateChangeEvent(fromState,toState,params);
    stateChanged(x);

  }

}
//SampleTest.java
package statechangepattern;
public class SampleTest
{

  public static void main(String [] args)
  {
    AbstractComponent x    = new SampleComponent();
    StateChangeListener l1 = new SampleStateChangeListener(
                             "First Listener",true);
    StateChangeListener l2 = new SampleStateChangeListener(
                             "Second Listener",false);
    x.addListener(l1);
    x.addListener(l2);
    x.doBusinessLogic();


  }

}

Author’s Profile

Mr. R. Venkatavaradan has been working as a Technical Consultant for Hewlett-Packard. He has a Masters Degree from the School of Automation, Indian Institute of Science, Bangalore. He has about 13 years of industry experience. The field of his work ranges from signal processing to Web services, J2EE, Enterprise Application Integration, and so forth. He has extensively worked on Web service technologies such as WSDL, SOAP, and UDDI and has provided technical consultancy to various projects in the field of mobile, telecom, and EAI, which have been architected based on Web service concepts.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories