Wednesday, May 30, 2007

Making JDOM run faster

It's time for another cool AspectJ hack here on RMA, once again leveraging Codehaus' excellent Maven plugin. Still working on the same project as the last post, we've decided to move from standard JAXP to JDOM for programmatic XML handling (the JDOM api is so much nicer to work with it's not even funny). As the returning reader may recall, the model in the MVC part of our application basically consists of a number of XML documents, and the view rendering technology is Freemarker. Freemarker is supposed to be able to handle both JAXP, JDOM and dom4j, but a closer look will reveal that it's more or less only JAXP that's up to date, the other wrappers are deprecated and don't work correctly anymore, which is a shame.

Using JDOM, there is a simple workaround however: the DOMOutputter, which is capable of converting an org.jdom.Document to an org.w3c.dom.Document which can then be handed to Freemarker. There is a speed penalty of course, and when profiling we found that almost all the time is spent in this method, in JAXPDOMAdapter:

public Document createDocument() throws JDOMException {

try {
// We need DOM Level 2 and thus JAXP 1.1.
// If JAXP 1.0 is all that's available then we error out.
Class.forName("javax.xml.transform.Transformer");

// Try JAXP 1.1 calls to build the document
Class factoryClass =
Class.forName("javax.xml.parsers.DocumentBuilderFactory");

// factory = DocumentBuilderFactory.newInstance();
Method newParserInstance =
factoryClass.getMethod("newInstance", null);
Object factory = newParserInstance.invoke(null, null);

// jaxpParser = factory.newDocumentBuilder();
Method newDocBuilder =
factoryClass.getMethod("newDocumentBuilder", null);
Object jaxpParser = newDocBuilder.invoke(factory, null);

// domDoc = jaxpParser.newDocument();
Class parserClass = jaxpParser.getClass();
Method newDoc = parserClass.getMethod("newDocument", null);
org.w3c.dom.Document domDoc =
(org.w3c.dom.Document) newDoc.invoke(jaxpParser, null);

return domDoc;
} catch (Exception e) {
throw new JDOMException("Reflection failed while creating new JAXP document", e);

You're probably wondering why the hell they're using this much reflection just to create an empty Document (we did, anyway). It avoids compile-time dependencies on certain javax.xml classes, but it sure isn't designed with high performance in mind!

In addition to that, the call trace from DOMOuputter to JAXPDOMAdapter contains private methods, so you can't simply inherit and override with your own implementation. So, what now? AspectJ to the rescue, of course!

What we realy want to do is replace this implementation with one that performs the sam thing but statically, so we wrote this around advice (DocBuilder creation omitted for brevity):

@Aspect
public class FastDOMDocumentCreator {

@Around("execution (* org.jdom.output.DOMOutputter.createDOMDocument(..))")
public Object createDOMDocument(ProceedingJoinPoint pjp) throws Throwable {
return docBuilder.newDocument();
}

}

This is a lot faster than the default way. But how do we perform weaving of JDOM classes, that are in an external jar? Actually, it's really simple: just place this snippet in the AspectJ plugin section in the pom-xml (details here):

<configuration>
<weaveDependencies>
<weaveDependency>
<groupId>jdom</groupId>
<artifactId>jdom</artifactId>
</weaveDependency>
</configuration>

If you're using AJDT (which I highly recommend), make sure you add the JDOM jar to the inpath in the configuration dialog, that way this weaving runs on the fly just like regular compilation. On a sidenote, AJDT has some really cool features such as contextual information on "weaves" and "weaved by". It supports annotation-style aspects too.

The weaved jar is exploded under the output directory, with the new weaved classes instead of the vanilla ones. This trick pushed the JDOM-to-JAXP document converstion from the top way down on the hotspot list, with a fairly small amount of work.

Update: While examining the situation a bit closer, we found that in fact it's possible to accomplish the same thing without having to weave the JAXPDOMAdapter. Extending AbstractDOMAdapter using the same code as in the aspect, and passing the new class' name to the DOMOutputter constructor will work too. Nevertheless, the technique is still interesting and may be applicable (as the only solution) somwhere else.

Wednesday, May 16, 2007

Clean solutions are the best

Don't you love it when things just seem to fit together exactly as you want them to? It doesn't happen all too often, but when it does, you just want to blog at the top of your lungs...

I'm working on a project where we communicate with an index server over HTTP, and recieve the query results in XML format. It's a data source, which basically boils down to this interface - the DocumentSource:

Document retrieveDocument( URL url );

The contract of this component is that if the document retrieval succeeds, we get a parsed and ready org.w3c.Document back, and in all other cases it throws some kind of exception. Handling exceptions is done in another part of the application, so don't worry about that right now.

Now, a failure can be either uncontrolled, for example if the index application hits a bug, if there's a network problem, the server might be on fire and so on. It could also be a problem with our implementation of of the afromentioned interface (not likely). In either case, the component will throw an exception to the caller, possibly wrapped in some way.

But a failure can also be controlled, which means that the index server returns a valid XML error message along with HTTP status 200 (OK), if the query is invalid in any way. This is also considered an error, and we handle in like this:

if (isErrorResult(document)) {
throw new IndexErrorException(method, document);
}

The method variable is the HttpMethod that we tried to execute, containing host, port and query information, and document is the parsed XML response from the index, in this case an error message.

What we want to do now is log this error, as transparently as possible. The snippet above expresses that we're not really interested in handling the error in detail, we just leave it at "ok, there was an error, so let's throw an exception. Here's all the information I have on why and where the error occurred".

That's all very well, but we still have to inspect the XML error message to present the error in a readable way. The best way to do that is of course the message property of the exception.

Here's where another aspect of our application comes in: we use Freemarker to build views (HTML and others) using the XML data we retrieve from the DocumentSource interface shown above. And since the error message is also XML, and we want to build a kind of view - a String - why not use the same approach here? That way we won't have to deal with cumbersome Java DOM apis, and we have maximum power to extract and format the error message the way we want. Sounds like a good idea.

It's also the case that we've abstracted away a lot of the fuss around the template engine, as well as the fact that we're using Freemarker, behind this very simple TemplateService interface:

String mergeTemplateIntoString( String templateName, Map model );

This service is a component, a Spring bean, in our application. It would be great if this service could be used to render the logged string from the document and the HTTP method, but in that case we have to supply the newly instantiated exception with a reference from the context. Sure, this could be accomplished by holding an (otherwise useless) reference in the DocumentSource implementation that is passed along the exception, but I prefer it when things Just Work.

Enter @Configurable and compile-time AspectJ weaving! We slap on an a TemplateService setter and an annotation (with autowire=Autowire.BY_NAME to avoid the need for a boilerplate bean definition) on the exception class. We're using AspectJ aspects for various other tasks already, and weaving is done at compile-time to avoid the proxy problem. The Codehaus Maven plugin works great!

In order to weave the Spring AnnotationBeanConfigurerAspect, we add the following to pom.xml:

<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>

And the aspect must be made aware of the Spring context (in any application context file):

<aop:spring-configured />
So from here on, the exception message may be rendered like this:

@Override
public String getMessage( ) {
return templateService.mergeTemplateIntoString( "error", model );
}

where "error" is the name of a template, and the model contains the XML document and some other stuff. The error message is now ready to be read and logged, for example in an @AfterThrowing aspect, but that's another story.

Sunday, May 06, 2007

Integrating Struts 1 and Spring

If you want to manage Struts 1 actions with Spring, for example to inject dependencies at runtime, you are going to need a bridging context that essentially duplicates every single action as a bean. (details are here). If you're working on an existing application with lots of actions, writing the bridge context XML will be a pain, so here's a quick Groovy hack that I came up with to generate the Spring context file from the Struts config file:

import groovy.xml.MarkupBuilder

def strutsConfig = new File("path/to/struts-config.xml")

def fromXml = new XmlParser().parse(strutsConfig)

def writer = new StringWriter()
def toXml = new MarkupBuilder(writer)

toXml.beans(
xmlns:"http://www.springframework.org/schema/beans",
"xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
"xsi:schemaLocation":"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd",
"default-autowire":"byName") {
fromXml."action-mappings".action.each {
bean(name:it["@path"],class:it["@type"])
}
}
}

// This simply dumps the XML to stdout, you could of course write to an actual file as well
println writer

This little snippet creates a <bean name="/foo" class="bar.Baz"/> for every <action path="/foo" type="bar.Baz"/> element in the struts-config.xml file, using a few neat Groovy tricks (GPath, closures, GroovyMarkup).

Still, you could do better. You could use a hook such as BeanFactoryPostProcessor that parses the Struts config and dynamically creates beans corresponding to the actions, or even write an XSD that allows Spring to interpret the Struts config file as a context file directly. There's an entry in the SpringIDE blog that shows how you could write a namespace that works in German, so for example <bean/> becomes <bohne/> and so on. That principle might be applicable to this context too.