Apache Tiles + Spring MVC serves jsps inside jar files

1k views Asked by At

Purpose
Design an "add-on" to a web project.

Web Project
I have a project packaged as WAR which uses Spring MVC 4.1.6 and Apache Tiles 3.0.5 as the UI framework. This a sample of the application-context:

<bean class="org.springframework.web.servlet.view.tiles3.TilesConfigurer" id="tilesConfigurer">
    <property name="definitions">
        <list>
            <value>/WEB-INF/foo/bar/layouts.xml</value>
            <value>classpath:/META-INF/ext/**/views.xml</value><!-- For add-ons -->
        </list>
    </property>
</bean>

JAR
I have another JAR, which is the "add-on". This jar will need to contain some jsp files. The general idea is, if I remove this jar from /WEB-INF/lib directory, all related features will be removed when I restart the web server. Likewise, all related features will be available when I put the jar into the lib directory. Sample tiles definition (views.xml):

<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
    <definition extends="main" name="space">
        <!-- This does not work -->
        <put-attribute name="body" value="classpath:/META-INF/resources/index.jspx" />
    </definition>
</tiles-definitions>


1. Can the jsp files that resides in the JAR file be defined in the tiles definition?
2. Can this be achieved with/without using web-fragment?

1

There are 1 answers

2
allancth On BEST ANSWER

Somehow, I managed to find the solution.

  1. Create a class that implements ServletContainerInitializer in your jar. Override method and add servlet mapping, something like this:

    @Override
    public void onStartup(final Set<Class<?>> clazzes, final ServletContext servletContext) throws ServletException {
        final ServletRegistration servletRegistration = servletContext.addServlet("name-of-servlet-declared-in-web.xml", DispatcherServlet.class);
        servletRegistration.addMapping("/name-of-tiles-definition");
    }
    
  2. In your tiles definition which resides in your jar, map the definition name added in #1.

    <tiles-definitions>
        <definition extends="main" name="name-of-tiles-definition">
            <put-attribute name="body" value="/path-to-resource/jsp-name.jspx" />
        </definition>
    </tiles-definitions>
    
  3. Create a file with name "javax.servlet.ServletContainerInitializer" in "/META-INF/services" directory. Inside this file should contain the FQDN of ServletContainerInitializer implementation.

  4. As for your JSPs, put them under the "/META-INF/resources/" directory. If for instance your JSPs are placed under "/META-INF/resources/example", in #2, the value for the "put-attribute" element would be "/example/jsp-name.jspx".

  5. Lastly, create your web-fragment.xml file in "/META-INF" directory. My web-fragment.xml contains nothing but only the "display.name" element. I am not sure if this file is necessary but since it worked for me I figured I'll just let it live in my hard drive.

In my jar, I have Controllers and i18n properties files as well, which is defined in the servlet-context, loaded and initialized in the main web.xml.

Let me know if this works for you. HTH.