Typically, to make Ivy tasks available to an Ant build, you need to:
Add ivy.jar to ${ANT_HOME}/lib.
Add an xmlns:ivy="antlib:org.apache.ivy.ant" declaration to your build.xml's <project> element.
Add a <taskdef> declaration inside build.xml that reference's the ivy.jar's antlib.xml file where all other tasks are defined.
I'd like to accomplish all of the above except the first step (adding ivy.jar to ${ANT_HOME}/lib). I'd like to have ivy.jar living somewhere inside my project, say, at lib/buildtime/ivy.jar, and somehow reference lib/buildtime/ivy.jar as where Ivy is located.
Is this possible? If so, how? If not, why? Thanks in advance!
The taskdef (step 3) is not required if the ivy jar is located in a standard ANT library directory.
I would recommend including a special "bootstrap" target that will install the ivy jar. Once this is done all other dependencies (including 3rd party ANT tasks) can be downloaded by ivy as a build dependency.
Here is my default build file that demonstrates the concept:
<project name="demo" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="bootstrap" description="Install ivy">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.3.0/ivy-2.3.0.jar"/>
</target>
<target name="resolve" description="Use ivy to resolve classpaths">
<ivy:resolve/>
<ivy:report todir='build/ivy-reports' graph='false' xml='false'/>
<ivy:cachepath pathid="compile.path" conf="compile"/>
<ivy:cachepath pathid="test.path" conf="test"/>
</target>
<target name="clean" description="Cleanup build files">
<delete dir="build"/>
</target>
<target name="clean-all" depends="clean" description="Additionally purge ivy cache">
<ivy:cleancache/>
</target>
</project>
Notes:
The "bootstrap" target only needs to be run once on a new development environment. Once installed the ivy jar is available to all future ANT runs.
This example doesn't use "$ANT_HOME/lib" (which you may not have write permissions for). Instead it uses the lesser known "$HOME/.ant/lib" directory which serves the same purpose.
Related
I'm trying to integrate forbiddenapis check into my project. I've defined that:
<target name="forbidden-checks" depends="clean, runtime, test">
<ivy:cachepath organisation="de.thetaphi" module="forbiddenapis" revision="2.2" inline="true" pathid="classpath"/>
<taskdef uri="antlib:de.thetaphi.forbiddenapis" classpathref="classpath"/>
<forbiddenapis classpathref="all-lib-classpath" dir="${build.dir}" targetVersion="${javac.version}">
<bundledsignatures name="jdk-unsafe"/>
<bundledsignatures name="jdk-deprecated"/>
<bundledsignatures name="jdk-non-portable"/>
</forbiddenapis>
</target>
all-lib-classpath includes all files to be checked by forbiddenapis plugin. I think that forbiddenapis jar will go into ${build.dir}. However I get that error:
Problem: failed to create task or type forbiddenapis
Cause: The name is undefined.
Action: Check the spelling.
Action: Check that any custom tasks/types have been declared.
Action: Check that any <presetdef>/<macrodef> declarations have taken place.
The files don't get downloaded into your workspace. The cachpath task will do two things, download and cache jars into the default directory "~/.ivy2/cache" and then create an Ant path based on those cached jars.
Secondly, as #Denis Kurochkin pointed out, the task you're using apparently requires a namespace to be declared, not unusual with modern Ant tasks.
Finally I couldn't resist demonstrating how you can also configure your ANT build to install the ivy jar if it is missing, making your build even more stand-alone.
Example
build.xml
<project name="demo" default="forbidden-checks" xmlns:ivy="antlib:org.apache.ivy.ant" xmlns:fa="antlib:de.thetaphi.forbiddenapis">
<available classname="org.apache.ivy.Main" property="ivy.installed"/>
<target name="resolve" depends="install-ivy">
<ivy:cachepath pathid="classpath">
<dependency org="de.thetaphi" name="forbiddenapis" rev="2.2" />
</ivy:cachepath>
<ivy:cachepath pathid="all-lib-classpath">
<dependency .... />
<dependency .... />
<dependency .... />
</ivy:cachepath>
</target>
<target name="forbidden-checks" depends="resolve">
<taskdef uri="antlib:de.thetaphi.forbiddenapis" classpathref="classpath"/>
<fa:forbiddenapis classpathref="all-lib-classpath" dir="${build.dir}" targetVersion="${javac.version}">
<bundledsignatures name="jdk-unsafe"/>
<bundledsignatures name="jdk-deprecated"/>
<bundledsignatures name="jdk-non-portable"/>
</fa:forbiddenapis>
</target>
<target name="install-ivy" unless="ivy.installed">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.4.0/ivy-2.4.0.jar"/>
<fail message="Ivy has been installed. Run the build again"/>
</target>
</project>
You need to declare namespace for forbiddenapis task from Ivy:
<project xmlns:ivy="antlib:org.apache.ivy.ant" xmlns:fa="antlib:de.thetaphi.forbiddenapis">
...
<fa:forbiddenapis ... >
Or declare task name explicitly:
<taskdef name="forbiddenapis"
classname="de.thetaphi.forbiddenapis.ant.AntTask"
classpath="path/to/forbiddenapis.jar"/>
Anyway look at the documentation https://github.com/policeman-tools/forbidden-apis/wiki/AntUsage
I have create RESTful web service based on the JAX-RS and used Jersey embedded web server. My ant script compiles code successfully while it gives me error ClassNotFoundException when I run my main class. So after doing research I came up with solution & here it goes java build ant file with external jar files . What I did was created a bundled jar file try to execute that & it works perfectly fine. I want to know the reason behind :
why this solution works ?
Why I should combine all jar file ?
Is it similar to war file which we create following J2EE architecture otherwise war will not be extracted by server ( say TOMCAT ) & in my case jar file for Jersey embedded HTTP server?
EDIT:
Here is my ant build.xml file
<property name="lib.dir" value="${user.dir}/lib"/>
<property name="build.dir" value="${user.dir}/build"/>
<property name="build.lib.dir" value="${build.dir}/lib"/>
<property name="build.classes.dir" value="${build.dir}/classes"/>
<property name="src.dir" value="${user.dir}/src/main/java"/>
<property name="main.class" value="com.assignment.ConsoleServer"/>
<path id="classpath">
<fileset dir="${lib.dir}" includes="**/*.jar"/>
</path>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
<target name="init" depends="clean">
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.classes.dir}"/>
</target>
<target name="copy_jars" depends="init" >
<copy todir="${build.lib.dir}" >
<fileset dir="${lib.dir}">
<include name="**/*.jar" />
</fileset>
</copy>
</target>
<target name="compile" depends="copy_jars">
<javac srcdir="${src.dir}" destdir="${build.classes.dir}" classpathref="classpath" includeantruntime="false"/>
</target>
<target name="jar" depends="compile">
<jar destfile="${build.dir}/${ant.project.name}.jar" basedir="${build.classes.dir}">
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
</manifest>
<zipgroupfileset dir="${lib.dir}" includes="*.jar"/>
</jar>
</target>
<target name="run" depends="jar">
<java fork="true" classname="${main.class}">
<classpath>
<path refid="classpath"/>
<path location="${build.dir}/${ant.project.name}.jar"/>
</classpath>
</java>
</target>
Here is my folder structure
P.S. I am not java expert so pardon me if this question is stupid.
Why this solution works?
In your particular case, you probably didn't include all of the necessary dependencies in your deployment in your previous. (It is not clear from your question how you were originally doing the deployment.)
Now you have put all of the application and dependent class files, etc into one JAR file, and presumably you are deploying / running that file. It works because now it has everything that it needs to run ... which it didn't before.
Why I should combine all jar file?
In your case I suspect that it was not strictly necessary. There was probably a way to "deploy" all of the dependencies without combining them into a single JAR file.
However, there is one case where a "uber-jar" has advantages. That is when the JAR is intended to be an "executable" JAR, and you want to be able to distribute / install it as a single file. (And executable JAR
file can refer to external JARs, etc, but the way that you have to do
it is "fragile".)
Is it similar to war file ... ?
Sort of, though a WAR file contains JAR files ... and typically other kinds of resources that the web-container understands.
The solution works because you packed all you service classes and depending libraries in one jar. That jar and everything inside will be in the class path and visible to your execution virtual machines class loader.
If you leave your depending libraries out your Jersey Web server needs to have them on it's class path, then you wouldn't get ClassNotFoundExcpetion
You shouldn't pack web application in single jar. You should crate war file where you dependencies will be placed inside WEB-INF/lib. You would easily then deploy that war on any application server. Switching to Maven instead of Ant can help a lot.
EDIT: After you added more details to description and ant
If you don't want to use fat-jar you can either
modify your antjava task to specify classpath that will reference
all external libraries (basically telling ant how to build
-classpath parameter for java -jar command
even better, modify your javac ant task by making complete Manifest file that specifies Class-Path correctly, take a better
look at the solution (at the bottom) of the answer you linked (java build ant file with external jar files)
For completness reference on Manifest here
In the documentation to socket.io-java by nkzawa is mentioned that to add ant dependency should be used next snippet:
<dependency org="com.github.nkzawa" name="socket.io-client" rev="0.1.1-SNAPSHOT">
<artifact name="socket.io-client" type="jar" />
</dependency>
In which file and how I should include it? How I should compile my application after that?
In order to manage dependency with ant you'll need to use Ivy
But I agree with Bart Kiers - switch to Gradle, especially as you're already using IDEA.
The socket.io-client documentation is misleading. ANT has an extension called ivy for performing dependency management, but it is not bundled by default.
Once setup you can list your project's dependencies in an ivy.xml file or within your build.xml using the cachepath task:
<ivy:cachepath pathid="compile.path">
<dependency org="com.github.nkzawa" name="socket.io-client" rev="0.1.1" />
</ivy:cachepath>
I have included a more complete example below. It details how to configure your ANT build to automatically setup ivy.
I am not an android programmer, so not able to recommend the best build tool. What I can say is that adding dependency management to your build process is a very good idea. ANT pre-dates more modern tools like Maven and Gradle that have this feature baked in.
Example
build.xml
<project name="demo" default="build" xmlns:ivy="antlib:org.apache.ivy.ant">
<!--
================
Build properties
================
-->
<available classname="org.apache.ivy.Main" property="ivy.installed"/>
<!--
===========
Build setup
===========
-->
<target name="install-ivy" description="Install ivy" unless="ivy.installed">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/ivy.jar" src="http://search.maven.org/remotecontent?filepath=org/apache/ivy/ivy/2.3.0/ivy-2.3.0.jar"/>
<fail message="Ivy has been installed. Run the build again"/>
</target>
<target name="resolve" depends="install-ivy" description="Use ivy to resolve classpaths">
<ivy:cachepath pathid="compile.path">
<dependency org="com.github.nkzawa" name="socket.io-client" rev="0.1.1" />
</ivy:cachepath>
</target>
<!--
===============
Compile targets
===============
-->
<target name="build" depends="resolve" description="Project build logic goes here">
<javac .... classpathref="compile.path">
</javac>
...
</target>
<!--
===============
Clean-up targets
===============
-->
<target name="clean" description="Cleanup build files">
<delete dir="build"/>
</target>
<target name="clean-all" depends="clean" description="Additionally purge ivy cache">
<ivy:cleancache/>
</target>
</project>
I know how to create javadocs for my source file in Apache Ant Build.
<target name="doc" description="generate documentation">
<delete dir="${doc.dir}"/>
<mkdir dir="${doc.dir}"/>
<javadoc sourcepath="${source.dir}" destdir="${doc.dir}"/>
</target>
But I don't know how to create them in Apache Ivy.
Could some one show me a sample example ?
Apache Ivy is a dependency management library for use with (not a replacement for) Apache Ant. Therefore, you will use the same <javadoc> task as always.
Apache Ivy is a dependency manager that works with Ant (a build manager). Apache Ivy is usually (or possible always?) used with Ant to handle builds. Since javadoc creation is a build task not a dependency task, it wouldn't make sense to generate javadocs using Ivy.
It looks like you're going around in a circle here. Ivy works with Ant. You still have a build.xml file that you use for your builds. The ivy.xml file simply contains a list of the third-party jars your project needs in order to build. Thus, the direct answer to your question would be:
Put the following in your build.xml:
<target name="doc" description="generate documentation">
<delete dir="${doc.dir}"/>
<mkdir dir="${doc.dir}"/>
<javadoc sourcepath="${source.dir}" destdir="${doc.dir}"/>
</target>
When you use Ivy, you still use Ant. And, you still have a build.xml file. And, you still write compose your build with various Ant tasks.
Download this project. It's a simple build that contains three class files and a build.xml file. You will notice there's a jar directory with the following two jars:
commons-logging-1.1.1.jar
spring.jar
If you look at lines 36 to 40 of the build.xml file, the project is creating a compile classpath like this:
<path id="java">
<fileset file="jar/spring.jar"/>
<fileset file="jar/commons-logging-1.1.1.jar"/>
</path>
So, when he compiles, he does this:
<javac destdir="bin">
<src path="${src}"/>
<classpath refid="java"/>
</javac>
Now, let's look at how this may change with Ivy. In Ivy, I create a ivy.xml file that contains a description of what jars I need. However, I only have to specify classes I use directly. In this case, I only need the spring.jar. Here's my ivy.xml:
<ivy-module version="1.0>
<info organisation="com.seantheflexguy"
name="ContextExample"
revision="1.0"/>
<configurations>
<conf="default" visibility="public"/>
<conf="compile" visibility="public"/>
</configurations>
<dependencies>
<dependency org="org.springframework" name="spring"
rev="2.0.4" conf="compile->default"/>
</dependencies>
</ivy-module>
Now, instead, of using the jars in the jar directory, I'll have Ivy construct the classpath:
<ivy:resolve/>
<ivy:cachepath pathid="java"/>
<javac destdir="bin">
<src path="${src}"/>
<classpath refid="java"/>
</javac>
Notice instead of using the <path> task to create a classpath, I use two Ant tasks that Ivy uses. The <ivy:resolve/> looks at my ivy.xml and resolves my dependencies on the jars I request. These jars will be downloaded into my $HOME/.ivy2/cache directory.
The <ivy:cachepath> task creates a classpath I'm calling the classpath java because that's what it was previously called.
With those two Ivy tasks, I've created a classpath that I can use with the <javac> task. In fact, I'm not even bothering to change the <javac> task.
So, in Ivy:
I still need my build.xml. It's how I define the various build tasks I need to do. In fact, Ivy defines even more Ant tasks I need in my build.xml file.
The ivy.xml file simply defines my jar dependencies. When I implement Ivy in this project, I can delete the jar directory.
Does this help you understand how Ivy works?
I currently have ANT_HOME located at /home/<myuser>/ant/1.8.4/ant-1.8.4.
I just downloaded the Apache Ivy tarball that includes its dependencies. I extracted it to /home/<myuser>/ivy/2.3.0-rc1/ivy-2.3.0-rc1.
I then copied /home/<myuser>/ivy/2.3.0-rc1/ivy-2.3.0-rc1/lib/*.jar to ANT_HOME/lib. If my understanding of how Ant works with plugins/extensions is correct, then Ant should now be able to access all of Ivy's tasks at runtime.
My next question is, how do I define Ivy tasks inside my Ant buildfile? Say I want to use ivy-retrieve, ivy-resolve and ivy-publish tasks. What are all the configurations I need to do (in the XML) to get these tasks working when I run my Ant build from the command-line (I will not be building through the Ant-Eclipse plugin). Thanks in advance!
First, you have to define a <taskdef> to point to the Ivy tasks.
<property environment="env"/>
<property name="ivy.home" value="${env_IVY_HOME}"/>
<taskdef resource="org/apache/ivy/ant/antlib.xml">
<classpath>
<fileset dir="${ivy.home}">
<include name="*.jar"/>
</fileset>
</classpath>
</taskdef>
That will give you access to the Ivy tasks. You'd use these tasks like this:
<cachepath pathid="main.classpath" conf="compile"/>
The problem is that your Ivy tasks names might clash with other Ant tasks. For example, there's an Ivy task <report>. To solve this, you can create an Ivy namespace. To do that, you put a reference in your namespace in the <project> entity like this:
<project name="my.proj" default="package" basedir="."
xmlns:ivy="antlib:org.apache.ivy.ant"/>
Now, when you define the Ivy tasks, you can use that antlib:org.apache.ivy.ant reference to your ivy namespace. Same taskdef as before, but with a uri field:
<property environment="env"/>
<property name="ivy.home" value="${env_IVY_HOME}"/>
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant">
<classpath>
<fileset dir="${ivy.home}">
<include name="*.jar"/>
</fileset>
</classpath>
</taskdef>
By the way, there's nothing special about that uri. I could have done this:
<project name="my.proj" default="package" basename="."
xmlns:ivy="pastrami:with.mustard">
[...]
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="pastrami:with.mustard">
<classpath>
<fileset dir="${ivy.home}">
<include name="*.jar"/>
</fileset>
</classpath>
</taskdef>
The point is now you can prefix your task names with ivy:. Instead of this:
<cachepath pathid="main.classpath" conf="compile"/>
You can now do this:
<ivy:cachepath pathid="main.classpath" conf="compile"/>
And that's how you gain access to your Ivy Ant tasks.
Now, you have access to your Ivy Ant tasks, you need to define an ivysettings.xml file and use the <ivy:settings/> task to point there:
<ivy:settings file="${ivy.home}/ivysettings.xml"/>
There is a default ivysettings.xml file embedded in Ivy that will point you to the world wide Maven repository system. If you don't have a company wide Maven repository, then you can use the default ivysettings.xml file:
<ivy:settings/>
That's pretty simple.
Once you've done that, you need to read in and resolve your ivy.xml file which usually sits in the root of your project in the same directory as your build.xml file.
Basically, your ivy.xml file contains references to the third party jars you want to bring into your project. For example:
<dependencies>
<dependency org="log4j" name="log4j" rev="1.2.17" conf="compile->default"/>
<dependency org="junit" name="junit" rev="4.10" conf="test->default"/>
</dependencies>
What this is saying is that I need the log4j.jar (revision 1.2.17) for compilation (and for compiling tests too) and I need junit.jar (revision.4.10) for compilation of my test code.
The compile->default is a mapping of my compile configuration to Maven's default configuration (which says I just want the Jar and any other jars that it might depend upon.
Where's does my compile configuration come from? I define it in my ivy.xml. There are ten standard configurations. This also goes into your ivy.xml file:
<configurations>
<conf name="default" visibility="public" description="runtime dependencies and master artifact can be used with this conf" extends="runtime,master"/>
<conf name="master" visibility="public" description="contains only the artifact published by this module itself, with no transitive dependencies"/>
<conf name="compile" visibility="public" description="this is the default scope, used if none is specified. Compile dependencies are available in all classpaths."/>
<conf name="provided" visibility="public" description="this is much like compile, but indicates you expect the JDK or a container to provide it. It is only available on the compilation classpath, and is not transitive."/>
<conf name="runtime" visibility="public" description="this scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath." extends="compile"/>
<conf name="test" visibility="private" description="this scope indicates that the dependency is not required for normal use of the application, and is only available for the test compilation and execution phases." extends="runtime"/>
<conf name="system" visibility="public" description="this scope is similar to provided except that you have to provide the JAR which contains it explicitly. The artifact is always available and is not looked up in a repository."/>
<conf name="sources" visibility="public" description="this configuration contains the source artifact of this module, if any."/>
<conf name="javadoc" visibility="public" description="this configuration contains the javadoc artifact of this module, if any."/>
<conf name="optional" visibility="public" description="contains all optional dependencies"/>
</configurations>
You can use any configuration name you want, but these map to the default Maven configurations and are widely used.
Once you have your ivy.xml file defined, you can use <ivy.resolve> to resolve your dependencies:
<ivy:resolve/>
So, we have the following:
How to use <taskdef> in your build.xml to incorporate the Ivy Ant tasks into your build.
How to use the Ivy Ant task <ivy:settings> to configure Ivy.
How to use <ivy:resolve/> to read in your ivy.xml file and resolve your third party jar dependencies.
Now, you probably want to actually use those jar files. There are three ways to do this:
<ivy:cachepath pathid="main.classpath" conf="compile"/>
The <ivy:cachepath/> task will create a classpath (in this case called main.classpath) that points to the jars you have in your ivy.xml file's compile configuration. This is used most of the time.
If you need a fileset, you can use this:
<ivy:cachefileset setid="compile.fileset" conf="compile"/>
In this case, it will create a fileset with a refid of compile.fileset.
Sometimes you have to bring the jars into your project. For example, if you create a war or ear file, you want to enclose your jars. In that case, you can use this:
<property name="lib.dir" value="${target.dir}/lib"/>
<ivy:retrieve pattern="${lib.dir}/[artifact].[ext]"
conf="runtime"/>
That will fetch your jars into the ${lib.dir} directory, so you can include them in wars or ears.
Sorry for the long answer, but there are a lot of steps to cover. I highly recommend Manning's book Ant in Action which has a whole chapter on Ivy.
David gave a very fine answer, but I'd like to point out that the taskdef is not required.
Provided the ivy.jar is in the expected location the namespace declaration at the top of the ANT file is enough:
<project ..... xmlns:ivy="antlib:org.apache.ivy.ant">
For more detail I'd recommend reading about how ANT libs work.
The following answer provides some more "setting up ivy" advice:
Ivy fails to resolve a dependency, unable to find cause