> 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!







Reply via email to