Struts2 & Tiles: When apache.org is down my webapp fails to start

19,635

Solution 1

I have discovered the problem and it is my fault, everything I said in my question was true however it was only true because there was a mismatch between the DTD version that was declared in the tiles.xml file and the version of tiles I was using.

I am actually using Tiles 2.0.6 but was referencing the DTD from tiles 2.1 so tiles was not referencing the bundled DTD and trying to download it instead.

<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
       "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

Should have been

<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_2_0.dtd">

Solution 2

I got a similar exception with below root cause -

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)

I am using Apache Tile 3.0.

Solution:

I downloaded the file "tiles-config_3_0.dtd" and placed it in WEB-INF/dtd dir. Made below changes in the tiles-definition.xml file -

<!DOCTYPE tiles-definitions PUBLIC
   "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
   "jndi:/localhost/myapp/WEB-INF/dtd/tiles-config_3_0.dtd">

It works fine and does not look for absolute path of the file thereafter.

Share:
19,635
3urdoch
Author by

3urdoch

Java webapp developer

Updated on June 08, 2022

Comments

  • 3urdoch
    3urdoch almost 2 years

    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.

    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.

    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.

    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.

    Struts tiles defenition file

    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE tiles-definitions PUBLIC
           "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
           "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
    <tiles-definitions>
        <definition name="master" template="/tiles/templates/master.jsp">
        </definition>
        <definition name="public" extends="master">
            <put-attribute name="header" value="/tiles/templates/public/header.jsp" />
            <put-attribute name="footer" value="/tiles/templates/public/footer.jsp" />
            <put-attribute name="templateMeta" value="/tiles/templates/public/meta.jsp" />
        </definition>  
    </tiles-definitions>
    

    Stacktrace when apache.org is down

    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
    
  • 3urdoch
    3urdoch about 13 years
    Yes I have done that but this is where the problem of the changing location on different developer machines comes in. The DTD path then has to be absolute, or relative to the working directory but the working directory isn't the same as the webapp root directory in my case its the tomcat instillation dir (or the eclipse instillation dir when developing in eclipse)
  • DaShaun
    DaShaun about 13 years
    It only has to be relative to the root of the application. So place the downloaded .dtd into your war file in /dtds
  • 3urdoch
    3urdoch about 13 years
    Tried that, doesn't work when i run it in eclipse it looks in the eclipse home directory and even throws a FileNotFoundException stating where it looked. "Caused by: java.io.FileNotFoundException: C:\Program Files (x86)\Eclipse Helios\tiles-config_2_1.dtd (The system cannot find the file specified)" if its running in tomcat its the same deal but the tomcat working directory.
  • Pierre Henry
    Pierre Henry about 13 years
    I had the exact same problem :) Your answer saved my day. Cheers
  • Pierpaolo Cira
    Pierpaolo Cira almost 9 years
    Wow... I wasn't able to figure that this misconfiguration was causing my issue... thanks
  • hurelhuyag
    hurelhuyag over 6 years
    jndi protocol working fine on development machine. But on ubuntu server can't understand jndi. Do you know why?