Tuesday, March 31, 2009

XML generation using SAXTransformer in Java JDK

XML generation is a common found requirement in applications. Typical way to address it in java is to manually append the XML string in a StringBuffer. Firstly this can be quite tedious. Secondly it is susceptible to manual errors while writing the XML. Also, the developer needs to take care of the escape characters etc. Clearly this is not the best way of XML generation in Java.
A better way of achieving this is to use the classes in javax.xml.transform package of JDK. These are traditionally used for XML parsing and transformations. Their use of XML generation is uncommon and unobvious. here's a code snippet that shows how these classes can be used for XML generation:

SAXTransformerFactory saxFactory = (SAXTransformerFactory) TransformerFactory.newInstance();
StringWriter writer = new StringWriter();
try {
TransformerHandler handler = saxFactory.newTransformerHandler();
Result result = new StreamResult(writer);
handler.setResult(result);
handler.startDocument();
AttributesImpl atts = new AttributesImpl();
atts.addAttribute("", "", "name", "CDATA", "");
atts.addAttribute("", "", "version", "CDATA", "6.2");
handler.startElement("http://wbe.ibm.com/6.2/Event/connect", "","connector", atts);
atts.clear();
atts.addAttribute("", "", "name", "CDATA", "connect");
atts.addAttribute("", "", "type", "CDATA", "Event");
handler.startElement("", "", "connector-bundle", atts);
atts.clear();
handler.startElement("", "", "connect", atts);
String paramValue = null;
for (ScenarioParameter param : scenarioParams) {
atts.clear();
atts.addAttribute("", "", "type", "CDATA", param.getType());
handler.startElement("", "", param.getName(), atts);
paramValue = getParamValue(param.getParamId(), params);
handler.characters(paramValue.toCharArray(), 0, paramValue.length());
handler.endElement("", "", param.getName());
}
handler.endElement("", "", "connect");
handler.endElement("", "", "connector-bundle");
atts.clear();
handler.startElement("", "", "system", atts);
String systemName = InetAddress.getLocalHost().getHostName();
handler.characters(systemName.toCharArray(), 0, systemName.length());
handler.endElement("", "", "system");
handler.startElement("", "", "timestamp", atts);
String timestamp = new Date().toString();
handler.characters(timestamp.toCharArray(), 0, timestamp.length());
handler.endElement("", "", "timestamp");
handler.startElement("", "", "loginfo", atts);
String logMsg = "Sending values at runtime";
handler.characters(logMsg.toCharArray(), 0, logMsg.length());
handler.endElement("", "", "loginfo");
handler.endElement("", "", "connector");
handler.endDocument();

System.out.println(writer.toString());

TransformerHandler listens for XML parse events and transforms them to Result. Since we are not using it for parsing, here the handler generates those events like startDocument, startElement and transforms them into Result. The Result thus contains the XML that we wanted to generate. Note that it is the developer's responsibility to take care of the well formedness of the XML. A startElement has to have a matching endElement and a startDocument has to have a matching endDocument.

~Ashish.

Monday, March 30, 2009

Dynamic EJB lookup using Java Reflection

Applications often need to lookup resources based on their JNDI names. The lookup code can be made short and dynamic using Java reflection.
In my application there was a need to lookup an EJB. The JNDI name was dependent on the value of a constant (called cepengine). This is how I implemented the lookup.
I wrote a constants file (constants.properties) with these entries:

cepengine=wbe
eventdefinition.bean.jndi=ejb/com/ibm/eventmanagement/eventdefinition/EventDefinitionServiceHome
eventdefinition.wbe.bean.jndi=ejb/com/ibm/eventmanagement/eventdefinition/wbe/WBEEventDefinitionServiceHome
eventdefinition.bean.home.wbe=com.ibm.eventmanagement.eventdefinition.wbe.WBEEventDefinitionServiceHome
eventdefinition.bean.home=com.ibm.eventmanagement.eventdefinition.EventDefinitionServiceHome

I then wrapped this up with a java class (PropertyLoader.java) with methods to return the various values in the properties file. For instance here is the method that returns the JNDI name:

public String getEventDefinitionServiceJNDI() {
String cepEngine = getCEPEngine();
String constStr = null;
if (cepEngine != null && !cepEngine.equalsIgnoreCase("")) {
constStr = "eventdefinition." + getCEPEngine() + ".bean.jndi";
} else {
constStr = "eventdefinition.bean.jndi";
}
return bundle.getString(constStr);
}

Similarly there is a method that returns the name of the home interface class.

Next I implemented the lookup code using the ServiceLocator pattern in a class aptly named ServiceLocator.java. Here's the code snippet that looks up the home interface object and creates the bean object:

private Object locateEJBHome(String jndi, Class homeClass)
throws ClassCastException, NamingException {
Object ejbHome = ejbHomeObjects.get(homeClass);
if (ejbHome == null) {
ejbHome = PortableRemoteObject.narrow(getInitialContext().lookup(jndi), homeClass);
ejbHomeObjects.put(homeClass, ejbHome);
}
return ejbHome;
}

public EventDefinitionService getEventDefinitionService() {
EventDefinitionService facade = null;
Object facadeHome = null;
PropertyLoader propLoader = new PropertyLoader();
String eventDefHomeName = propLoader.getEventDefinitionServiceHome();

try {
facadeHome = locateEJBHome(propLoader.getEventDefinitionServiceJNDI(), Class.forName(eventDefHomeName));

if (facadeHome != null) {
facadeHome = Class.forName(eventDefHomeName).cast(facadeHome);
Method createMethod = facadeHome.getClass().getMethod("create",new Class[] {});
facade = (EventDefinitionService) createMethod.invoke(facadeHome, new Object[] {});

m_log.info("Received the Event Definition service bean handle");
}
} catch (NamingException ne) {
m_log.severe("NamingException getting event definition EJB facade home."+ ne);
} catch (Exception e) {
m_log.severe("Exception getting event definition service object."+ e);
}
return facade;
}

Let's look at the getEventDefinitionService() method. The method first gets the bean JNDI name and home interface class name using the PropertyLoader. It then uses the generic locateEJBHome() method to look up and return the home object. We then typecast the returned object to actual home class. Using java reflection we get the method object for the method called "create". This is the method that creates the bean object. Note that in my requirement there was a hierarchial relationship between the bean implementations. WBEEventDefinitionService is a subclass of EventDefinitionService. Therefore when I invoke the create method object, I know that the returned object is an instance of either EventDefinitionService or its subclass. However if this is not the case, the same notion of reflection can be extended here as well.

Thus you can see that this code makes is extremely short and easy to do look up the EJB what might have otherwise required separate lookup code for each EJB.

~Ashish