views:

2165

answers:

5

We have the usual web.xml for our web application which includes some jsp and jsp tag files. I want to switch to using pre-compiled jsp's. I have the pre-compilation happening in the build ok, and it generates the web.xml fragment and now I want to merge the fragment into the main web.xml.

Is there an include type directive for web.xml that will let me include the fragment.

Ideally I will leave things as is for DEV- as its useful to change jsp's on the fly and see the changes immediately but then for UAT/PROD, the jsp's will be pre-compiled and thus work faster.

+1  A: 

Doh - there is an option on the jasper2 task to auto-merge the fragment into the main web.xml - addWebXmlMappings

    <jasper2
         validateXml="false"
         uriroot="${web.dir}"
         addWebXmlMappings="true"
         webXmlFragment="${web.dir}/WEB-INF/classes/jasper_generated_web.xml"
         outputDir="${web.dir}/WEB-INF/jsp-src" />

I wonder how good the merge is...

Annoyingly you need to generate the fragment still, even though its not needed after this task.

Chris Kimpton
+3  A: 

I use the Tomcat jasper ANT tasks in my project, which precompile the JSPs into servlets and add the new servlet mappings to the original web.xml. In the DEV builds, just skip this step and deploy the JSPs without pre-compile and modification of the web.xml.

    <?xml version="1.0"?>
<project name="jspc" basedir="." default="all">
 <import file="${build.appserver.home}/bin/catalina-tasks.xml"/>

 <target name="all" depends="jspc,compile"></target>

 <target name="jspc">
  <jasper
   validateXml="false"
   uriroot="${build.war.dir}"
   webXmlFragment="${build.war.dir}/WEB-INF/generated_web.xml"
   addWebXmlMappings="true"
   outputDir="${build.src.dir}" />
 </target>

 <target name="compile">
  <javac destdir="${build.dir}/classes"
   srcdir="${build.src.dir}"
   optimize="on"
   debug="off"
   failonerror="true"
   source="1.5"
   target="1.5"
   excludes="**/*.smap">
   <classpath>
    <fileset dir="${build.war.dir}/WEB-INF/classes">
     <include name="*.class" />
    </fileset>
    <fileset dir="${build.war.lib.dir}">
     <include name="*.jar" />
    </fileset>
    <fileset dir="${build.appserver.home}/lib">
     <include name="*.jar" />
    </fileset>    
    <fileset dir="${build.appserver.home}/bin">
     <include name="*.jar"/>
    </fileset>
   </classpath>
    <include name="**" />
    <exclude name="tags/**"/>
  </javac>
 </target>

 <target name="clean">
  <delete>
   <fileset dir="${build.src.dir}"/>
   <fileset dir="${build.dir}/classes/org/apache/jsp"/>
  </delete>
 </target>
</project>

If you already have the JSP compilation working and just want to merge the web.xml files, a simple XSLT could be written to add selected elements(such as the servlet mappings) from the newly generated web,xml into your original.

Mads Hansen
+2  A: 

Because the generated fragment is not a valid XML file ( it's a fragment after all ), it is not possible to use XSLT directly. On the other hand you don't have to. Here is a simple trick that will give you exactly what you need.

In your web.xml file insert XML comment <!-- @JSPS_MAP@ --> between <servlet> and <servlet-mapping> elements, e.g.

  <servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>my.servlets.MyServlet</servlet-class>
  <servlet>

  <!-- @JSPS_MAP@ -->

  <servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/my-servlet</url-pattern>
  </servlet-mapping>

Then use a token filter to replace @JSPS_MAP@ tag with generated content.

<loadfile
  property="generated.web.xml.fragment"
  srcFile="${generated.fragment.file}"
/>

<copy file="${orig-web-content.dir}/WEB-INF/web.xml"
  toFile="${generated-web-content.dir}/WEB-INF/web.xml"
>
  <filterset>
    <filter token="JSPS_MAP"
      value=" --&gt; ${generated.web.xml.fragment} &lt;!-- "
    />
  </filterset>
</copy>

This approach has an advantage that the original web.xml file is completely valid (a tag is hidden in the comment), but gives you total control of where and when the generated fragment will be inserted.

So for DEV build, just copy ${orig-web-content.dir}/WEB-INF/web.xml to ${generated-web-content.dir}/WEB-INF/web.xml without filtering.

Alexander Pogrebnyak
+1  A: 

There is the jasper2 ant task others have noted. I thought I'd mention a couple of other options I've found.

One is cactus' webxmlmerge ant task, which uses org.codehaus.cargo.module.webapp.WebXmlMerger

Another would be to use JAXB to manipulate the web.xml; Sebastien Dionne's dtd-schemas-generator demo does this. Not sure what the license is though.

fwiw having considered these options i think I'm going to use the ant XSLT task.

plutext
+1  A: 

In your web.xml file if you have tags to specify where the merge starts and ends the addWebXmlMappings flag will generate the file correctly for you. The tags are: and after doing this to my web.xml everything worked like a charm! (I have to look at the code for org.apcahe.jasper.JspC to see how this was implemented)

Rick Justesen