ant-ivy-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Davide Baroncelli <baronce...@yahoo.com>
Subject Re: ivy and jars in war or ear
Date Fri, 20 Apr 2007 16:25:13 GMT
> I have a web application with multiple jars.  Some jars are included directly in the wars,
but some are placed in the ear itself.
> I would like to find an elegant solution using ivy and ant to : - package the wars with
the correct libs - generate the classpath to be placed in the MANIFEST.MF of the wars- package
the ear with the correct libs

Hi Gilles, what we do have here is a custom build system based on ivy + ant which does some
of the things you want. 

Our ivy files define different configurations for the dependencies only needed when building,
and the ones needed at runtime. For a normal webapp we normally have three configurations:
 - build
 - prod
 - stage, 
as in 
    <configurations>
        <conf name="prod"/>
        <conf name="stage" extends="prod"/>
        <conf name="build" visibility="private"/>
    </configurations>
and we then define dependencies like this:
<dependency org="jaspersoft" name="jasperreports" rev="latest.integration" conf="prod,build->default"/>
or this:
<dependency name="servlet-api" rev="latest.integration" conf="build->default"/> <!--
per la compilazione delle classi che dipendono dai servlet -->

when we build, we build against one of the "runtime" configurations (either prod or stage
in this case), but also resolve the "build time" configuration. For this our compilation target
depends on a "resolve" target done like this (note the "ivy-resolve" line):

    <target name="resolve" unless="disable.library.resolution" depends="version.define"
description="retrieves dependencies with ivy">
        <property name="ivy.revision" value="${version.number.full}"/>
        <ivy-resolve conf="${target.deployment.name},build"/>
        <ivy-retrieve validate="false" pattern="${dir.lib}/[conf]/[module]/[artifact].[ext]"/>
    </target>

with "target.deployment.name" being "prod" or "stage".

So if we are building a "prod" configuration we have the "build time" libraries in the ${dir.lib}/build/[module]
dir and the "runtime" ones in the ${dir.lib}/prod/[module]. For compilation we then use a
classpath like this:

    <path id="build.classpath">
        <fileset dir="${dir.lib}/build">
            <include name="**/*.jar"/>
        </fileset>
    </path>

and this resolves the part regarding compilation.

Now, for what concerns webapps, ears or standalone applications, we do something like this.

1) for wars we have a preparation target doing this (among other things):
        <copy todir="${dir.build.war}/WEB-INF/lib">
            <fileset refid="${fileset.war.runtime.libs.name}"/>
            <mapper type="flatten"/>
        </copy>

and that fileset is defined like this:

    <fileset id="fileset.war.runtime.libs" dir="${dir.lib}/${target.deployment.name}">
        <include name="**/*.jar"/>
    </fileset>

(with "target.deployment.name" being "prod", in this case).

2) for standalone applications we have a "jar preparation" target doing this:
        <manifestclasspath property="jar.package.manifestclasspath">
            <classpath refid="runtime.classpath"/>
        </manifestclasspath>
        <touch file="${jar.package.manifest}" mkdirs="true"/>
        <jar manifest="${jar.package.manifest}"
             destfile="${dir.build.packages}/${file.name.jar}"
             basedir="${dir.build.jar}">
            <manifest>
                <attribute name="Class-Path" value="${jar.package.manifestclasspath}"/>
                <attribute name="Specification-Title" value="${app.name}"/>
                <attribute name="Specification-Version" value="${version.number.full}"/>
                <attribute name="Specification-Vendor" value="${name.enterprise}"/>
                <attribute name="Implementation-Title" value="${app.name}"/>
                <attribute name="Implementation-Version" value="${version.number.full}
${date.formatted}"/>
                <attribute name="Implementation-Vendor" value="${name.enterprise}"/>
            </manifest>
        </jar>

"manifestclasspath" is a target taken from hivemind (I've found it on the web) and building
a "classpath string" suitable for insertion in a MANIFEST.MF starting from the libraries in
the "runtime.classpath"... which of course includes the libraries we have resolved through
ivy in the "prod" configuration:

    <path id="runtime.classpath">
        <fileset refid="fileset.libs.runtime"/>
    </path>

    <fileset id="fileset.libs.runtime" dir="${dir.lib}/${target.deployment.name}">
        <include name="**/*.jar"/>
    </fileset>

we then build a distribution zip where the libraries are packaged along with our application's
jar, which has the manifest above in its META-INF directory.

3) for now we have a single ear, and it only includes MDBs, so no web applications inside.
Should we have to do it we would probably:
 - manage the web applications as separate ivy modules, and build them as above
 - resolve the wars through ivy and include them in the ear,
 - manage the ear libraries as we are doing now:

- build the ejb-jar as above (i.e. via the manifestclasspath), 
- include the runtime libraries:

    <target name="ear.prepare.dir.include.libraries" if="no.web.module">
        <antcall target="jar.package"/>
        <echo level="info" message="copying libraries into ear preparation directory"/>
        <copy todir="${dir.build.ear}">
            <fileset file="${dir.build.packages}/${file.name.jar}"/>
        </copy>
        <copy todir="${dir.build.ear}">
            <fileset refid="fileset.libs.runtime"/>
            <mapper type="flatten"/>
        </copy>
    </target>

I hope this is helpful for you!








Mime
View raw message