Thursday, May 15, 2008

Identity transformation, my butt

Some lovely trivia I have recently discovered about the default implementations of XSLT transformations in the JDK 1.5:


  1. The so-called "identity transformation" available at TransformerFactory.newTransformer() is anything but the identity when applied to XHTML, until certain non-default configuration is applied. Specifically, you have to do all this:


    xfmEng.setOutputProperty( OutputKeys.DOCTYPE_SYSTEM, "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" );
    xfmEng.setOutputProperty( OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD XHTML 1.0 Transitional//EN" );
    xfmEng.setOutputProperty( OutputKeys.METHOD, "html" );
    xfmEng.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" );


    or you get tons of <!-- ... --> garbage before the real document. The garbage seems to live in the w3c.org dtd files for xhtml.

  2. Even with all that, you still end up with the very non-identity transformation of input like <script src=...></script> becoming <script src=.../>. The latter is actually malformed according to many browsers. Forget newTransformer() and use an xslt-based transformation like

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html"/>
    <xsl:template match="/">
    <xsl:copy-of select="."/>
    </xsl:template>
    </xsl:stylesheet>

  3. Speaking of the w3c.org dtd files, there's still some nasty stuff going on behind the scenes; when any transformer created via TransformerFactory.newTransformer() or Templates.newTransformer() starts processing XHTML, it actually goes and grabs those extremely well-known DTDs off the web from their URIs at w3c.org. Every document, even with the same transformer, engenders a new set of GETs to w3c. Pretty ridiculous. Here's how to get around that:


    package MyPackage;

    import org.xml.sax.SAXNotRecognizedException;
    import org.xml.sax.SAXNotSupportedException;
    import com.sun.org.apache.xerces.internal.impl.Constants;
    import com.sun.org.apache.xerces.internal.parsers.SAXParser;

    public class MyTransform {

    // ...

    public static class MySAXParser extends SAXParser {
    public MySAXParser() {
    super();
    try {
    setFeature( Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE, false );
    setFeature( Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE, false );
    } catch ( SAXNotRecognizedException sne ) {
    } catch ( SAXNotSupportedException sse ) {
    }
    }
    }

    // in the code that uses the transformer:
    System.setProperty( "org.xml.sax.driver", "MyPackage.MyTransform$MySAXParser" );
    TransformerFactory.newInstance().newTransformer().transform( stmIn, stmOut );

    // ...
    }


AspectJ: A crucial distinction between execution and call join points

Given the following code:


class Super {
protected void m() {}
}
class Sub extends Super {}


A call( * Sub+.m( .. ) ) join point will match any call to m made on an instance statically known to be a Sub (in particular, ( ( Super )s ).m() will not only not match, but will cause a compiler warning); an execution( * Sub+.m() ) join point will not match s.m(), even if s is Sub, because there's no m() code to execute in Sub!

Spring declarative transactions, applied dynamically

I think declarative transaction management is possibly the most compelling reason for using the Spring Framework. I won't explain how it usually works, leaving that to the Spring docs and plenty of examples in the literature. Recently I ran into the following conundrum, however.

I have a service class that has not only some "transactional" methods, but also other methods that return instances of secondary classes with their own transactional methods. It is easy in the configuration of the Spring container to declare the transactional methods in the service as such, because it is a typical singleton bean. The problem is that if the code in the service implementation is to remain decoupled from Spring, how do we instruct Spring to wrap transactional proxies around any instances of the secondary classes that are produced at runtime?

My first attempt to solve this problem was to factor the code that needed to be transactional out of the secondary classes into package-access methods on the main service, in the hopes that I could declare those helper methods transactional in the configuration. Then the formerly transactional methods in the secondary classes could call those helper methods back in the service bean. This attempt proved to be not just inelegant, but also ineffectual: a complete waste of time.

Why didn't it work? Because the newly-minted secondary class instances were not receiving a reference to the service bean's transactional proxy to make their call backs on; they got the unadorned service instance as obtained via this, and in order to get the proxy, the Spring coupling would have to creep back into the code. Only a more complete AOP framework like AspectJ, with its special compiler, could avoid the this problem.

My solution to this problem was in four parts. Spring 2.5 is required.


  1. Create a new implementation of each secondary class which is a pure delegating proxy. The constructor of DelegatingSecondaryClassImpl takes a SecondaryClass as delegate, and every method simply forwards to that delegate.

  2. Create a BeanFactoryAware aspect ServiceAdvice with around advice for the methods on the service class that produce instances of these secondary classes, one advice method per secondary class. In each case the advice looks like this:

    public SecondaryClass secondaryClassAroundAdvice( ProceedingJoinPoint pjp ) throws Throwable {
    return ( SecondaryClass )bf.getBean( "secondaryClassBeanId", new Object[] { pjp.proceed() } );
    }


  3. Add a prototype bean to the configuration XML for each secondary class:

    <bean id="secondaryClassBeanId" class="com.amazon.foo.bar.DelegatingSecondaryClassImpl" scope="prototype">
    <constructor-arg><null/></constructor-arg>
    </bean>


  4. Add advice to the service methods that produce instances of each secondary class in the configuration XML:

    <bean id="serviceAdvice" class="com.amazon.foo.bar.ServiceAdvice">
    <aop:config>
    <!-- transactional advisor goes here ... -->
    <aop:aspect id="proxyAspect" ref="proxyAdvice">
    <aop:around pointcut="execution( com.amazon.foo.bar.SecondaryClass createSecondaryClass1( .. ) ) || execution( com.amazon.foo.bar.SecondaryClass createSecondaryClass2( .. ) )" method="secondaryClassAroundAdvice">
    </aop:around>
    </aop:aspect>
    </aop:config>