Tuesday, June 24, 2008

Xalan vs. FileSystemPreferences

The following is a possible work-around for sun.com Bug ID: 6396599 which seems to bite anyone trying to use the Preferences API on a Linux version of Sun's Java Runtime in an application that also uses the Apache Xalan XSLT engine.

SafeTransformerFactory below is just a wrapper for the standard JAXP TransformerFactory class. It's only purpose is to catch, log, and ignore exceptions thrown by calls to setAttribute -- most notably by the setAttribute("indent-number", new Integer(2)) calls generated by the FileSystemPreferences.

Use system property settings like these to have JAXP use the wrapper class:

// Access transformer factory through wrapper:
System.setProperty("javax.xml.transform.TransformerFactory",
"sandbox.SafeTransformerFactory");
// Use Xalan's transformer factory inside the wrap:
System.setProperty("sandbox.SafeTransformerFactory",
"org.apache.xalan.processor.TransformerFactoryImpl");

The wrapper may look like this:

package sandbox;

import java.util.logging.*;

import javax.xml.transform.*;

public class SafeTransformerFactory
extends TransformerFactory
{
private final static Logger LOG = Logger.getLogger(SafeTransformerFactory.class.getName());
private TransformerFactory m_factory;

public SafeTransformerFactory()
{
super();
m_factory = createFactory();
}

private static TransformerFactory createFactory()
{
String realFactoryClassName =
System.getProperty("sandbox.SafeTransformerFactory",
"org.apache.xalan.processor.TransformerFactoryImpl");
try

{
Class realFactoryClass = Class.forName(realFactoryClassName);
try
{
return (TransformerFactory)realFactoryClass.newInstance();
}
catch (Exception err)
{
throw new RuntimeException(realFactoryClass.getName() + ": failed to build transformer factory", err);
}
}
catch (ClassNotFoundException err)
{
throw new RuntimeException(realFactoryClassName + ": failed to load factory template class", err);
}
}

public Transformer newTransformer(Source source)
throws TransformerConfigurationException
{
return m_factory.newTransformer(source);
}

public Transformer newTransformer()
throws TransformerConfigurationException
{
return m_factory.newTransformer();
}

public Templates newTemplates(Source source)
throws TransformerConfigurationException
{
return m_factory.newTemplates(source);
}

public Source getAssociatedStylesheet(Source source, String media, String title, String charset)
throws TransformerConfigurationException
{
return m_factory.getAssociatedStylesheet(source, media, title, charset);
}

public void setURIResolver(URIResolver resolver)
{
m_factory.setURIResolver(resolver);
}

public URIResolver getURIResolver()
{
return m_factory.getURIResolver();
}

public void setFeature(String name, boolean value)
throws TransformerConfigurationException
{
throw new UnsupportedOperationException("Not supported yet.");
}

public boolean getFeature(String name)
{
throw new UnsupportedOperationException("Not supported yet.");
}

public void setAttribute(String name, Object value)
{
try

{
m_factory.setAttribute(name, value);
}
catch (Throwable err)
{
LOG.log(Level.WARNING, "setAttribute(\"" + name + "\", " + value + ") ignored", err);
}
}

public Object getAttribute(String name)
{
return m_factory.getAttribute(name);
}

public void setErrorListener(ErrorListener listener)
{
m_factory.setErrorListener(listener);
}

public ErrorListener getErrorListener()
{
return m_factory.getErrorListener();
}
}

Wednesday, July 18, 2007

Migrating from FOP 0.20 to 0.93

Having upgraded a FOP and Batik application to use Batik 1.6 seemed to break the Barcode4J plugin for FOP 0.20 prompting me to begin migration to FOP 0.93. This looks like a major task, requiring substantial modifications to the FO stylesheet base. http://xmlgraphics.apache.org/fop/compliance.html