Resolving log4j.dtd error on JBoss

I recently faced an issue where the application was not able to find the log4j.dtd, when deployed on jboss. We were using our own repository selector for logging and an isolated classloader. But could see a “FileNotFoundException” for log4j.dtd in the JBoss log when the application was deployed, although the dtd was part of the log4j jar contained within the application. The reason for that was the xml parser was not looking in the classpath resources for the dtd, but was just looking in a path relative to the application’s root directory.

Now in order to load the dtd from the classpath I updated the repository selector and set an EntityResolver to the DocumentBuilder so that when the parser encounters the dtd reference the resolver looks it up from the classpath. Here is the code to that.

Assuming that the doctype reference in log4j.xml is:

<!DOCTYPE log4j:configuration SYSTEM 'org/apache/log4j/xml/log4j.dtd'>

The code to override the default behavior of the parser to look for the dtd in the classpath:

import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
.
.
.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver( new EntityResolver() {
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        // Check for dtd ref
        if( systemId.endsWith( "org/apache/log4j/xml/log4j.dtd" ) ) {
            // return the dtd from classpath
            return new InputSource( getClass().getClassLoader().getResourceAsStream( "org/apache/log4j/xml/log4j.dtd" ) );
        }

        // Resume normal flow
        return null;
    }
} );

// now parse the log4j.xml
Document doc = builder.parse( "WEB-INF/classes/log4j.xml" );

Now our EntityResolver will return the dtd from classpath whenever the parser encounters it. Although I wish the parser could support the “classpath” protocol in the doctype uri.

2 Comments

Leave a Reply