Thanks a lot, I didn't knew the task manifestclasspath. This task
will simplify the script that I have now, based on properties. By the
way, I have seen it is now in ant 1.7.
But still, there is one piece missing. When we have ears and wars, I
need a flexible technique to define which jars are in the wars, and
which jars are in the ear.
I think that if I move to ant 1.7, I will probably be able to use file
selectors to do that.
Gilles
2007/4/20, Davide Baroncelli <[EMAIL PROTECTED]>:
> 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!
--
Gilles SCOKART