Struts: How to validate DTDs locally

Published: Sunday, 1 April 2012

Local DTD Validation

We had internet issues and noticed that the application failed to startup. On closer inspection it was validating the tiles xml config against a DTD, but instead of using the local copy bundled with Struts, it was going out to the internet.

Network activity should be restricted for production deployments. DTD validation should be done locally.

javax.servlet.UnavailableException: IO Error while parsing file '/WEB-INF/tiles-defs.xml'. Connection reset
	at org.apache.struts.action.ActionServlet.init(ActionServlet.java:368)
	at javax.servlet.GenericServlet.init(GenericServlet.java:212)
	at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1139)
	at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:966)
	at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:3996)
	at org.apache.catalina.core.StandardContext.start(StandardContext.java:4266)
	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:760)

To fix this, the public identifier in the DTD header should match exactly what is inside your struts.jar.

In this case we incorrectly had:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration//EN"
       "http://struts.apache.org/dtds/tiles-config_1_1.dtd">

This had to be changed to:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN"
       "http://struts.apache.org/dtds/tiles-config_1_1.dtd">

Note that the “1.1” was missing. To find the correct public identifier, find the corresponding DTD in the struts.jar and ensure it matches. In struts-1.2.9.jar, look inside org/apache/struts/resources/tiles-config_1_1.dtd