Tuesday, December 30, 2008

Final Build Script

<?xml version="1.0"?>
<project name="Consumer" basedir="." xmlns:artifact="antlib:org.apache.maven.artifact.ant">

<property name="src" value="src" />
<property name="project.build" value="build" />
<property name="classes" value="WEB-INF/classes" />
<property name="dist" value="dist" />
<property name="classpath" value="WEB-INF/lib" />
<!-- Specify the location of your local Maven repository -->
<property name="repository1.home" value="${user.home}\.m2"/>
<property name="repository.home" value="http://10.20.21.80:80/artifactory/repo"/>
<echo message="Repository Location: ${user.home} ${repository.home} "/>
<artifact:localRepository id="local.repository" path="${repository.home}" layout="default"/>
<property name="webapp.lib" value="WEB-INF/lib" />
<!-- junit test case properties -->
<property name="test.reports" value="reports" />
<property name="test.src" value="WEB-INF/src/test" />


<!-- runtime parameters from build -->
<property environment="env" />
<property name="ms.server.name" value="${env.MS_SERVER_NAME}" />
<property name="ms.server.port" value="${env.MS_SERVER_PORT}" />
<property name="ms.db.url" value="${env.MS_URL}" />
<property name="rating.url" value="${env.RATING_URL}" />
<property name="mode" value="${env.MODE}" />
<echo message="Build mode: ${mode} Server NAME:${ms.server.name} Server PORT: ${ms.server.port} Server URL: ${ms.db.url} Rating URL: ${rating.url}" />

<!--Load the Maven project file and assign some id for the project -->
<artifact:pom file="pom.xml" id="maven.project" />

<target name="init">
<tstamp />
<mkdir dir="${project.build}" />
<mkdir dir="${project.build}/${src}" />
<mkdir dir="${project.build}/${dist}" />
<mkdir dir="${project.build}/${dist}/int" />
<mkdir dir="${project.build}/${dist}/live" />
<mkdir dir="${project.build}" />
<mkdir dir="${test.reports}" />
<mkdir dir="${test.reports}/test-classes" />
</target>

<target name="setup" depends="init">
<copy todir="${project.build}/${src}">
<fileset dir="" defaultexcludes="yes" excludes="build.xml">
<exclude name="**/*Test*" />
<exclude name="PROJ_SETTING_TEMP/**" />
<exclude name="build/**" />
<exclude name="reports/**" />
</fileset>
</copy>
</target>

<!-- Export various classpath variables from the Maven -->
<target name="resolve.dependencies">
<artifact:dependencies pathId="compile.classpath" filesetId="compile.fileset" useScope="compile">
<pom refid="maven.project"/>
</artifact:dependencies>
<artifact:dependencies pathId="runtime.classpath" filesetId="runtime.fileset" useScope="runtime">
<pom refid="maven.project"/>
</artifact:dependencies>
<artifact:dependencies pathId="test.classpath" filesetId="test.fileset" useScope="test">
<pom refid="maven.project"/>
</artifact:dependencies>
</target>

<target name="buildlocal">
<!-- Add here if you want seperate build process for developer machine -->
<antcall target="builddev" inheritall="yes" inheritrefs="yes">
<param name="mode" value="int"/>
<param name="ms.server.name" value="Local"/>
<param name="ms.server.port" value="80"/>
<param name="ms.db.url" value="msdev1.wwe.com"/>
<param name="rating.url" value="ratingdev.proxy7.wwe.com"/>
</antcall>

<antcall target="deploy-local" />
</target>

<target name="builddev" depends="setup, resolve.dependencies, create-release-info, copy-config-file, compile, create-war, test" />

<target name="buildqa" depends="setup, resolve.dependencies, create-release-info,copy-config-file, compile, create-war">
</target>

<target name="buildstage" depends="setup, resolve.dependencies, create-release-info, copy-config-file, compile, create-war">
</target>

<target name="buildlive" depends="setup, resolve.dependencies, create-release-info, copy-config-file, compile, create-war">
</target>

<target name="build-all">
<antcall target="builddev" inheritall="yes" inheritrefs="yes">
<param name="mode" value="int"/>
<param name="ms.db.url" value="msdev1.wwe.com"/>
<param name="rating.url" value="ratingdev.proxy7.wwe.com"/>
</antcall>
<antcall target="buildlive" inheritall="yes" inheritrefs="yes">
<param name="mode" value="live"/>
<param name="ms.db.url" value="localhost"/>
<param name="rating.url" value="ratings.wwe.com"/>
</antcall>
</target>

<target name="create-war">
<echo message="MODE: ${mode}"/>
<!-- replace the dynamic parameters for the build -->
<replace file="${project.build}/src/WEB-INF/${mode}.web.xml">
<replacefilter token="MS_SERVER_NAME" value="${ms.server.name}" />
<replacefilter token="MS_SERVER_PORT" value="${ms.server.port}" />
<replacefilter token="MS_URL" value="${ms.db.url}" />
<replacefilter token="RATING_URL" value="${rating.url}" />
</replace>
<!-- copy runtime libraries -->
<copy todir="${project.build}/${src}/${webapp.lib}">
<fileset refid="runtime.fileset" />
<mapper type="flatten" />
</copy>
<!-- create the war file, exclude all unwanted files -->
<war destfile="${project.build}/${dist}/${mode}/ROOT.war" webxml="${project.build}/src/WEB-INF/${mode}.web.xml" duplicate="preserve">
<fileset dir="${project.build}/${src}">
<exclude name="**/WEB-INF/src/**" />
<exclude name="**/WEB-INF/web.xml" />
<exclude name="**/WEB-INF/*.web.xml" />
<exclude name="**/WEB-INF/classes/*.*.properties" />
<exclude name="**/WEB-INF/classes/test/**" />
<exclude name="**/WEB-INF/templates/samples/**/*.*" />
</fileset>
<!--classes dir="${project.build}/${src}/${classes}" /-->
</war>
</target>

<target name="compile">
<!-- compile the java & jsp files -->
<javac srcdir="${project.build}/${src}/WEB-INF/src" destdir="${project.build}/src/${classes}" classpath="${classpath}" fork="true" failonerror="true" verbose="off">
<compilerarg value="-Xlint:-path -Xlint:-deprecation -Xlint:-unchecked"/>
<classpath >
<fileset dir="${classpath}" includes="*.jar"/>
</classpath>
<classpath refid="compile.classpath"/>
</javac>
</target>

<target name="copy-config-file">
<copy file="WEB-INF/src/${mode}.oscache.properties" overwrite="true" tofile="${project.build}/${src}/WEB-INF/classes/oscache.properties" />
<copy file="WEB-INF/src/${mode}.log4j.properties" overwrite="true" tofile="${project.build}/${src}/WEB-INF/classes/log4j.properties" />
</target>

<target name="create-release-info">
<echo message="MODE: ${mode}"/>
<!-- Build timestamp in the release.jsp -->
<echo file="${project.build}/src/release.jsp" message="Build MODE: ${mode}. " />
<tstamp>
<format property="timestamp" pattern="yyyy/MM/dd hh:mm:ss z" />
</tstamp>
<echo file="${project.build}/src/release.jsp" message=" Built at: ${timestamp}." append="true" />
<echo file="${project.build}/src/release.jsp" message=" Build Parameters used in web.xml. Server NAME:${ms.server.name} Server PORT: ${ms.server.port} Server URL: ${ms.db.url} Rating URL: ${rating.url}" append="true" />
</target>

<path id="junit.classpath.test">
<pathelement location="${test.reports}/test-classes" />
<pathelement location="${project.build}/src/${classes}" />
<path refid="test.classpath" />
<fileset dir="${classpath}" includes="*.jar"/>
</path>

<target name="test" depends="resolve.dependencies">
<!-- compile test cource -->
<javac srcdir="${test.src}" destdir="${test.reports}/test-classes" classpath="${classpath}">
<classpath refid="junit.classpath.test"/>
</javac>

<!-- run junit -->
<junit fork="yes" haltonfailure="yes" showoutput="yes" printsummary="yes" >
<batchtest fork="yes" todir="${test.reports}" haltonfailure="false" haltonerror="false" >
<fileset dir="${test.src}" includes="**/*Test*.java"/>
</batchtest>
<formatter type="xml" usefile="true" />
<classpath refid="junit.classpath.test"/>
</junit>

<!-- generate junit reports -->
<junitreport todir="${test.reports}">
<fileset dir="${test.reports}">
<include name="TEST-*.xml" />
</fileset>
<report todir="${test.reports}" />
</junitreport>

<!-- cleanup -->
<delete dir="${test.reports}/test-classes" />
</target>

<target name="deploy-local">
<!-- move the file to J2EE-HOME -->
<property environment="env"/>
<copy file="${project.build}/${dist}/int/ROOT.war" overwrite="true" todir="${env.J2EE_HOME}/webapps" />
</target>

<target name="clean-build">
<delete dir="${project.build}/src" includeEmptyDirs="true"/>
</target>

<target name="clean-all">
<delete dir="${project.build}" />
<delete dir="${test.reports}" />
</target>
</project>

Tuesday, December 16, 2008

Ant Script

I was looking for JSP Pre-compilation using Ant, Tomcat 6.0. It took me a while to find required resources and complete the pre-compilation for my project. I am creating this blog with the steps i have used for JSP Pre-compilation for Tomcat 6.0. There is not a lot of information available on internet which really works.

Below is the ant script for jsp-precompilation:

<target name="builddev_jspprecompile" depends="setup">
The below task helps in creating a release.jsp and places under the jsp source folder. Any time we run a build, the release jsp is updated with the MODE (DEV, QA, STAGE, PROD). Along with that the build time stamp is added to the jsp. Both these information helps to ensure each environment has the right build. The jsp can be accessed using http://localhost/myapp/release.jsp.

<!-- Build timestamp in the release.jsp -->
<echo file="${build}/src/release.jsp" message="Build in DEV mode. "/>
<tstamp>
<format property="timestamp" pattern="yyyy/MM/dd hh:mm:ss z" />
</tstamp>
<echo file="${build}/src/release.jsp" message=" Built at: ${timestamp}." append="true"/>

The below copy task copies the configuration/properties files required by the application.

<copy file="WEB-INF/src/oscache.properties" overwrite="true" tofile="${build}/${src}/WEB-INF/classes/oscache.properties" />
<!--copy file="WEB-INF/src/dev.log4j.properties" overwrite="true" tofile="${build}/${src}/WEB-INF/classes/log4j.properties" /-->
<copy file="WEB-INF/src/log4j.properties" overwrite="true" tofile="${build}/${src}/WEB-INF/classes/log4j.properties" />
<echo message="builddev: ${classpath} build: ${build}"/>

Below statements are properties for setting up J2EE-HOME. In my case, it will refer to Tomcat 6.0. J2EE-HOME has been set as an environmental variable in my computer.

<!-- these two properties are the generated web.xml fragment, and the resulting merged xml-->
<property name="jspc.webxml.fragment" value="${build}/src/WEB-INF/jspc-xml-fragment-web.xml"/>
<property name="jspc.webxml.merged" value="${build}/src/WEB-INF/jspc-merged-web.xml"/>
<property name="dir.jspc.gensrc" value="${build}/src/WEB-INF/src"/>
<property environment="env"/>

<!--property name="tomcat.home" value="C:/Software/Tomcat6.0"/ -->
<property name="tomcat.home" value="${env.J2EE-HOME}"/>
<property name="ant.home" value="${env.ANT-HOME}"/>
<echo message="Tomcat Home: ${tomcat.home}" />

Jspc class was used to generate Java code from JSP, and generates the fragmented xml file specified by the property "jspc.webxml.fragment". Below is the code snipplet for generating the java classes.

<!-- create the java class from jsp files -->
<java classname="org.apache.jasper.JspC" fork="true" failonerror="true">
<arg line="-d ${dir.jspc.gensrc} -p com.wwe.jspc -v -s -l
-uriroot ${build}/${src}
-webinc ${jspc.webxml.fragment}
-webapp ${build}/${src}"/>
<classpath>
<fileset dir="${classpath}" includes="ant.jar"/>
<fileset dir="${ant.home}/lib" includes="*.jar"/>
<fileset dir="${tomcat.home}/lib" includes="*.jar"/>
<fileset dir="${tomcat.home}/bin" includes="*.jar"/>
</classpath>
</java>

Finally Javac compiler compiles the project Java files ( including JSP files).

<!-- compile the java & jsp files -->
<javac debuglevel="lines,vars,source" srcdir="${build}/${src}/WEB-INF/src" destdir="${build}/src/${classes}" classpath="${classpath}" fork="true" failonerror="true" verbose="true">
<classpath>
<fileset dir="${classpath}" includes="*.jar"/>
<fileset dir="${tomcat.home}/lib" includes="*.jar"/>
</classpath>
<exclude name="**/common/galleryThumbnail_jsp.java" />
<exclude name="**/common/gallerybuilderfooter_jsp.java" />
</javac>

Below code merges the generated web xml with the project specific web.xml. I am using the string "<!-- @JSPC-INSERT-HERE@ -->" in my web.xml. The below code always looks for that string, and then replaces the generated xml with it.

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

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

The last step is to create the war file including all the .class files and libraries. Any generated code can be eliminated here using excludes.

<!-- create the war file, exclude all unwanted files -->
<war destfile="${build}/${dist}/dev/ROOT.war" webxml="${jspc.webxml.merged}" duplicate="preserve">
<fileset dir="${build}/${src}">
<exclude name="**/WEB-INF/src/**" />
<exclude name="**/WEB-INF/web.xml" />
<exclude name="**/WEB-INF/*.web.xml" />
<exclude name="**/WEB-INF/*-web.xml" />
<exclude name="**/WEB-INF/classes/*.*.properties" />
<exclude name="**/WEB-INF/classes/test/**" />
<!--exclude name="**/WEB-INF/classes/**/*.*" / -->
<exclude name="**/WEB-INF/templates/samples/**/*.*" />
</fileset>
<!--classes dir="${build}/${src}/${classes}" /-->
</war>

The below task moves the war file to the J2EE-HOME deployment directory.

<!-- move the file to J2EE-HOME -->
<copy file="${build}/${dist}/dev/ROOT.war" overwrite="true" todir="${tomcat.home}/webapps" />
</target>

I kept everything under one task. This is just for me to follow up the steps. I am working on a new version to seperated the task, i might publish it in future.