<$BlogRSDUrl$>

Saturday, July 05, 2003

Precompiling JSP's under JBoss/Jetty 3.2.1... 

One of the things I've been meaning to do for quite some time now was to modify our build process to precompile our JSP's. With so many other higher priority things this kept getting pushed to the back burner... After the 10th time someone reported a bug which amounted to "first access to webpage seems abysmally slow", I finally broke down and started on this on the plane ride home from Montreal this week. Here's a summation of what is required to get JSP precompilation going under JBoss/Jetty 3.2.1.

First, a high-level rundown of the process :

  1. Using Jasper (a JSP compiler), we'll transform the JSP's into .java files (servlets).
  2. Jasper will also spit out a web.xml fragment with servlet definitions and mappings for each of the above generated servlets.
  3. We'll use the ant jspc task to make the previous two bullets a little easier.
  4. We'll compile the .java files into .class files and then copy them into the WEB-INF/classes directory of the WAR
  5. We'll insert the web.xml fragment generated by Jasper into your normal web.xml file (at a very specific place).
  6. build your war as normal
Ok, so here's the build target which generates the war in question (disregard project specific stuff) :
<target name="dist" depends="compile">

   <!-- copy required libs to WEB-INF/lib-->
   <copy todir="${dir.webinf}/lib">
      <fileset dir="${dir.thirdpartytools.struts}/lib"/>
      <fileset dir="${dir.thirdpartytools.jstl}/lib"/>
      <fileset dir="${dir.search}/dist/lib" includes="${jar.name.search-domain}, ${jar.name.search-services}"/>
   </copy>

   <!-- copy classes we built earlier to WEB-INF/classes -->
   <copy todir="${dir.webinf}/classes">
      <fileset dir="${classes}"/>
   </copy>

   <!-- copy the tld's we're using to WEB-INF/tld -->
   <copy todir="${dir.webinf}/tld">
      <fileset dir="${dir.thirdpartytools.struts}/tld" includes="*.tld"/>
      <fileset dir="${dir.thirdpartytools.jstl}/tld" includes="*.tld"/>
      <fileset dir="${dir.config}/tld" includes="*.tld"/>
   </copy>

   <!-- these two properties are the generated web.xml fragment, and the resulting merged xml-->
   <property name="jspc.webxml.fragment" value="${dir.jspc.temp}/jspc-web-xml-fragment.xml"/>
   <property name="jspc.webxml.merged" value="${dir.jspc.temp}/merged-web.xml"/>

   <path id="jspc.classpath">
      <path refid="cp.jspc"/>
      <path refid="cp.jboss"/>
      <path refid="cp.webclient-thirdparty.tools"/>
      <path refid="build.classpath"/>
      <fileset dir="${classes}"/>
      <fileset dir="${dir.webinf}/lib" includes="*.jar"/>
   </path>


   <!-- JSP -> .java -->
   <jspc srcdir="${dir.docroot}"
         destdir="${dir.jspc.gensrc}"
         verbose="9"
         classpathref="jspc.classpath"
         webinc="${jspc.webxml.fragment}">

     <include name="**/*.jsp"/>
   </jspc>

   <!-- .java -> .class -->
   <javac deprecation="${deprecation.javac}"
          fork="${fork.javac}"
          source="${source}"
          debug="${debug}"
          srcdir="${dir.jspc.gensrc}"
          destdir="${dir.webinf}/classes"
          classpathref="jspc.classpath"/>


   <!-- merge the jspc generated web.xml fragment with the real web.xml-->
   <loadfile property="jspc.webxml.fragment.contents" srcFile="${jspc.webxml.fragment}"/>
   <copy file="${dir.webinf}/web.xml" tofile="${jspc.webxml.merged}"/>

   <replace file="${jspc.webxml.merged}">
      <replacefilter token="&lt;!-- @JSPC-INSERT-HERE@ --&gt;" value="${jspc.webxml.fragment.contents}"/>
   </replace>

   <!-- Now war everything up -->
   <war destfile="${dist}/lib/${jar.name.epcportal-presentation}"
      webxml="${jspc.webxml.merged}">
      <fileset dir="${dir.docroot}"/>
      <classes dir="${classes}"/>
      <classes dir="${dir.property.file}">
         <include name="**/*.properties"/>
      </classes>
   </war>
</target>
In the above fragment, the following two properties are defined earlier :

<property name="dir.jspc.temp" value="${dist}/tmp/jspc"/>
<property name="dir.jspc.gensrc" value="${dir.jspc.temp}/gensrc"/>
And cp.jspc is defined as the following :

<path id="cp.jspc">
   <pathelement location="${jboss.home}/server/default/deploy/jbossweb-jetty.sar/jasper-compiler.jar"/>
   <pathelement location="${jboss.home}/server/default/deploy/jbossweb-jetty.sar/jasper-runtime.jar"/>
   <pathelement location="${ant_home}/lib/ant.jar"/>
</path>
Now, modify your existing web.xml file to have the following comment in it, just AFTER the last <servlet> tag and just BEFORE the first <servlet-mapping> tag.
      <!-- @JSPC-INSERT-HERE@ -->
This comment will serve as the insertion point where we'll include the jspc generated web.xml fragment. Here's an example of our web.xml file :

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN' 'http://java.sun.com/dtd/web-app_2_3.dtd'>
<web-app>


   <!-- Struts Action Servlet Configuration -->
   <servlet>
      <servlet-name>action</servlet-name>
      <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
      <init-param>
         <param-name>application</param-name>
         <param-value>ApplicationResources</param-value>
      </init-param>
      <init-param>
         <param-name>config</param-name>
         <param-value>/WEB-INF/struts-config.xml</param-value>
      </init-param>
      <init-param>
         <param-name>debug</param-name>
         <param-value>0</param-value>
      </init-param>
      <init-param>
         <param-name>detail</param-name>
         <param-value>0</param-value>
      </init-param>
      <init-param>
         <param-name>validate</param-name>
         <param-value>true</param-value>
      </init-param>
      <load-on-startup>2</load-on-startup>
   </servlet>





   <!-- JSP-PRECOMPILER INSERTION POINT, DO NOT REMOVE, MODIFY OR MOVE THE FOLLOWING LINE-->
   <!-- @JSPC-INSERT-HERE@ -->





   <!-- Action Servlet Mapping -->
   <servlet-mapping>
      <servlet-name>action</servlet-name>
      <url-pattern>*.do</url-pattern>
   </servlet-mapping>


   <!-- The Welcome File List -->
   <welcome-file-list>
      <welcome-file>index.jsp</welcome-file>
   </welcome-file-list>

   <error-page>
      <error-code>404</error-code>
      <location>/error404.jsp</location>
   </error-page>

   <error-page>
      <error-code>400</error-code>
      <location>/error400.jsp</location>
   </error-page>

   <error-page>
      <error-code>401</error-code>
      <location>/error401.jsp</location>
   </error-page>

	<error-page>
      <error-code>500</error-code>
      <location>/error500.jsp</location>
   </error-page>

   <!-- Struts Tag Library Descriptors -->
   <taglib>
      <taglib-uri>/tags/struts-bean</taglib-uri>
      <taglib-location>/WEB-INF/tld/struts-bean.tld</taglib-location>
   </taglib>

   <taglib>
      <taglib-uri>/tags/struts-html</taglib-uri>
      <taglib-location>/WEB-INF/tld/struts-html.tld</taglib-location>
   </taglib>

   <taglib>
      <taglib-uri>/tags/struts-logic</taglib-uri>
      <taglib-location>/WEB-INF/tld/struts-logic.tld</taglib-location>
   </taglib>
  <taglib>
    <taglib-uri>/tags/struts-nested</taglib-uri>
    <taglib-location>/WEB-INF/tld/struts-nested.tld</taglib-location>
  </taglib>

  <taglib>
    <taglib-uri>/tags/struts-tiles</taglib-uri>
    <taglib-location>/WEB-INF/tld/struts-tiles.tld</taglib-location>
  </taglib>

   <!-- JSTL -->
   <taglib>
     <taglib-uri>/tags/jstl-c</taglib-uri>
     <taglib-location>/WEB-INF/tld/c.tld</taglib-location>
   </taglib>

   <taglib>
     <taglib-uri>/tags/jstl-c-rt</taglib-uri>
     <taglib-location>/WEB-INF/tld/c-rt.tld</taglib-location>
   </taglib>

   <taglib>
     <taglib-uri>/tags/jstl-fmt</taglib-uri>
     <taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
   </taglib>

   <taglib>
     <taglib-uri>/tags/jstl-fmt-rt</taglib-uri>
     <taglib-location>/WEB-INF/tld/fmt-rt.tld</taglib-location>
   </taglib>

   <taglib>
     <taglib-uri>/tags/jstl-x</taglib-uri>
     <taglib-location>/WEB-INF/tld/x.tld</taglib-location>
   </taglib>

   <taglib>
     <taglib-uri>/tags/x-rt</taglib-uri>
     <taglib-location>/WEB-INF/tld/x-rt.tld</taglib-location>
   </taglib>

   <!-- Project Specific Tag Libs -->
   <taglib>
     <taglib-uri>/tags/epc</taglib-uri>
     <taglib-location>/WEB-INF/tld/epc.tld</taglib-location>
   </taglib>

</web-app>

OK - that's about it. A couple of things to watch out for :

This page is powered by Blogger. Isn't yours?