Building complex project with Ant - java

I have an Eclipse project that depends on several other projects from the same workspace. I know hot to create a simple Ant build script for a single independent Java project, but how to tell Ant to integrate all those project into my main JAR file so my dependent program can work?

In Ant, the simplest way is to explicitly enumerate those other projects and include them in the jar target. Something like:
<path id="all-projects">
<fileset dir="../my.other.project" includes="**/*class">
</path>

One solution : Create a master project and put all the projects into it and have a single build.xml.
Another option : Create a master project but leave everything at the same level (do not place project-components inside the project folder) Then arrange your build script to refer to the other projects via relative paths. Note that with some build tools this is not even necessary as they will look at their repository.

While you can munge together a solution with Ant, Apache Maven is a better solution for managing dependencies than Ant. If you don't want to go with a full blown Maven lifecycle management project, you can also look at using a Nexus repository to store your artifacts, and include Apache Ivy in your Ant build scripts to perform dependency management.
Ivy or Maven will provide a better, more manageable dependency management strategy which is likely to be easier to integrate into a team than anything you will be able to assemble on your own.

Related

Packaging to Maven project

currently we are using ANT script to build the project and running jUnit tests. Now, we decided to move to Maven.
We have two web projects, Core-Project and Sub-Project. Now here it gets complicate. Their project is as follow.
Now, If I want to add this Sub-Project to Core-Project then I will create a jar of Sub-Project with WebContent folder and put it into Core-Project. Now whenever I run Core-Project, we have one utility class which extract content of Sub-Project into Core-Project.
Final(expected) project structure should look like this.
How can I achieve this in Maven? I mean how do I create a jar which contain some files located in src->main->webapp.
It seems that you need to rethink your architecture a bit. This answer may go beyond the scope of your question, but it's important to treat Maven as 'convention over configuration'. It is possible to achieve your layout using a combination of maven packaging tools, but if you restructure and follow Maven conventions, it will make more sense to people outside your project and be less work to maintain.
Suggested:
config-project
sub-project
core-project
config-project can hold the configuration for all parts of your application. sub-project and core-project can depend on this project and use it at runtime. You should package this project as 'jar' or 'zip' depending on the resources you need to make available to other projects.
sub-project should only contain the binary code common to the non-web based part of your application. It should be packaged as a 'jar' project and not be packaged with the config-project dependencies.
core-project should be packaged as a 'war' project. and follow the directory structure as suggested here: Maven War Plugin
Keeping the separation between your configuration, your non-web code and your web code will take a little bit to get used to. There is an excellent archetype by Tomcat which generates a maven project structure composed of these parts. It is easy to generate and inspect: Maven Tomcat Archetype

IntelliJ Idea with Gradle: Best Practices

I am developing a Java application using IntelliJ Idea 14.1.4.
If it would have been solely Java application, I would have known exactly how to structure the project in Idea:
A single Java project, containing several modules: One for each part of the application (JAR).There will be at most 4-5 JARs.
The dependencies between the modules are also known: Protocol does not depend on anything, everything else depends on Infrastructure, and so on.
Next, I would like to use Gradle scripting for managing the project. So my question is what is the best practice to structure the code in Idea?
Should I create a single Gradle Project and a Gradle module for each of the JARs?
Should I create a single Java project (or maybe empty project) and Gradle modules for each of the JARs?
Should I create a single Gradle project and each of the modules will be a Gradle's sub-project? Maybe it will be better to have an empty project and several Gradle modules because not all of the JARs are closely coupled?
Since I have never used Gradle before, I would appreciate any guidance for the best practices when combining both Gradle and Idea.
Thanks,
Guy
As long as possible, I would keep the code in one source repository. On the root, I would have an "empty" project not outputting anything. All your jar projects would be sub-projects (in Gradle terms). You include them via the settings.xml file located in the root project.
Each sub-project has its own build.gradle file. In those files, you can easily define the dependencies between your sub-projects, e.g.:
dependencies {
compile project(':subProject3')
}
For convenience, I often create a special export task to put all artefacts in one export/ folder on the root level so that you don't need to go through all those sub-folders to get your stuff.
task export(type: Copy) {
from project(':subProject1').jar
from project(':subProject2').jar
from project(':subProject3').war
into 'export/'
}
IntelliJ Ultimate 14 works fine with this approach. You can simply hit Make to compile everything. You might also want to configure your project settings to run gradle jar or gradle export during a make if you prefer.

Maven: is there simple way to generate a pom.xml file only?

I wanted to take a legacy project, and generate an initial pom.xml file for it, without converting the whole project. (The thinking is to take advantage of some Maven tasks without creating a big ripple effect in the automated builds that already include this project, which are not Maven projects.)
Is there some way to do this other than archetype:generate (in a phony directory), and then
copying the pom.xml to where I really want it?
AFAIK, no.
But if you know enough about Maven, you can typically write a POM file for a legacy project.
The complication is that the files / directories of a legacy project will typically not be organized in the Maven recommended way, so the normal generation tools won't work. However, "it is said" that Maven can cope with non-standard organisations ... if you write the POM file appropriately.
Another approach is to build the legacy project in the legacy way, and then manually add the resulting JAR files to your Maven repo with appropriate "coordinates" (i.e. group-id, artifact-id and version) so that your Maven projects can use them.
You seem to want to do an unorthodox thing with Maven, and while I like Maven, I find Maven is absolutely terrible at doing unorthodox things.
I would suggest using Gradle instead--especially since you just need to perform one task and don't need to build with it (and therefore learn it).
Because Gradle is a Groovy DSL, you can simply write some Groovy code to access a repository and copy it into a directory on the local file system.
(I will leave aside my personal abhorrence of putting compiled artifacts into source control.)
Gradle also has outstanding integration with Ant.

use ivy java project in maven?

I have a big maven project with many subprojects that are also maven based.
I started using Red5, and red5 creates an ivy based project. I need to add that project to the dependencies.
list files of project main directory:
build.properties build.xml ivy.xml ivysettings.xml lib readme.txt src www
how can I add this project as one of the maven project dependencies ?
using Java with Maven 3.0.4
thanks!
Kfir
Interesting... A lib directory in an Ivy project.
You can modify the build.xml to create one more target that calls the <ivy:makepom/> target. Just make sure that <ivy:resolve> is called first. This will create a small piece of the pom.xml file you need.
As for the rest. What's that technical term? Oh yeah, you're screwed.
The problem is that Ant and Maven have two completely different build philosophies. In Ant, you write a build.xml script that describes what you want to build and how you want to build it. In Maven, you describe your project via a pom.xml file, and Maven does all the build processing for you.
This isn't an issue of whether or not Whether Ant or Maven is the force of all that's good in the world and the other is only for luzers Apple Fanboys. This is a case of manually converting a pre-existing project into Maven.
You'll have to go through your build.xml and figure out everything it is doing. Then, you need to convert this over to a Maven pom.xml file. There's no way to automate this. Even worse, Red5 isn't setup like a Maven project, so you'll either have to move all the files around, or go into archaic pom.xml configuration hell trying to override how Maven assumes the build is suppose to take place. This can take days, even weeks to get right. And, in the end, you end up with a project you don't control that if you want to update will have to be done all over again from scratch.
Trust me, I did this before for another job where the System Architect decided that Maven was better than Ant, and all of our projects must be converted from Ant to Maven. And, who got stuck with this task? Not the developers who were too busy with other tasks, but I the Configuration Manager.
And, in the end, you will have a project you don't control that if you want to update will have to be done all over again from scratch.
There is an alternative: Ignore it.
Does it really matter if Red5 is an Ivy project? What do you need from this Red5 project anyway? Do you need that red5.jar or the distribution that gets built.
If you need the distribution, let it remain as an Ivy project. Simply set the ivysettings.xml to point to your Maven repository and let it know that it's in Maven 2 format. Ivy will have no problems getting stuff out of that. So what if it's Ivy?
If you just need that red5.jar file in your other Maven project, you can simply use the <ivy:makepom/> task to generate a pom.xml file for you. Then use mvn deploy:deploy-file to deploy that jar into your Maven repository:
$ mvn deploy:deploy-file -Dfile=red5.jar \
-DpomFile=pom.xml \
-DrepositoryId=$repoId \
-Durl=$url
Now, your red5.jar is in your Maven repository as a fully transitive downloading jar. If you really, really want to get fancy, you can embed the generated pom.xml file into the jar itself, so it is self referential just like Maven jars are. That will take about 30 minutes of hacking the current build.xml file. (Or, if your jar doesn't have to have the pom.xml embedded in it, a separate Ant file that just builds the pom.xml you need, and maybe even deploys it into your Maven repository for you. That way, if the project gets updated, you don't have to worry about the build.xml file being updated.
I've not used it myself, but I know Ivy has a task which can convert an ivy file to a maven pom. I'd explore an option where my CI environment runs that task to generate a pom after a successful build, and then get my maven project to look at the CI's latest artifacts for the jar and pom. You could skip the CI environment as well, and have maven resolve artifacts from the local file system.
I don't think you're going to get away without creating a JAR. Maven's whole dependency philosophy is built around JAR files in a repository - when one maven project depends on another the way it works is that the dependent project builds its JAR and puts it in the local repository, then the main project depends on it from there.
That said, you can fairly easily automate this using a combination of <ivy:makepom> and the Maven Ant Tasks. The idea is to make the Ivy project build its JAR and push that to the local Maven repository as part of every build, so it is immediately available for the maven projects to depend on.
<jar destfile="project.jar">
<fileset dir="classes" />
</jar>
<ivy:makepom ivyfile="ivy.xml" pomfile="project.pom" conf="default,runtime">
<mapping conf="default" scope="compile"/>
<mapping conf="runtime" scope="runtime"/>
</ivy:makepom>
<artifact:pom id="project.pom" file="project.pom" />
<artifact:install file="project.jar" pomRefId="project.pom" />
Make sure your Ivy project has a version number that ends with -SNAPSHOT in its ivy.xml.

How to express inter project dependencies in Eclipse PDE

I am looking for the best practice of handling inter project dependencies between mixed project types where some of the projects are eclipse plug-in/OSGI bundle projects (an RCP application) and others are just plain old java projects (web services modules). Few of the eclipse plug-ins have dependencies on Java projects.
My problem is that at least as far as I've looked, there is no way of cleanly expressing such a dependency in Eclipse PDE environment. I can have plug-in projects depend on other plug-in projects (via Import-Package or Require-Bundle manifest headers), but not of the plain java projects.
I seem to be able to have project declare a dependency on a jar from another project in a workspace, but these jar files do not get picked up by neither export nor launch configuration (although, java code editing sees the libraries just fine).
The "Java projects" are used for building services to be deployed on an J2EE container (JBoss 4.2.2 for the moment) and produce in some cases multiple jar's - one for deploying to the JBoss ear and another for use by client code (an RCP application).
The way we've "solved" this problem for now is that we have 2 more external tools launcher configurations - one for building all the jar's and another for copying these jar's to the plug-in projects. This works (sort of), but the "whole build" and "copy jars" targets incur quite a large build step, bypassing the whole eclipse incremental build feature and by copying the jars instead of just referencing the projects I am decoupling the dependency information and requesting quite a massive workspace refresh that eats up the development time like it was candy.
What I would like to have is a much more "natural" workspace setup that would manage dependencies between projects and request incremental rebuilds only as they are needed, be able to use client code from service libraries in an RCP application plug-ins and be able to launch the RCP application with all the necessary classes where they are needed.
So can I have my cake and eat it too ;)
NOTE
To be clear, this is not so much about dependency management and module management at the moment as it is about Eclipse PDE configuration.
I am well aware of products like [Maven], [Ivy] and [Buckminster] and they solve a quite different problem (once I've solved the workspace configuration issue, these products can actually come in handy for materializing the workspace and building the product)
Eclipse projects depend on each other by virtue of the checkbox in the project's properties (dependent projects?) which is how Eclipse decides which to build. You can set this yourself, but it's usually set when you change your Java build path. It stores the data in the .project file IIRC so once you've gone through the GUI and seen what changes, you can be more flexible in how you apply the others.
However, it sounds like you want to mix and match Jars and Bundles. The easy way to do that is just treat all projects as Java projects. In the PDE project, you can actually go in and tweak the Java build path; it'll complain and say that it isn't the right way to do it, but it will allow you to have a PDE project depend on a Java project without all that fluffy JARing up. Having said that, it wouldn't surprise me if there were runtime problems with this approach - the PDE runtime is likely to not see it that way.
The other approach is to make your JARs themselves PDE/OSGi bundles. After all, an OSGi bundle is nothing more than a JAR with a bit of extra cruft in the Manifest, and it will let you develop and assemble your projects trivially using automatic dependency management. That's probably the easiest one to go for, even if you don't really need the manifest to be present in your bundles. But doing this will mean your PDE app can be shipped with a more modular approach instead of embedding the libraries in each plugin as necessary.
So, PDE can generate OSGi bundles, and that's just another name for JAR + Manifest stuff. You can use a JAR in exactly the same way in other environments (e.g. for your EAR or other client uses) and you can take advantage of the OSGi layer in your app. There's really no reason not to do this given the type of hybrid bundle that you're talking about.
I never did it so this is a theoretical approach. But I'd try a dependency management system like ivy or maven2.
Since maven2 does much more, then just dependency management, I'd recommend ivy in this case.
Our solution uses an Ant builder to copy the "classes" directories of the plain Java projects directly into the top directory of the plugin project. We skip the JAR building step to save time, and it works pretty well. If the plugin project depends on external JARs that're already built, we copy those in too.
Here's exactly how to set it up in Eclipse 3.5 (sorry for the odd formatting, but that's the only way I could find to preserve indentation):
Create empty "classes" dir in plugin project
Select plugin project, hit F5 to refresh resources
Create new Ant build file in plugin project to copy dependencies (ours is shown below)
Right-click plugin project, select Properties
Select Builders
Click "New..." (brings up Edit Configuration dialog)
Select Ant Builder and click "OK"
Name your builder (ours is called "PluginProject externals")
Browse workspace for Buildfile (ours is ${workspace_loc:/PluginProject/copyDependencies.xml})
click Refresh tab
check "Refresh resources upon completion", click "Specific resources"
click "Specify Resources...", check box for the classes dir, click "Finish"
Click "OK" (closes Edit Configuration dialog)
Click "Up" to move "PluginProject externals" to top of builder list
Click "OK" (closes Properties dialog)
Open your plugin project's MANIFEST.MF
Click "Runtime" tab
Click "Add..." under "Classpath", select your the "classes" dir and JARs and click "OK"
The manual creation of the empty "classes" directory in the plugin project is so you can tell your new builder to refresh that resource (which doesn't exist yet before the new builder is run). Here's what's in our copyDependencies.xml file:
<project name="Copy dependencies" default="copyDependencies" basedir=".">
<!--
This copying is needed because it appears that Eclipse plugins can't
depend directly on external Eclipse projects.
-->
<description>
Copies external dependency class andd JAR files into this plugin's directory.
</description>
<target name="copyDependencies">
<copy file="../External/JDOM/jdom-1.0/build/jdom.jar" todir="." preservelastmodified="true"/>
<copy file="../External/Xalan/xalan-j_2_6_0/bin/xalan.jar" todir="." preservelastmodified="true"/>
<copy file="../External/Xalan/xalan-j_2_6_0/bin/xercesImpl.jar" todir="." preservelastmodified="true"/>
<copy file="../External/Xalan/xalan-j_2_6_0/bin/xml-apis.jar" todir="." preservelastmodified="true"/>
<copy todir="./classes/com/arm" preservelastmodified="true">
<fileset dir="../Utilities/src/com/arm" excludes="**/*.java"/>
</copy>
</target>
<target name="clean" description="Deletes local copies of external classes and JARs.">
<delete file="jdom.jar" quiet="true"/>
<delete file="xalan.jar" quiet="true"/>
<delete file="xercesImpl.jar" quiet="true"/>
<delete file="xml-apis.jar" quiet="true"/>
<delete dir="./classes/com/arm/utilities" quiet="true"/>
</target>
</project>
The only downside to this method seems to be that Eclipse isn't 100% perfect about invoking the external builder when it needs to be invoked, so occasionally you have to do a "Project > Clean..." in Eclipse to force it along.
You have my sympathies. I too have battled with this issue and the Wall-of-Silence from the Eclipse devs on such a simple, obvious question: how to declare a dependency from a plugin to a normal Java project (such that it works at runtime)?
I dont think they support it. The only way Ive got around the problem is to create folders inside my plugin projects that are actually links to the bin/ folders of the java projects, and then include these folders into the plugin. That at least works, but its brittle due to the absolute filesystem paths required.
maybe you can use "project properties" -> "deployment assembly" on Eclipse, and add other projects to your main project. The other projects are seeing like "jars" that automatically are added to your deployment file (war, ear or whatever). Maybe this can be works. At least it works for me. Good luck !!
Ariesandes.
There is a "Link source" option in Build path properties that allows you to define additional source folders for a project. You can selected the "src" folder of another workspace project and rename it to "src2" or whatever you want. This way classes are compiled and deployed into the plug-in project output folder and can be loaded at runtime.
With a complex set of build dependencies, I've found Maven2 and Hudson (for CI) to be a pretty nice combination. It took a while to set up the infrastructure and get my head around configuration, but after that, it just worked.
Of course, you are dependent then on Maven2 (or Hudson) support for your build mechanism. I'm not sure how well Eclipse Headless builds are supported. But if the only reason you're using Eclipse headless is to allow the dependencies to be expressed in a single place, do yourself a favour and switch.
I am having the exact same problems. We have a set of multiple normal java projects that can be built by Maven and should (currently) all share the same classpath to work properly. These projects can be used to start a server in a non-OSGi environment. Then we also have an eclipse RCP client which uses these projects as one bundle. I am perfectly able to build this one-big-bundle with Maven using the Apache Felix Maven Bundle Plugin and everything works fine. But whenever I change one class in the normal project I have to rebuild the entire bundle. Incremental build and resource linking does not work.
I tried the "solution" with linking binaries/source directories from these projects into the Manifest classpath of the one-big-bundle and it seems to work but it would be a real maintenance nightmare because I even have to link some individual files.
So ironically BECAUSE of the use of OSGi in the client I am actually thinking of collapsing our nice and modular structure with Maven modules into subpackages of only one plugin project. This is a better alternative than having extremely slow development.
The other and better alternative (according to the OSGi guys) which I will investigate first is to make all my Maven modules into OSGi bundles. But this may be a real PITA because I depend on classpath scanning and combining multiple configuration files from several bundles (with sometimes the same name) to form one configuration.
(Specifically we use the Spring framework and we merge multiple persistence.xml files into one persistence context. We also merge several spring XML context files from different modules (all providing a different ASPECT) that should together form one Spring context to be used by Spring-DM.)

Categories