|
How do I build a versioned war file?
Author: Deron Eriksson
Description: This Ant tutorial shows how to build a versioned war file using a customized task
Tutorial created using:
Windows XP || JDK 1.5.0_09 || Eclipse Web Tools Platform 1.5.1
This tutorial will build upon much of the work that we've done in other tutorials. In other tutorials, we've created AntSW targets to perform tasks such as using Ant to compile our Java classes, building a war file, securely transferring a war file to a server using pscp, undeploying the web application from TomcatSW, deploying the warW file sitting on the server to Tomcat, and emailing us a message when the web application is done deploying. We also created tasks that allowed us to do such things as create versioned jar files. In addition, we created a customized Ant task that serves as a variable in Ant which is useful since an Ant property can't be changed after it is initially set. This tutorial will build upon this earlier work to create an Ant target that allows us to automatically build and deploy a versioned war file. The 'var' task based on the Variable class (that we created in another tutorial ) is included here in the teamcakes-ant-util-1.0.jar file, shown below. In another tutorial, I showed how to include this jarW file in the Ant classpathW so that we can use it, so I won't go over that here. teamcakes-ant-util-1.0.jar
PK
???6 META-INF/?? PK
???6h??? ? META-INF/MANIFEST.MF]??
?0E?@?!? ??J??u?,X\?Y?l??C??(????G?3?_p?fp???p???{"?,?{?QRM?\>?L???M?ls???????ubKI9?>|?-????~??x?s
O?<??qZ?$Wi??cKIm?-? !??9S?PK
'?6 com/PK
2?6
com/cakes/PK
@?6 com/cakes/ant/PK
??6???? ? com/cakes/ant/Variable.class}T?RA=Iv?,?" ?r?@V?QT????J?0???P???b)Ti??>?Q?=?0?V?zz?????L~????^kh`??;????v|a??lx\C??'(m?N??os[?W Yw?]???8Cji??sl???5Qr?,C|????L<p}W?04???2lr?0M?H???$ZM??Z??C????ra???%yQ?w?zUcLl?!C?RtDE??bY1???'????N)r?????j|???4c~???
?P??0???m?"
bX??^???????e??h?l????Kb
c'8/??5?yP?????^???N!?c??????j?,9N?
-??y??)?????????5?b?X_?*??t?aH?q!?f?
L?~??&?!?????d????9S55?%}Z????'L]4g?)?ih"?
Z??xFC?????M?V#rh???X???q&^a??)T???$?EE/???Ky????n>Y?I???H??~?V???3A]=#???N?
m?c4eR?_?d????L!F?$?$?V4?CY??f??jR?N?g???S-QB[??5pz????3?D???
#3tU???W70\?$?VO?;?H_4??z"}????J?????d??????????O????r???0?#??8?}H?wL?M?>???~j??,C?Ia?B3G????S??j???A?;??x??3u?ju?(??PK
???6 ?A META-INF/?? PK
???6h??? ? ??+ META-INF/MANIFEST.MFPK
'?6 ?A? com/PK
2?6
?A com/cakes/PK
@?6 ?AD com/cakes/ant/PK
??6???? ? ??p com/cakes/ant/Variable.classPK m ?
The ant-utilities build-main.properties file used in this tutorial (minus the juicy info that pertains to me) is included below. For more information about the ant-utilities project, which is created and described elsewhere, see the other Ant tutorials. ant-utilities build-main.properties#build-main.properties file project-name=ant-utilities builder=TeamCakes ftp-server=-- ftp-userid=-- ftp-password=-- tomcat-manager-url=http://--/manager tomcat-manager-username=-- tomcat-manager-password=-- server-home-directory=--/-- email-to=-- email-from=-- tomcat-home=/apache-tomcat-5.5.20 The original ant-utilities build-main.xml file that we'll start with is included below: original ant-utilities build-main.xml<?xml version="1.0" encoding="UTF-8"?> <project name="ant-utilities" default="war" basedir="."> <property file="build-main.properties" /> <property name="war-file-name" value="${project-name}.war" /> <property name="source-directory" value="src" /> <property name="classes-directory" value="bin" /> <property name="web-directory" value="web" /> <property name="web-xml-file" value="web/WEB-INF/web.xml" /> <tstamp prefix="build-info"> <format property="current-date" pattern="d-MMMM-yyyy" locale="en" /> <format property="current-time" pattern="hh:mm:ss a z" locale="en" /> <format property="year-month-day" pattern="yyyy-MM-dd" locale="en" /> </tstamp> <property name="build-directory" value="build" /> <property name="ftp-remotedir" value="uploaded-wars" /> <path id="project-classpath"> <fileset dir="web/WEB-INF/lib" includes="*.jar" /> <fileset dir="${tomcat-home}/bin" includes="*.jar" /> <fileset dir="${tomcat-home}/common/lib" includes="*.jar" /> <fileset dir="${tomcat-home}/server/lib" includes="*.jar" /> </path> <path id="jar-project-classpath"> <fileset dir="lib" includes="*.jar" /> <fileset dir="${tomcat-home}/bin" includes="*.jar" /> <fileset dir="${tomcat-home}/common/lib" includes="*.jar" /> <fileset dir="${tomcat-home}/server/lib" includes="*.jar" /> </path> <taskdef name="start" classname="org.apache.catalina.ant.StartTask" /> <taskdef name="stop" classname="org.apache.catalina.ant.StopTask" /> <taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask" /> <taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask" /> <taskdef name="var" classname="com.cakes.ant.Variable" /> <target name="variable-test"> <var name="myVar" value="value1" /> <echo>myVar is ${myVar}</echo> <var name="myVar" value="value2" /> <echo>myVar is ${myVar}</echo> </target> <target name="project-name-test"> <echo>hello, the project is: ${project-name}</echo> </target> <target name="stop" description="stop application in tomcat"> <stop url="${tomcat-manager-url}" username="${tomcat-manager-username}" password="${tomcat-manager-password}" path="/${project-name}" /> </target> <target name="start" description="start application in tomcat"> <start url="${tomcat-manager-url}" username="${tomcat-manager-username}" password="${tomcat-manager-password}" path="/${project-name}" /> </target> <target name="undeploy" description="undeploy from tomcat"> <undeploy failonerror="no" url="${tomcat-manager-url}" username="${tomcat-manager-username}" password="${tomcat-manager-password}" path="/${project-name}" /> </target> <target name="deploy" description="deploy to tomcat"> <echo>deploying from client</echo> <deploy url="${tomcat-manager-url}" username="${tomcat-manager-username}" password="${tomcat-manager-password}" path="/${project-name}" war="file:/projects/workspace/${project-name}/${build-directory}/${war-file-name}" /> </target> <target name="deploy-from-server"> <echo>deploying server war file</echo> <sleep seconds="5" /> <deploy url="${tomcat-manager-url}" username="${tomcat-manager-username}" password="${tomcat-manager-password}" path="/${project-name}" localwar="file:/${server-home-directory}/uploaded-wars/${war-file-name}" /> <echo>done deploying</echo> </target> <target name="war"> <mkdir dir="${build-directory}" /> <delete file="${build-directory}/${war-file-name}" /> <war warfile="${build-directory}/${war-file-name}" webxml="${web-xml-file}"> <classes dir="${classes-directory}" /> <fileset dir="${web-directory}"> <!-- Need to exclude it since webxml is an attribute of the war tag above --> <exclude name="WEB-INF/web.xml" /> </fileset> <manifest> <attribute name="Built-By" value="${builder}" /> <attribute name="Built-On" value="${build-info.current-date}" /> <attribute name="Built-At" value="${build-info.current-time}" /> </manifest> </war> </target> <target name="ftp" depends="" description="upload war file to server"> <ftp server="${ftp-server}" remotedir="${ftp-remotedir}" userid="${ftp-userid}" password="${ftp-password}" action="mkdir" verbose="yes"> </ftp> <ftp server="${ftp-server}" remotedir="${ftp-remotedir}" userid="${ftp-userid}" password="${ftp-password}" action="send" verbose="yes" depends="yes"> <fileset file="${build-directory}/${war-file-name}" /> </ftp> </target> <target name="pscp" depends="" description="securely upload war file to server"> <echo message="uploading war file to server using pscp" /> <exec executable="pscp.exe"> <arg value="-v" /> <arg value="-pw" /> <arg value="${ftp-password}" /> <arg value="${build-directory}/${war-file-name}" /> <arg value="${ftp-userid}@${ftp-server}:${ftp-remotedir}/${war-file-name}" /> </exec> <echo message="done uploading war file to server using pscp" /> </target> <target name="mail-build-and-deploy"> <mail from="${email-from}" tolist="${email-to}" subject="${war-file-name} was uploaded to the server and deployed" message="The ${war-file-name} file was uploaded to ${ftp-server} in ${ftp-remotedir} and deployed to the /${project-name} context" /> </target> <target name="clean"> <delete dir="bin" /> <mkdir dir="bin" /> </target> <target name="copy-non-java-files"> <copy todir="bin" includeemptydirs="false"> <fileset dir="src" excludes="**/*.java" /> </copy> </target> <target name="compile" depends="clean,copy-non-java-files"> <javac srcdir="src" destdir="bin" classpathref="project-classpath" /> </target> <target name="compile-jar-classes" depends="clean,copy-non-java-files"> <javac srcdir="src" destdir="bin" classpathref="jar-project-classpath" /> </target> <target name="clean-jar"> <delete dir="build" /> <mkdir dir="build" /> </target> <target name="jar"> <jar basedir="bin" destfile="build/${project-name}.jar"> <manifest> <attribute name="Built-By" value="${builder}" /> <attribute name="Built-On" value="${build-info.current-date}" /> <attribute name="Built-At" value="${build-info.current-time}" /> </manifest> </jar> </target> <target name="build-jar"> <antcall target="compile-jar-classes" /> <antcall target="clean-jar" /> <antcall target="jar" /> </target> <target name="jar-version"> <buildnumber /> <property name="version-number" value="${major-version-number}.${build.number}" /> <jar basedir="bin" destfile="build-version/${project-name}-${version-number}.jar"> <manifest> <attribute name="Built-By" value="${builder}" /> <attribute name="Built-On" value="${build-info.current-date}" /> <attribute name="Built-At" value="${build-info.current-time}" /> <attribute name="Implementation-Version" value="${version-number}" /> </manifest> </jar> </target> <target name="build-jar-version"> <antcall target="compile-jar-classes" /> <mkdir dir="build-version" /> <antcall target="jar-version" /> </target> <target name="build-and-deploy-from-server" depends="war,ftp,undeploy,deploy-from-server,mail-build-and-deploy" /> <target name="build-and-deploy-from-server (secure)" depends="war,pscp,undeploy,deploy-from-server,mail-build-and-deploy" /> <target name="kitchen-sink" depends="compile,war,pscp,undeploy,deploy-from-server,mail-build-and-deploy" /> </project> So, let's start hacking... To begin with, we need to replace two of our old properties with our new variable tasks, since their values are going to change. Personally, I really don't understand why the creators of Ant haven't added a 'variable' element to Ant. I can understand trying to avoid the use of Ant as a programming language by limiting the creation of variables, but personally I'd rather have variables since this can increase code maintainability through reduced code replication. Anyway, in our build-main.xml file, let's replace our 'war-file-name' and 'build-directory' properties with our 'var' task versions of the properties. So I'll replace
<property name="war-file-name" value="${project-name}.war" />
<property name="build-directory" value="build" />
with
<var name="war-file-name" value="${project-name}.war" />
<var name="build-directory" value="build" />
The only other change that we need to make is to add a 'war-version' target based on our original 'war' target. The original 'war' target is shown here:
<target name="war">
<mkdir dir="${build-directory}" />
<delete file="${build-directory}/${war-file-name}" />
<war warfile="${build-directory}/${war-file-name}" webxml="${web-xml-file}">
<classes dir="${classes-directory}" />
<fileset dir="${web-directory}">
<!-- Need to exclude it since webxml is an attribute of the war tag above -->
<exclude name="WEB-INF/web.xml" />
</fileset>
<manifest>
<attribute name="Built-By" value="${builder}" />
<attribute name="Built-On" value="${build-info.current-date}" />
<attribute name="Built-At" value="${build-info.current-time}" />
</manifest>
</war>
</target>
The new 'war-version' target is shown below. It is very similar to 'war'. However, first, we change the value of the 'build-directory' variable to be 'build-version' rather than the default 'build'. Then, we make this directory if it doesn't already exist. Next, it creates a build number if it doesn't exist and increments it if it already exists. Next, we create a 'version-number' property that consists of the 'major-version-number' property followed by a period followed by the build number that we either created or incremented. Next, we append the 'version-number' to the 'war-file-name' variable. I added an 'Implementation-Version' attribute set to the version number in the generated MANIFEST.MF file in case we ever needed to look inside the war file and see the version of the war file.
<target name="war-version">
<var name="build-directory" value="build-version" />
<mkdir dir="${build-directory}" />
<buildnumber />
<property name="version-number" value="${major-version-number}.${build.number}" />
<var name="war-file-name" value="${project-name}-${version-number}.war" />
<war warfile="${build-directory}/${war-file-name}" webxml="${web-xml-file}">
<classes dir="${classes-directory}" />
<fileset dir="${web-directory}">
<!-- Need to exclude it since webxml is an attribute of the war tag above -->
<exclude name="WEB-INF/web.xml" />
</fileset>
<manifest>
<attribute name="Built-By" value="${builder}" />
<attribute name="Built-On" value="${build-info.current-date}" />
<attribute name="Built-At" value="${build-info.current-time}" />
<attribute name="Implementation-Version" value="${version-number}" />
</manifest>
</war>
</target>
The values of the 'build-directory' and 'war-file-name' variable tasks will be used in any targets and tasks that are executed after they have been set in 'war-version' target. This allows us to use the same targets and tasks to transfer our war file to the server and to deploy it to the server. Since our 'deploy-from-server' target in build-main.xml uses the 'deploy' Tomcat task, we don't need to make any modifications to this target. The 'deploy' task lets us specify the both the 'localwar' war file name and location on the server, and it also lets us specify the 'path' that we should deploy to, which is basically the name of the web application. Since we set the path equal to '/${project-name}', this maps our versioned war file to the project name. Our 'tomcat-demo' web application project's build.xml file references our ant-utilities build-main.xml and build-main.properties files. It contains our 'major-version-number' property and our 'project-name' property. build.xml<?xml version="1.0" encoding="UTF-8"?> <project name="tomcat-demo" default="" basedir="."> <property name="major-version-number" value="1" /> <property name="project-name" value="${ant.project.name}" /> <property file="../ant-utilities/build-main.properties" /> <import file="../ant-utilities/build-main.xml" /> </project> (Continued on page 2) Related Tutorials: |

