16 May 2006

InstanceTrackingFilter -- a bit of spit and polish

As a bit of an extension to the InstanceTrackingFilter, I added a small piece of code to its init() method so as to allow the names of the elements inserted into the HttpSession to be provided, as well as enabling the JMX notification functionality to be turned on or off.

The parameters are passed in as context-param and init-param values in the web.xml file.

The parameter names and behaviours are:
  • SEND_JMX_NOTIFICATION: [true | false] specifies whether to broadcast JMX notifications when a session failover is detected. Will also gate whether to register the NotifierMBean.

  • SESSION_IDENTIFIER: specifies the name of the attribute injected into the HttpSession which contains the InstanceIdentifier object

  • SESSION_FAILOVER: specifies the name of the attribute injected into the HttpSesison which reflects whether a session failover has occurred

When used in the web.xml file they appear as follows:
  <context-param>
<param-name>SEND_JMX_NOTIFICATION</param-name>
<param-value>true</param-value>
</context-param>

<filter>
<filter-name>InstanceTrackingFilter</filter-name>
<filter-class>sab.demo.cluster.InstanceTrackingFilter</filter-class>
<param-name>SESSION_IDENTIFIER</param-name>
<param-value>INSTANCE_IDENTIFIER</param-value>
</init-param>
<init-param>
<param-name>SESSION_FAILOVER</param-name>
<param-value>FAILOVER_OCCURRED</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>InstanceTrackingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


This gives an administrator or developer the ability to control how the parameters are put into the HttpSession -- perhaps to either to avoid conflicts with other session attribute names used by the application itself or to specify a specific attribute name the application wants to use if it is reading the objects placed into the session by the InstanceTrackingFilter.

Reading these parameters is very easy to do:
    private void readConfigurationParameters() {
String filterName = _filterConfig.getFilterName();
// Note this is being read from the ServletContext -- this is to enable
// one common place to specify this setting which both the
// ServletContextListener and ServletFilter can access.
String jmxNotifications = _filterConfig.getServletContext().getInitParameter("SEND_JMX_NOTIFICATIONS");

// These parameters are being read from the filter/init-param section
// of web.xml
String sessionIdentiferParam = _filterConfig.getInitParameter("SESSION_IDENTIFIER");
String sessionFailoverParam = _filterConfig.getInitParameter("SESSION_FAILOVER");

if (jmxNotifications != null &&
jmxNotifications.equalsIgnoreCase("false")) {
ENABLE_JMX = false;
}

if(sessionFailoverParam!=null &&
!sessionFailoverParam.equalsIgnoreCase("")) {
SESSION_FAILOVER = sessionFailoverParam;
}

if(sessionIdentiferParam != null &&
sessionIdentiferParam.equalsIgnoreCase("")) {
SESSION_IDENTIFIER = sessionIdentiferParam;
}

debug("ENABLE_JMX: " + ENABLE_JMX);
debug("SESSION_FAILOVER: " + SESSION_FAILOVER);
debug("SESSION_IDENTIFIER: " + SESSION_IDENTIFIER);
}

With that in place the InstanceTrackingFilter is just about ready to use!

There's one final little piece to this which I haven't written up -- in order to dynamically register the MBean used to send out the notifications, I used a ServletContextListener. The benefit of using this over doing hte registration in the ServletFilter init method is that the MBean can be registered/unregistered once in the respective contextInitialized and contextDestroyed methods. Enabling the MBean to be created before the ServletFilter is ever used through setting the appropriate load-on-startup value for the web module. This enables subscriptions to the notifications to be done on each node easily without needing to make sure the ServletFilter has accessed.

Here's the relevant pieces of code from the ServletContextListener

    /**
* The context for the Web module is being initialized. Create and register
* the NotifierMBean if the the configuration says to do do.
* @param event
*/
public void contextInitialized(ServletContextEvent event) {
context = event.getServletContext();
readConfigurationParameters();
if (ENABLE_JMX) {
InstanceTrackingNotifier notifier = new InstanceTrackingNotifier();
try {
MBeanServer mbeanserver =
MBeanServerFactory.createMBeanServer();
ObjectName objectname = new ObjectName(NOTIFIER_MBEAN);
if (!mbeanserver.isRegistered(objectname)) {
mbeanserver.registerMBean(notifier, objectname);
}
} catch (Exception e) {
e.printStackTrace();
}
}

}

/**
* ServletContext is being destroyed, unregister the NotifierMBean.
* @param event
*/
public void contextDestroyed(ServletContextEvent event) {
context = event.getServletContext();

if(ENABLE_JMX) {
try {
MBeanServer mbeanserver =
MBeanServerFactory.createMBeanServer();
ObjectName objectname = new ObjectName(NOTIFIER_MBEAN);
mbeanserver.unregisterMBean(objectname);
} catch (Exception e) {
e.printStackTrace();
}
}

}


And that really is all folks ... :)

No comments: