Create specific WAR file - ant

In a ANT script, is there a way to include a file from 'environnement' directory into the different war ?
My filesystem tree :
environnementDEVweb.xmllog4j.propertiesINTweb.xmllog4j.propertiesWebContentWEB-INFweb.xmllog4j.properties
Extract from build.xml :
<target name="createForDEV">
<delete file="environnement/DEV/${timeStampDay}/${warfile}.war" />
<war destfile="environnement/DEV/${timeStampDay}/${warfile}.war" webxml="environnement/DEV/web.xml" update="true">
<classes dir="build/classes" />
<fileset dir="WebContent">
<exclude name="WEB-INF/web.xml" />
<exclude name="**/Thumbs.db" />
</fileset>
</war>
</target>
<target name="createForINT">
<delete file="environnement/INT/${timeStampDay}/${warfile}.war" />
<war destfile="environnement/INT/${timeStampDay}/${warfile}.war" webxml="environnement/INT/web.xml" update="true">
<classes dir="build/classes" />
<fileset dir="WebContent">
<exclude name="WEB-INF/web.xml" />
<exclude name="**/Thumbs.db" />
<exclude name="**/test.jsp" />
</fileset>
</war>
</target>
I have two configuration files :
for DEV environment
for INT environment
When I make the WAR file, I would like to ignore some files and replace them by others specific files from 'environnement' directory ?
When making WAR in createForDEV target, I would like to take file from environnement/DEV and replace corresponding files
When making WAR in createForINT target, I would like to take file from environnement/INT and replace corresponding files

The trick here is to utilize the duplicate attribute of the war task, and to include multiple fileset elements. The value preserve for duplicate tells it to ignore duplicate entries. The files in the first fileset (from either DEV or INT) will be placed in the war first. Any additional files in WebContent will be included by the second fileset, but any files already included from DEV or INT will be ignored.
<target name="createForDEV">
<delete file="environnement/DEV/${timeStampDay}/${warfile}.war" />
<war destfile="environnement/DEV/${timeStampDay}/${warfile}.war" webxml="environnement/DEV/web.xml" update="true" duplicate="preserve">
<classes dir="build/classes" />
<fileset dir="environnement/DEV">
<exclude name="web.xml" />
</fileset>
<fileset dir="WebContent">
<exclude name="WEB-INF/web.xml" />
<exclude name="**/Thumbs.db" />
</fileset>
</war>
</target>
<target name="createForINT">
<delete file="environnement/INT/${timeStampDay}/${warfile}.war" />
<war destfile="environnement/INT/${timeStampDay}/${warfile}.war" webxml="environnement/INT/web.xml" update="true" duplicate="preserve">
<classes dir="build/classes" />
<fileset dir="environnement/INT">
<exclude name="web.xml" />
</fileset>
<fileset dir="WebContent">
<exclude name="WEB-INF/web.xml" />
<exclude name="**/Thumbs.db" />
<exclude name="**/test.jsp" />
</fileset>
</war>
</target>

Related

Is it possible to have a fileset with multiple source directories?

I have some ant logic that looks like this:
<copy todir="src_#{version}" flatten="true">
<fileset dir="${generic-libs.source}\prolo">
<include name="**/*.c"/> <!-- all .c files including subfolders -->
<include name="**/*.h"/> <!-- all .h files including subfolders -->
<exclude name="**/test/*.*" /> <!-- exclude test (sub)folders -->
<exclude name="**/test*.*" /> <!-- exclude remaining test sources -->
</fileset>
<fileset dir="${generic-libs.source}\genlo">
<include name="**/*.c"/>
<include name="**/*.h"/>
<exclude name="**/test/*.*" />
<exclude name="**/test*.*" />
</fileset>
<fileset dir="${generic-libs.source}\ptclo">
<include name="**/*.c"/>
<include name="**/*.h"/>
<exclude name="**/test/*.*" />
<exclude name="**/test*.*" />
</fileset>
...
</copy>
The ... has 10 more identical constructs.
The contents of the fileset tag are always the same, so I guess there has to be a way to shorten this?
Ant 1.9.4 introduced multirootfileset for that purpose :
A new resourcecollection type acts like a union of <fileset>s and <dirset>s that share the same configuration but have different base directories.
In your case something like :
<multirootfileset basedirs="${generic-libs.source}\prolo,${generic-libs.source}\genlo,${generic-libs.source}\ptclo">
<include name="**/*.c"/>
<include name="**/*.h"/>
<exclude name="**/test/*.*"/>
<exclude name="**/test*.*"/>
</multirootfileset>

Compiled classes are not included in generated Jar

I am creating a jar bundle using ant build script. The problem is that the .class files are not included in the generated .jar file. I have also tried the {build.dest} in making the jar, but with no effect.
remaining all the files i require are in .jar file.
Here is my build script
<?xml version="1.0"?>
<project name="TaskNodeBundle" default="all" basedir=".">
<!-- Sets variables which can later be used. -->
<!-- The value of a property is accessed via ${} -->
<property name="bundlename" value="task-node-bundle" />
<property name="src.dir" location="../src" />
<property name="lib.dir" location="../lib" />
<property name="build.dir" location="/buildoutput" />
<property name="build.dest" location="../build/dest" />
<!--
Create a classpath container which can be later used in the ant task
-->
<path id="classpath">
<fileset dir="${lib.dir}/">
<include name="*.jar" />
</fileset>
</path>
<target name="clean">
<delete dir="${build.dir}" />
<delete dir="${build.dest}" />
</target>
<!-- Deletes the existing build directory -->
<target name="mkdir" depends="clean">
<mkdir dir="${build.dest}"/>
</target>
<!-- Compiles the java code -->
<target name="compile" depends="mkdir">
<javac srcdir="${src.dir}" destdir="${build.dest}" classpathref="classpath" />
</target>
<target name="package-bundle" depends="compile" description="Generates the bundle" >
<jar destfile="${build.dest}/${bundlename}.jar" manifest="${src.dir}/META-INF/MANIFEST.MF">
<fileset dir="${src.dir}">
<include name="**/**.class" />
<include name="**/**.properties"/>
<include name="/META-INF/**.*" />
<include name="/META-INF/spring/**.*" />
</fileset>
</jar>
</target>
<target name="all" depends="package-bundle">
</target>
</project>
Firstly, what do you mean by "tried {build.dest} in making the jar"?
Whatever, you need to take a look at this part of your build:
<jar destfile="${build.dest}/${bundlename}.jar" manifest="${src.dir}/META-INF/MANIFEST.MF">
<fileset dir="${src.dir}">
<include name="**/**.class" />
<include name="**/**.properties"/>
<include name="/META-INF/**.*" />
<include name="/META-INF/spring/**.*" />
</fileset>
</jar>
You compiled class files are in ${build.dest}, so you should use ${build.dest} as the root dir for the nested <fileset> of the <jar> task. But now you are pointing the <fileset> to your source code folder.
You should avoid putting the generated jar file in the same directory where the class files are. For example, you can put the jar in ${dist.dir}, which is another directory.
So try this:
You have a property:
<property name="dist.dir" value="../build/dist" />
And then,
<jar destfile="${dist.dir}/${bundlename}.jar" manifest="${src.dir}/META-INF/MANIFEST.MF">
<fileset dir="${build.dest}">
<include name="**/*.class" />
</fileset>
<fileset dir="${src.dir}">
<include name="**/*.properties"/>
<include name="/META-INF/**/*.*" />
<include name="/META-INF/spring/**/*.*" />
</fileset>
</jar>

MANIFEST.MF is override after running build.xml using ant

have following directory structure
src/com
src/META-INF/MANIFEST.MF
src/META-INF/spring
src/META-INF/spring/context.xml
now when i run the script, my menifest file is override, i don't want that, because i have to add custom enteries in it and i want that to be adding in generated .jar file. THing is all other files are copied, but this one is override.
my build.xml is as follows
<project name="TaskNodeBundle" default="all" basedir=".">
<!-- Sets variables which can later be used. -->
<!-- The value of a property is accessed via ${} -->
<property name="bundlename" value="tasknodebundle" />
<property name="src.dir" location="../src" />
<property name="lib.dir" location="../lib" />
<property name="build.dir" location="/buildoutput" />
<property name="build.dest" location="../build/dest" />
<!--
Create a classpath container which can be later used in the ant task
-->
<path id="classpath">
<fileset dir="${lib.dir}/">
<include name="*.jar" />
</fileset>
</path>
<target name="clean">
<delete dir="${build.dir}" />
<delete dir="${build.dest}" />
</target>
<!-- Deletes the existing build directory-->
<target name="mkdir" depends="clean">
<mkdir dir="${build.dest}"/>
</target>
<!-- Compiles the java code -->
<target name="compile" depends="mkdir">
<javac srcdir="${src.dir}" destdir="${build.dest}" classpathref="classpath" />
</target>
<target name="package-bundle" depends="compile" description="Generates the bundle">
<jar destfile="${build.dest}/${bundlename}.jar">
<fileset dir="${src.dir}">
<include name="**/**.class" />
<include name="**/**.properties"/>
<include name="/META-INF/**.*" />
<include name="/META-INF/spring/**.*" />
</fileset>
</jar>
</target>
<target name="all" depends="package-bundle">
</target>
</project>
See http://ant.apache.org/manual/Tasks/jar.html.
If the manifest is omitted, a simple one will be supplied by Apache
Ant.
Just add manifest attribute or use zip task.
Also ant path masks are used incorrectly. See http://en.wikibooks.org/wiki/Apache_Ant/Fileset.
Corrected version:
<zip destfile="${build.dest}/${bundlename}.jar">
<fileset dir="${src.dir}">
<include name="META-INF/**" />
<include name="**/*.class" />
<include name="**/*.properties"/>
</fileset>
</zip>

How to Obfuscate my web application project.war using Ant & YGuard?

We developed a web application (struts 1.x/Hibernate based) for which I built a
war file using ANT build script. Now, my company wants me to obfuscate the .classes files
before generating a war & distributing it to the client. When I googled, I came
across an example using YGuard library to accomplish this task. The link was pretty useful however, I only had a partial success, as it obfuscated all the java classes, leaving behind the hibernate mapping (*.hbm.xml) files un-obfuscated, which had references to these classes which were already obfuscated.
For example: After obfuscation, references to MenuGlobalBean.class would turn to something like say A.B.H.I.N(where A,B..are package names & N is the class name).
But my MenuGlobal.hbm.xml still refers to this as
<class name="com.mycompany.myproduct.bean.MenuGlobalBean" table="MENU_GLOBAL">
rather than
<class name="A.B.H.I.N" table="MENU_GLOBAL">
Now my question is how do I obfuscate my war file in such a way that
the obfuscated class references reflect in my *.hbm.xml & other config/property files if any.
Below is my complete ANT build script using YGuard library for obfuscation
<!-- Build MyProject.war section -->
<project name="MyProject" default="dist" basedir=".">
<property name="proj-home" value="/home/simba/tomcat-7.0.19/webapps/MyProject" />
<!-- set global properties for this build -->
<property name="src" location="WEB-INF/src"/>
<property name="build" location="build"/>
<property name="lib" location="WEB-INF/lib"/>
<property name="dist" location="dist"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
</target>
<path id="project-classpath">
<fileset dir="${proj-home}/WEB-INF/lib" includes="*.jar" />
</path>
<target name="copy-non-java-files">
<copy todir="build" includeemptydirs="false">
<fileset dir=".">
<include name="*" />
<include name="css/**/*" />
<include name="help_files/**/*" />
<include name="images/**/*" />
<include name="js/**/*" />
<include name="jsp/**/*" />
<include name="schemas/**/*" />
<include name="Sounds/**/*" />
<include name="VideoImage/**/*" />
<exclude name="WEB-INF/src" />
<exclude name="yguard.jar" />
<exclude name="*.war" />
<exclude name="build.xml" />
</fileset>
<fileset dir=".">
<include name="WEB-INF/classes/**/*" />
<include name="WEB-INF/classes/*.xml" />
<include name="WEB-INF/lib/**/*" />
<include name="WEB-INF/*.xml" />
<include name="WEB-INF/*.properties"/>
<include name="WEB-INF/*.dtd" />
<include name="WEB-INF/*.tld" />
<include name="WEB-INF/*.txt" />
<include name="WEB-INF/*.ico" />
</fileset>
</copy>
</target>
<target name="compile" depends="clean,init,copy-non-java-files" description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}/WEB-INF/classes" classpathref="project-classpath"/>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}/lib"/>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<war jarfile="${dist}/lib/MyProject.war" basedir="${build}"/>
</target>
<target name="clean"
description="clean up" >
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
<!-- Using Yguard to obfuscate my .war file -->
<!-- prepare a temporary directory in which the war file is expanded and obfuscated -->
<tempfile property="unwar.dir" destdir="${java.io.tmpdir}" deleteonexit="no"/>
<mkdir dir="${unwar.dir}"/>
<unwar src="${dist}/lib/MyProject.war" dest="${unwar.dir}"/>
<!-- create a jar of webapp classes (required by yguard) for obfuscation -->
<jar destfile="${unwar.dir}/WEB-INF/lib/MyProject.jar" whenempty="fail">
<zipfileset dir="${unwar.dir}/WEB-INF/classes" excludes="*.xml,*.properties"/>
</jar>
<delete dir="${unwar.dir}/WEB-INF/classes/*" excludes="*.xml,*.properties"/>
<!-- create a fileset of internal libraries to be obfuscated -->
<fileset dir="${unwar.dir}/WEB-INF/lib" id="internal.lib.set">
<include name="MyProject.jar"/>
</fileset>
<!-- move the internal libraries to a temporary directory and make a fileset out of them -->
<tempfile property="obfuscation.dir" destDir="${java.io.tmpdir}" deleteonexit="yes"/>
<mkdir dir="${obfuscation.dir}"/>
<move todir="${obfuscation.dir}">
<fileset refid="internal.lib.set"/>
</move>
<!-- create a jar of web.xml (required by yguard) for obfuscation -->
<jar destfile="${obfuscation.dir}/web.xml.jar" whenempty="fail">
<zipfileset dir="${unwar.dir}/WEB-INF" includes="*.xml"/>
</jar>
<!--<delete file="${unwar.dir}/WEB-INF/web.xml"/> -->
<!-- make a fileset of all jars to be obfuscated -->
<fileset dir="${obfuscation.dir}" includes="*.jar" id="in-out.set"/>
<!-- make a fileset of the remaining libraries, these are not obfuscated -->
<path id="external.lib.path">
<fileset dir="${unwar.dir}/WEB-INF/lib" includes="*.jar"/>
</path>
<taskdef name="yguard"
classname="com.yworks.yguard.YGuardTask"
classpath="../ref/yguard.jar"/>
<yguard>
<inoutpairs>
<!-- these filesets are inputs to be obfuscated -->
<fileset refid="in-out.set"/>
</inoutpairs>
<externalclasses refid="external.lib.path"/> <!-- external libs, not obfuscated -->
<rename>
<adjust replaceContent="true">
<include name="web.xml"/> <!-- modified to reference the obfuscated Servlet -->
<include name="struts-config.xml"/>
<include name="*.hbm.xml"/>
</adjust>
<keep>
<!-- classes, packages, methods, and fields which should not obfuscated are specified here -->
</keep>
</rename>
</yguard>
<!-- move our newly obfuscated classes back into the lib area -->
<move todir="${unwar.dir}/WEB-INF/lib">
<fileset dir="${obfuscation.dir}" includes="*_obf.jar"/>
</move>
<!-- unjar the adjusted web.xml -->
<unzip dest="${unwar.dir}/WEB-INF/" src="${unwar.dir}/WEB-INF/lib/web.xml_obf.jar">
<patternset includes="*.xml"/>
</unzip>
<!-- <delete>
<fileset dir="${unwar.dir}/WEB-INF/lib" includes="web.xml*.jar"/>
</delete> -->
<!-- rebuild the war file -->
<war destfile="MyProject_obf.war" basedir="${unwar.dir}"/>
</project>
Use the same trick I used to encrypt the references in web.xml -- temporarily put the Hibernate .xml files into a jar. (See the section commented by "create a jar of web.xml (required by yguard) for obfuscation".)

Combine filesets using Ant

I have 2 different filesets defined in Ant as follows:
<fileset id="fileset1" dir="${classes.dir}">
</fileset>
<zipfileset id="fileset2" src="myArchive.zip" includes="**/*.class">
</zipfileset>
I want to create a third fileset which is the union of both the above filesets
<fileset id="merged">
</fileset>
Can someone tell me how to do this ? Is it even possible to do something like that ?
Thanks in advance!
One way to do this is with Ant resource collections, in particular a union.
<fileset id="fileset1" dir="${classes.dir}" />
<zipfileset id="fileset2" src="myArchive.zip" includes="**/*.class" />
<union id="onion">
<resources refid="fileset1" />
<resources refid="fileset2" />
</union>
Then you can refer to the 'onion' anywhere you might use a fileset, e.g.
<copy todir="dest">
<resources refid="onion" />
</copy>
I recommend using generic resources elements rather than filesets for maximum flexibility.
Try this: I think it should work, since <fileset> is an implicit <patternset>.
<fileset id="fileset1" dir="${classes.dir}">
</fileset>
<zipfileset id="fileset2" src="myArchive.zip" includes="**/*.class">
</zipfileset>
EDIT: odd. This perhaps?
<patternset id="merged">
<patternset refid="fileset1" />
<patternset refid="fileset2" />
</patternset>
problem with fileset is, that it requires a directory as a base upon it applies the patternset. Which means you have to find a common base directory that is shared by all filesets.
A <pathconvert> Task can take filesets via refid. You can put several filesets (e.g. from various build targets to assemble a compound set in a root/main target for a modular build environment):
<project name="root" basedir="." xmlns:if="ant:if" xmlns:unless="ant:unless">
<!--
it's important to take the xmlns:features in your project head
otherwhise this code won't work
-->
<target name="init">
<!-- set some common prerequisites -->
<property name="prerequisite.property.xyz" value="xyz" />
</target>
<target name="targetA" depends="init">
<fileset dir="${common.basedir}${file.separator}${targetA.subdir}" id="targetA.fileset">
<include name="**/*.html" />
</fileset>
<property name="targetA.fileset.exists" value="true" />
</target>
<target name="targetB" depends="init">
<fileset dir="${common.basedir}${file.separator}${targetB.subdir}" id="targetB.fileset">
<include name="**/*.java" />
</fileset>
<property name="targetB.fileset.exists" value="true" />
</target>
<target name="targetC" depends="init">
<fileset dir="${common.basedir}${file.separator}${targetC.subdir}" id="targetC.fileset">
<include name="**/*.class" />
</fileset>
<property name="targetC.fileset.exists" value="true" />
</target>
<target name="root" depends="init">
<pathconvert property="all.files.as.commaseparated.path" pathsep="," dirsep="/">
<fileset refid="targetA.fileset" if:true="${targetA.fileset.exists}" />
<fileset refid="targetB.fileset" if:true="${targetB.fileset.exists}" />
<fileset refid="targetC.fileset" if:true="${targetC.fileset.exists}" />
<map from="${common.basedir}/" to="" />
</pathconvert>
<!-- assemble new fileset from paths as comma separated property string -->
<fileset id="new.refid" dir="${common.basedir}" includes="${all.files.as.commaseparated.path}" />
</target>
</project>
This can be called via command line like:
ant targetA targetB targetC root
or
ant targetA root
Be aware that root is always the last target being called.

Resources