title: Struts2 & Tiles: When apache.org is down my webapp fails to start
body: <p>I am building a Struts2 web application which uses tiles however I have discovered a quite frustrating problem where if apache.org is down (which seems to happen quite regularly) the web application fails to start. This is because in its standard setup the StrutsTilesListener tries to load the tiles defenitions file which includes a DOCTYPE with a public-id which points to a DTD located on tiles.apache.org. </p>
  
  <p>When the application starts up the definition file is loaded using Apache Xerces via Apache Commons Digester which tries to load the DTD from tiles.apache.org but if apache.org is down then this fails and with it the whole web application wont start.</p>
  
  <p>I can bypass the download from a remote location by downloading the file and placing it local and specifying the new local location in the struts definitions file, however this solution is not very portable as the location where the DTD is saved locally may be different on different developer machines and different once uploaded to a live environment so I would have to keep editing the location so suite the machine the webapp is running on which is just plain annoying.</p>
  
  <p>No other xml files in the project have this problem, including the struts.xml file which also has a DTD location on apache.org so clearly there is a setup problem where Tiles is strictly requiring the DTD but other components are not. Is there any solution to this? I am running out of patience and I cannot put this webapp live knowing that if apache.org is down when I restart it the webapp wont come back up.</p>
  
  <p>Struts tiles defenition file</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt;
  &lt;!DOCTYPE tiles-definitions PUBLIC
         "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
         "http://tiles.apache.org/dtds/tiles-config_2_1.dtd"&gt;
  &lt;tiles-definitions&gt;
      &lt;definition name="master" template="/tiles/templates/master.jsp"&gt;
      &lt;/definition&gt;
      &lt;definition name="public" extends="master"&gt;
          &lt;put-attribute name="header" value="/tiles/templates/public/header.jsp" /&gt;
          &lt;put-attribute name="footer" value="/tiles/templates/public/footer.jsp" /&gt;
          &lt;put-attribute name="templateMeta" value="/tiles/templates/public/meta.jsp" /&gt;
      &lt;/definition&gt;  
  &lt;/tiles-definitions&gt;
  </code></pre>
  
  <p>Stacktrace when apache.org is down</p>
  
  <pre><code>SEVERE: Exception sending context initialized event to listener instance of class org.apache.struts2.tiles.StrutsTilesListener
  java.lang.IllegalStateException: Unable to instantiate container.
      at org.apache.tiles.web.startup.TilesListener.contextInitialized(TilesListener.java:60)
      at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3972)
      at org.apache.catalina.core.StandardContext.start(StandardContext.java:4467)
      at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
      at org.apache.catalina.core.StandardHost.start(StandardHost.java:785)
      at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
      at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
      at org.apache.catalina.core.StandardService.start(StandardService.java:519)
      at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
      at org.apache.catalina.startup.Catalina.start(Catalina.java:581)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
      at java.lang.reflect.Method.invoke(Unknown Source)
      at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
      at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
  Caused by: org.apache.tiles.definition.DefinitionsFactoryException: I/O Error reading definitions.
      at org.apache.tiles.definition.digester.DigesterDefinitionsReader.read(DigesterDefinitionsReader.java:273)
      at org.apache.tiles.definition.UrlDefinitionsFactory.readDefinitions(UrlDefinitionsFactory.java:286)
      at org.apache.tiles.definition.UrlDefinitionsFactory.init(UrlDefinitionsFactory.java:130)
      at org.apache.tiles.impl.BasicTilesContainer.initializeDefinitionsFactory(BasicTilesContainer.java:406)
      at org.apache.tiles.impl.BasicTilesContainer.init(BasicTilesContainer.java:130)
      at org.apache.tiles.factory.TilesContainerFactory.initializeContainer(TilesContainerFactory.java:232)
      at org.apache.tiles.factory.TilesContainerFactory.createTilesContainer(TilesContainerFactory.java:198)
      at org.apache.tiles.factory.TilesContainerFactory.createContainer(TilesContainerFactory.java:163)
      at org.apache.tiles.web.startup.TilesListener.createContainer(TilesListener.java:90)
      at org.apache.struts2.tiles.StrutsTilesListener.createContainer(StrutsTilesListener.java:68)
      at org.apache.tiles.web.startup.TilesListener.contextInitialized(TilesListener.java:57)
      ... 15 more
  Caused by: java.net.SocketException: Connection reset
      at java.net.SocketInputStream.read(Unknown Source)
      at java.io.BufferedInputStream.fill(Unknown Source)
      at java.io.BufferedInputStream.read1(Unknown Source)
      at java.io.BufferedInputStream.read(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
      at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
      at org.apache.commons.digester.Digester.createInputSourceFromURL(Digester.java:2072)
      at org.apache.commons.digester.Digester.resolveEntity(Digester.java:1725)
      at com.sun.org.apache.xerces.internal.util.EntityResolverWrapper.resolveEntity(Unknown Source)
      at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.resolveEntityAsPerStax(Unknown Source)
      at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(Unknown Source)
      at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(Unknown Source)
      at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(Unknown Source)
      at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
      at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
      at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
      at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
      at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
      at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
      at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
      at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
      at org.apache.commons.digester.Digester.parse(Digester.java:1887)
      at org.apache.tiles.definition.digester.DigesterDefinitionsReader.read(DigesterDefinitionsReader.java:267)
      ... 25 more
  </code></pre>