Running ant-target to send a mail via java - java

I´m a pretty new to ant and I´m trying to send an email within an ant-target which is called by Java. I´m using the Netbeans IDE.
Ant:
<project name="AntTargets" default="main" basedir=".">
<description>Builds, tests, and runs the project AntTargets.</description>
<import file="nbproject/build-impl.xml"/>
<target name="run" depends="jar">
<java classpathref="AntTargets.classpath" fork="true" classname="Client" />
</target>
<target name="main">
<echo message="******************[MAIN]******************"/>
<property file="nbproject/build.properties"/>
<property name="to" value="${builder}" />
<property name="from" value="${builder}" />
<property name="server" value="${server}" />
<property name="port" value="${port}" />
<mail mailhost="${server}" mailport="${port}" subject="Test build">
<from address="${from}"/>
<replyto address="${to}"/>
<to address="test#domain.de"/>
<message>The build has been completed</message>
</mail>
<echo message="Email to ${to} from ${from} has been sent using the server ${server} on port ${port}."/>
</target>
</project>
Java:
import java.io.File;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
public class AntTargets {
public static void main(String[] args) {
//get new file
File buildFile = new File("build.xml");
//create new project
Project p = new Project();
p.setUserProperty("ant.file", buildFile.getAbsolutePath());
p.init();
//initialize helper
ProjectHelper helper = ProjectHelper.getProjectHelper();
p.addReference("ant.projectHelper", helper);
//parse and execute
helper.parse(p, buildFile);
p.executeTarget(p.getDefaultTarget());
}
}
When I execute the ant part directly, the properties file is found, read and works overall but the mail-part gives me this error:
Failed to send email: javax.mail.internet.MimeMessage
build.xml:16:
java.lang.ClassNotFoundException: javax.mail.internet.MimeMessage
When I call it with java I get:
Reference AntTargets.classpath not found.
BUILD FAILED (total time: 0 seconds)
I would greatly appreciate any help and tip overall.

The issue is Ant doesn't know what AntTargets.classpath is.
You must define a classpath variable and give it id="AntTargets.classpath. In this path variable you should define the physical locations of the libraries you use. (You should look to creating path variables to reduce redundancies in code, particularly when you want to use the same path in different ant targets.)
Here's an example: Let's say that your project requires the Gson library at runtime.
First, create a path for that library. Let's assume you have your libraries in a lib directory.
<path id="library.gson-2.8.0.classpath">
<pathelement location="${basedir}/lib/gson-2.8.0.jar"/>
</path>
Do the same for other dependencies as well.
Next, create a path that will contain all these dependencies, so you can refer to all the dependencies as one variable. This will be your AntTargets.classpath
<path id="AntTargets.classpath">
<path refid="library.gson-2.8.0.classpath"/>
...... <!-- Add paths for your other dependencies by refid here-->
</path>
Now, when you use AntTargets.classpath Ant will know what that is and use it to run your jar.
I notice that you use this in the run target, so if you're trying to run the Client class from your own jar, include that in your classpath as well.
Also keep in mind that "Client" may not be enough information--you must provide the fully qualifying name of the class, including package names, e.g. something like "com.package.Client".
EDIT:
I just noticed the exception you're getting from running directly with Ant. You need to include the javax.mail library in this path variable we create. That should resolve that issue.
EDIT 2:
I seem to have misunderstood. I thought that your ant task was trying to call your Java program which would send the mail, but it couldn't since it didn't know where the javax.mail.jar is, and so I instructed you to add it to the classpath.
But what you want to do is:
Use the Ant mail task to send a mail.
And in the Java you want to read the build file and execute the target that sends the mail.
Here's some information on that: mail is an Ant Task that requires the javax.mail library, if you want to use certain arguments. Looking at a few questions like this and this, I see that you should put ${ANT_HOME}/lib, i.e. where your ant.jar is, so that Ant's classloader can pick it up and use it. In that case, if my assumption about what you want is correct, then you should be able to get rid of AntTargets.classpath, because really, your build file doesn't need to know how you call any of it's targets.

Related

Migrate an ant script to Maven3

I'm migrating a maven 1 project to maven 3. The job is almost done actually with a missing task, What I need is to get all dependency names from pom file and write them to a configuration file as one string, the job is done like below in the maven.xml, check the last 5 lines where it writes the names to a file called wrapper.conf.
How can I achive this with Maven3? Is there a maven plugin I can use for this or I need to use ant script within my pom.xml?
<goal name="service">
<mkdir dir="${maven.build.dir}/grid" />
<ant:copy todir="${maven.build.dir}/grid">
<fileset dir="resources/javaservicewrapper" />
</ant:copy>
<j:forEach var="lib" items="${pom.artifacts}">
<j:set var="dep" value="${lib.dependency}"/>
<j:if test="${dep.getProperty('service.bundle')=='true'}">
<ant:copy failonerror="true" todir="${maven.build.dir}/grid/lib">
<fileset dir="${maven.repo.local}/${dep.groupId}/jars">
<include name="${dep.artifactId}-${dep.version}.${dep.type}"/>
<j:set var="SERVCP" value="../lib/${dep.artifactId}-${dep.version}.${dep.type}:${SERVCP}" />
</fileset>
</ant:copy>
</j:if>
</j:forEach>
<attainGoal name="jar" />
<ant:copy file="target/${maven.final.name}.jar" tofile="${maven.build.dir}/grid/lib/grid.jar" />
<j:set var="SERVCP" value="${SERVCP}../lib/gridcache.jar" />
<ant:copy todir="${maven.build.dir}/gridcache/conf" file="resources/javaservicewrapper/conf/wrapper.conf" overwrite="true">
<filterset begintoken="#" endtoken="#">
<filter token="service.classpath" value="${SERVCP}"/>
</filterset>
</ant:copy>
</goal>
EDIT : The solution using build-classpath worked well but I had other problems specific to using Javaservicewrapper. So best solution I found was creating whole the script/config file by appassembler-maven-plugin and let maven-assembly plugin to copy it to the conf folder
If you have the need to create a JSW (wrapper.conf) the simplest solution would be to use the appassembler-maven-plugin which can create such files.
Have a look at the build-classpath goal of the Maven Depency Plugin. You can fast check the result on the command line:
mvn dependency:build-classpath
You can change the path to the dependeny files using the 'prefix' (mdep.prefix) property
mvn -Dmdep.prefix=myLibFolder dependency:build-classpath
You will find much more configuration parameters in the documentation, e.g. the outputFile parameter ;-)

Set target or property to a sub project with Ant/Eclipse on Android

I need to switch to Ant, I managed to compile and install the Android apk file but I didn't manage to transmit the property or a specific target to the referenced library.
My code on the build.xml in the referenced library :
<echo message="Property value is '${foo.dist}'" />
<target name="AfficherVersionAnt">
<echo message="Version d'Ant utilisée : ${ant.version}"/>
</target>
The same code is functional when I put it in the starting package.
<property name="foo.dist" value="true"/>
(and for the target, if I launch with the target)
My ant configuration was generated with :
"C:\Program Files (x86)\Android\android-sdk\tools\android" update project -p "D:\project"
And I don't see where I could set a link
Can someone help me ? I would need global variables or something like this
In eclipse you can define your own variables for ant
Go to external tools configuration > your profile > environnement, and define new environnement variable.

Programmatically executing ANT script in Java

I've built a swing gui in eclipse that is supposed to run a bunch of code previously developed, part of which involves running ant to build the code. When I run the any script outside of the GUI (in the original project) the ant executes correctly and builds the project. However when I try and run ant programmatically it throws errors that look like the project doesn't have the necessary .jars. The code, top of the build.xml, and errors are listed below.
Code Block
File buildFile = new File("lib\\ePlay\\build.xml");
Project p = new Project();
p.setUserProperty("ant.file", buildFile.getAbsolutePath());
DefaultLogger consoleLogger = new DefaultLogger();
consoleLogger.setErrorPrintStream(System.err);
consoleLogger.setOutputPrintStream(System.out);
consoleLogger.setMessageOutputLevel(Project.MSG_INFO);
p.addBuildListener(consoleLogger);
try {
p.fireBuildStarted();
p.init();
ProjectHelper helper = ProjectHelper.getProjectHelper();
p.addReference("ant.projectHelper", helper);
helper.parse(p, buildFile);
p.executeTarget(p.getDefaultTarget());
p.fireBuildFinished(null);
} catch (BuildException e) {
p.fireBuildFinished(e);
}
Build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="EPlay" xmlns:ivy="antlib:org.apache.ivy.ant" default="resolve">
<dirname file="${ant.file}" property="ant.dir" />
<property name="scm.user" value="scmrel"/>
<property name="scm.user.key" value="/.ssh/scmrel/id_rsa"/>
<property name="ivy.jar" value="ivy-2.0.0.jar" />
<property name="ivy.settings.dir" value="${ant.dir}/ivysettings" />
<property name="VERSION" value="LATEST" />
<property name="tasks.dir" value="${ant.dir}/.tasks" />
<property name="deploy.dir" value="${ant.dir}/deploy" />
...
<!-- retrieve the dependencies using Ivy -->
<target name="resolve" depends="_loadantcontrib,_getivy" description=" retrieve the dependencies with Ivy">
<ivy:settings file="${ivy.settings.dir}/ivysettings.xml" />
<ivy:resolve file="${ant.dir}/ivy.xml" transitive="false" />
<ivy:retrieve pattern="${deploy.dir}/[conf]/[artifact].[ext]"/>
</target>
And the error
resolve:
BUILD FAILED
H:\eclipse\CLDeploySwing\lib\ePlay\build.xml:66: Problem: failed to create task or type antlib:org.apache.ivy.ant:settings
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.
No types or tasks have been defined in this namespace yet
This appears to be an antlib declaration.
Action: Check that the implementing library exists in one of:
-ANT_HOME\lib
-the IDE Ant configuration dialogs
Total time: 0 seconds
I've looked through my ant installation and it appears everything is there. Like I said, the original project builds successfully if build.xml is run outside of this application.
I would suggest that this is causde because your java program does not have the same classpath, where it is running, as does the normal ant build - and thus the ANT_HOME isn't the right one.
You can make sure that this is correct by passing the right enviornmental variables into the JVM, or simply a call to System.getProperty("ANT_HOME"), to see where your ANT_HOME actually is residing.
I think ${basedir} for your project is not properly calculated.
Add this line to your build.xml
<echo message="basedir='${basedir}'/>
Looking at this line
File buildFile = new File("lib\\ePlay\\build.xml");
It may be that it's 2 levels up ( I know the documentation says that it should be a parent directory of build.xml, but you are not running from the command line ).
rather than load the ivy library using the new method of using the namespace in the project declaration go old school on it.
<path id="ivy.lib.path">
<fileset dir="path/to/dir/with/ivy/jar" includes="*.jar"/>
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/>
I am doing something in Gradle that requires this
ant.taskdef(name: 'ivy-retrieve', classname: 'org.apache.ivy.ant.IvyRetrieve', classpath: '...path to ivy jar.../ivy-2.2.0.jar')
which in ant would be something like
<taskdef name="ivy-retrieve" classname="org.apache.ivy.ant.IvyRetrieve"/>
I know it's more klunky and simply not as nice as including the namespace declaration but it does remove some of the confusion regarding which libraries on which classpath are being loaded.

Java Ant - how to pass a ProGuard task arguments and use them inside a configuration file?

I have this in my build.xml:
<target depends="build-jar" name="proguard">
<taskdef resource="proguard/ant/task.properties" classpath="tools/proguard4.6/lib/proguard.jar" />
<proguard configuration="ant/proguard.conf" />
</target>
It works fine.
Inside the configuration file (i.e "ant/proguard.conf") I'm trying to access properties defined in this build.xml file but I'm always getting this kind of error:
Value of system property 'jar.final_name' is undefined in '<jar.final_name>' in line 1 of file '.......\ant\proguard.conf'
The error is clear. Question is how I do what I'm trying to?
If I'd do it the "Embedded ProGuard configuration options" way I could use these properties like any other property in build.xml, but I'm trying to keep the files separate.
How do I do that then?
By default, Ant doesn't provide a way to set java system properties for its tasks. You can only specify -D options in the ANT_OPTS system variable when starting Ant itself.
I'll consider supporting the use of Ant properties in referenced ProGuard configurations (being the developer of ProGuard).
For the time being, an acceptable solution might be to specify input and output jars in Ant's XML-style:
<proguard configuration="ant/proguard.conf">
<injar name="${injar}" />
<outjar name="${outjar}" />
<libraryjar name="${java.home}/lib/rt.jar" />
</proguard>
This part of the configuration is more closely tied to the Ant script anyway.

Is there a way to generalize an Apache ANT target?

We have an Apache ANT script to build our application, then check in the resulting JAR file into version control (VSS in this case). However, now we have a change that requires us to build 2 JAR files for this project, then check both into VSS.
The current target that checks the original JAR file into VSS discovers the name of the JAR file through some property. Is there an easy way to "generalize" this target so that I can reuse it to check in a JAR file with any name? In a normal language this would obviously call for a function parameter but, to my knowledge, there really isn't an equivalent concept in ANT.
I would suggest to work with macros over subant/antcall because the main advantage I found with macros is that you're in complete control over the properties that are passed to the macro (especially if you want to add new properties).
You simply refactor your Ant script starting with your target:
<target name="vss.check">
<vssadd localpath="D:\build\build.00012.zip"
comment="Added by automatic build"/>
</target>
creating a macro (notice the copy/paste and replacement with the #{file}):
<macrodef name="private-vssadd">
<attribute name="file"/>
<sequential>
<vssadd localpath="#{file}"
comment="Added by automatic build"/>
</sequential>
</macrodef>
and invoke the macros with your files:
<target name="vss.check">
<private-vssadd file="D:\build\File1.zip"/>
<private-vssadd file="D:\build\File2.zip"/>
</target>
Refactoring, "the Ant way"
It is generally considered a bad idea to version control your binaries and I do not recommend doing so. But if you absolutely have to, you can use antcall combined with param to pass parameters and call a target.
<antcall target="reusable">
<param name="some.variable" value="var1"/>
</antcall>
<target name="reusable">
<!-- Do something with ${some.variable} -->
</target>
You can find more information about the antcall task here.
Take a look at Ant macros. They allow you to define reusable "routines" for Ant builds. You can find an example here (item 15).
Also check out the subant task, which lets you call the same target on multiple build files:
<project name="subant" default="subant1">
<property name="build.dir" value="subant.build"/>
<target name="subant1">
<subant target="">
<property name="build.dir" value="subant1.build"/>
<property name="not.overloaded" value="not.overloaded"/>
<fileset dir="." includes="*/build.xml"/>
</subant>
</target>
</project>
You can use Gant to script your build with groovy to do what you want or have a look at the groovy ant task.

Categories