How do I manage a 3rd party jar dependency with Eclipse, Maven and Jenkins? - eclipse

We're trying to manage a project made of multiple Eclipse plug-ins.
One plug-in has a dependency to a 3rd party plug-in. It imports a class from a library named bpmn2. This library is a jar file and NOT included in the Maven remote repository.
Locally, in Eclipse, we have the library checked out into the workspace and referenced in the classpath of the Eclipse project. The plug-in manifest doesn't explicitly state the dependency to bpmn2. Which works locally...
We try to use Jenkins for continuous integration. The Multi-Plug-in-Project is managed using Maven and multiple POM files, using the Maven tycho plug-in.
The problem is that Maven doesn't care for the locally present library bpmn2 (of course). So we thought that using Maven install:install to install bpmn2 to the local Maven repository
./mvn install:install-file -Dfile=/home/someUser/bpmn2/org.eclipse.bpmn2_0.7.0.201111021300.jar -DgroupId=org.eclipse.bpmn2 -DartifactId=bpmn2 -Dversion=0.7.0 -Dpackaging=jar -DlocalRepositoryPath=/var/lib/jenkins/localRep/
and adapting the corresponding POM with a dependency entry for the library
<dependencies>
<dependency>
<groupId>org.eclipse.bpmn2</groupId>
<artifactId>bpmn2</artifactId>
<version>0.7.0</version>
<type>jar</type>
</dependency>
</dependencies>
would work. But it didn't.
The output of Maven is:
[ERROR] Cannot resolve project dependencies:
[ERROR] Software being installed: modeltype.bpmn2 1.0.0.qualifier
[ERROR] Missing requirement: modeltype.bpmn2 1.0.0.qualifier requires 'bundle org.eclipse.bpmn2 0.7.0' but it could not be found
[ERROR]
The question is:
How could we better integrate the 3rd party library?
The local classpath reference is not the optimal solution for the greater picture, I think. Should everyone who develops for the project install the bpmn2 library and only use the dependency in the manifest?
And what are we doing wrong with Maven? The local repository is
/var/lib/jenkins/localRep
and after installing the library to the repository, it seemed that the created dir structure was okay.
/org/eclipse/bpmn2/bpmn2/0.7.0/bpmn2-0.7.0.jar
Can somebody help?

The simplest solution would be to set up a repository server for your company and proxy all your calls through that server.
I use Nexus from Sonatype.
It acts as a proxy when you need to download artifacts from remote locations, like maven central, but it also has an ability to setup repositories to store non-publcicly distributed artifacts.
The whole setup process is very well documented here -> http://www.sonatype.com/books/nexus-book/reference/.
Note, that open-source edition of the product is very good and is enough for your purposes.
Just to be fair, there is a competing product called Artifactory. You may read about it here -> http://www.jfrog.com/products.php

I had a similar scenario where I need to include a third party library (not loaded in maven repository) in Maven Web project.
Following approach helped us make the code portable.
Solution:
Created the "lib" directory under WEB_INF as below:
<<Project_Base_Dir>>/src/main/webapp/WEB-INF/lib
Copied the third party JARs to LIB directory.
Updated POM.xml to use the SYSTEMPATH as below:
<dependency>
<groupId>GROUP_ID</groupId>
<artifactId>ARTIFACT_ID</artifactId>
<version>VERSION</version>
<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/<<JAR_FILENAME>></systemPath>
<scope>system</scope>
</dependency>

If you can't use Nexus, you can use scope system :
Dependency Scopes
system: This dependency is required in some phase of your
project's lifecycle, but is
system-specific. Use of this scope
is discouraged: This is considered an
"advanced" kind of feature and should
only be used when you truly understand
all the ramifications of its use,
which can be extremely hard if not
actually impossible to quantify.
This scope by definition renders your
build non-portable. It may be
necessary in certain edge cases. The
system scope includes the
<systemPath> element which points to
the physical location of this
dependency on the local machine. It is
thus used to refer to some artifact
expected to be present on the given
local machine an not in a repository;
and whose path may vary
machine-to-machine. The systemPath
element can refer to environment
variables in its path: ${JAVA_HOME}
for instance.
You can use it with
Be careful, using this is probably making your build not portable.

Related

How to set Maven dependencies on a local jar file

I am starting to play around with Maven, to see whether we could use it in the future to handle our dependency management, and IDE environments.
I have looked at some YouTube vids on how to get started with Eclipse (we also use Eclipse), and where you basically start off with creating a new project of type Maven. I have done this, and imported my existing source into the src/main package type.
Now I want to start adding the dependencies. No changes to my pom file yet.
I have two directories with jar files in them, and I need to set those dependencies in the pom file.
How do I do that?
This is not how you usually use Maven. You can add a jar through a path
<dependency>
<groupId>org.javap.web</groupId>
<artifactId>testRunWrapper</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/lib/testRunWrapper.jar</systemPath>
</dependency>
but the recommended way is to draw your jars from a Maven repository (like MavenCentral, or your Nexus/Artifactory).
So if you want to use Maven in your company, make sure you have a running Nexus or Artifactory server in your company as well. Then you can either proxy external Maven repositories (which contain most of the available open source components) or upload your own jars through the interface of your Nexus/Artifactory.

Configuring to Maven Project

I was using eclipse for building my project. Now I am configuring the project to Maven project. All the libs were manually downloaded to lib folder. If I do a Maven build, Maven is unable to map those libs. There are lots of libs, I don't want to manually place them in pom.xml. What is the best way out?
I have read few answers, first declare local repo and then add the respective dependencies. But again I don't want to add all the dependencies manually.
Maven: best way of linking custom external JAR to my project?
1.) Install locally
There are two scopes which are interesting for you. If you declare a scope "runtime" (which is the default scope) and have a local repository configured, maven will try to download the file from your local repository.
2.) System dependency
If you just don't want maven to manage dependencies, you can (although shan't) use the system scope like this:
<dependency>
...
<scope>system</scope>
<systemPath>/path/to/dependency.jar</systemPath>
</dependency>
The downsides are:
the system scope is deprecated and might not work in future versions of maven.
you need to check in a jar file, which is not a good idea.
it may not be portable (e.g. architecture dependent libraries).

How to package only the necessary libs in Google App Engine Project(Java)?

Let me explain first what I mean by necessary libs. I'm creating my first project using the Google App Engine for Java with the official Google Maven Plugin, the main problem that have Maven as a packaging solution (or maybe the Java development as a whole) is that if the dependency tree grows too much, the release process may be harder.
Let me illustrate it with an example. Let's start with the Jackson JSON library (it's a good starting point since it has no parent dependencies), now someone makes a JSON-RPC library and uses Jackson for the JSON serialization/deserialization. Imagine that this library not just provides a JSON-RPC client implementation, but also a server, that means that the POM of this lib will add some Java EE related libraries such us Jetty as dependencies.
Probably the guidelines say that the application should be either divided into modules or mark the server related deps as optional, but you know that many people don't follow the standards.
Now someone need a JSON-RPC client for his/her project, call it Project X, and uses the lib mentioned above, at compile time there will be no problems, Maven will successfully download the required libs and the application will compile fine, but the problem comes when that person wants to release the application. Which dependencies should be distributed along with the package (in a lib folder for example)?
Actually that's something that happened to me, I wasn't too much familiar with Maven so I used the Eclipse Runnable Jar Exporter, that produced jar file with all the maven libs copied to a lb subfolder, so the workaround that I did then was to just delete the libs that looked unnecessary and then tested if the application was still working. If there are classes that are not executed, as far as I know they are not loaded by the ClassLoader so they could be omitted and are unnecessary
I can't use the same trick now since the scenario is much more complex, we are talking of a Java Web Application, not a desktop application like the other one, and the library that I want to include is a Liquid Template Engine, which uses the ANTLR framework to generate the parsers plus Jackson for the JSON handler and Jsoup for HTML parsing.
Which libs should be packaged inside the WEB-INF/lib folder? I'm sure that I will need Jackson for JSON parsing but I'm not so sure about Jsoup, and what about ANTLR, it is necessary or is used just at compile time?
Update: I think I need to re-formulate my question, actually what I want is to determine which dependencies are really necessary for the application, and package those into the app WEB-INF/lib folder
Solution: It seems that the POM file that is packaged in the WAR file of the web app is used once the app is in the Google App Engine production environment to retrieve the necessary dependencies, and probably the appengine:update goal only packages those dependencies that can't be retrieved from the maven central repo, so there is no need to worry about that.
Thanks to David to point this.
You should check Maven's dependency scopes. Here's an extract from the documentation :
There are 6 scopes available:
compile This is the default scope, used if none is specified. Compile
dependencies are available in all classpaths of a project.
Furthermore, those dependencies are propagated to dependent projects.
provided This is much like compile, but indicates you expect the JDK
or a container to provide the dependency at runtime. For example, when
building a web application for the Java Enterprise Edition, you would
set the dependency on the Servlet API and related Java EE APIs to
scope provided because the web container provides those classes. This
scope is only available on the compilation and test classpath, and is
not transitive.
runtime 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.
test 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.
system 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.
import (only
available in Maven 2.0.9 or later) This scope is only used on a
dependency of type pom in the section. It
indicates that the specified POM should be replaced with the
dependencies in that POM's section. Since they
are replaced, dependencies with a scope of import do not actually
participate in limiting the transitivity of a dependency.
So in a Maven project, the developer indicates which dependencies should be bundled in the application and which should not.
Basically there are two cases here :
If you're building a web application (WAR or EAR format) and want to deploy it, or if you're building an actual runnable jar, then you will need to bundle it with all the dependencies with scope compile and runtime.
If you're building a library, then you do not package any dependency with your library. Instead you include the pom.xml so that others know what dependency your library requires. For Maven to know how to find the associated POM for a given jar, the best and most common solution is to deploy the library to a Maven repository. Repos have a directory structure that helps Maven find the right version of a library, and find the POM that indicates the required dependencies.
Depending on wether your library is open source or not, you will be able to be hosted for free by some repositories such as Sonatype (complete list here). But you can also setup your own repository either by installing a dedicated software such as Nexus or by configuring a Github project as the repo, as is explained on this blog.
You can exclude any transitive dependency.
For your case, to remove jetty from this json-rpc-library, you need:
<dependency>
<groupId>com.somecomp</groupId>
<artifactId>jsonrpclib</artifactId>
<version>1.0</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</exclusion>
</exclusions>
</dependency>
See docs: http://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html

what exactly maven dependency tag does?

I have started reading and trying maven since yesterday. But its making me go crazy.
I am java developer but never came across ant or maven before.
I want to know what exactly happens with the dependency tag in POM.xml file?
Lets say, I am using camel framework and want to use camel core jars.
If one of my class file contains following line:
CamelContext context = new DefaultCamelContext();
so what exactly I need to do after that?
Do I need to include the jars myself in the class path or dependency tag will download the jar files over internet for me?
If the case is former, what dependency tag will do? & where should I place my jar files? I mean is there any specific location on my hard drive? and
if the case is lateral then during compile time I get error "cannot be resolved to a type"
And the imports are to be specified or not?
I know the question might sound silly but I am not able to find its answer.
I have tried googling alot, it didn't help me still.
Any help would be greatful, even help on maven topics which I might come across in near future would be appreciated.
Thanks in advance.
Solved. Please check https://stackoverflow.com/a/20094312/1121208 for help
dependency tag will download the jar specified in the dependency tag for you if available. Otherwise will raise a pom.xml error - could not found dependency..
Imports have nothing to do with maven. They will appear when you will you another class in your class/java file. So if you import in build path the jar by yourserf or if you put it there with maven, you will have the import.
Are you using eclipse or any other ide ?
First of all, Maven is a build tool. It doesn't run your app. It builds it. So, at runtime, the classpath needs to be set like for any oter application yo would have built with something else.
When you build an app, you depend on external libraries. The dependencies mechanism of Maven simply lets you declare wwhich libraries your ap needs. When you build your app, Maven downloads these libraries from a central repository (or sevaral ones), and stores them in a local repository on your hard drive. These jars are automatically added to the build classpath by Maven. At runtime though, depending on the kind of ap you're building, you'll have to copy or embed those jars in order to create a runnable application.
The rules of Java don't change just you build them with Maven. Meven uses the stadard Java compiler (javac). And of course, if you want to use a class by its simple name, you'll have to add an import statement for this class.
I think that, before using Maven, you should try to compile and run a simple application depending on an external library without using any IDE. You would then understand better all the steps that are required to build and run an app, the concept of build and runtime classpath, etc.
Finally got what I needed to know
Sharing it for others who may stuck up in same situation
Does dependency tag download the jar specified?
maven dependency tag actually downloads the jar files you specify in the dependency tag. It downloads and save it under .m2/repositories(local repository) folder on your hard drive (along with some information like last updated, etc)
Local repository is shared among all your projects
from where it downloads?
It downloads the jar from the central repositories. There central repositories contain almost all the open source jar files one needs in a project. It downloads based on information you provide in groupid, artifactid, etc.
http://repo1.maven.org/maven/
http://mvnrepository.com/
can be checked for correct groupid, etc
Once these jar files are downloaded, they are automatically added to the classpath and are available in your project for use.
If the jar files you are searching for, are not available in the central repository, maven may throw error, in that case you can download it manually and let maven know about it.
Without maven you need to put jars into lib folder.
With maven you specify as declaration inside <dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
and when you do mvn package, maven will download required jars on your PC.
With Eclipse and m2e (maven eclipse integration) you can do that all not leaving Eclipse,
and even get sources for used libraries automatically.
Read http://maven.apache.org/ It worth it.

How can I use Eclipse p2 repositories from Maven?

I am trying to create an Eclipse based setup where Eclipse projects are Maven based. So it should all work with Maven whether or not Eclipse is used.
I have a dependencies on various Eclipse project libraries, with more to be added. I want to use p2 repositories, and I've managed to pull an Eclipse EMF library and turn it into a jar following this example: Use dependencies from Eclipse p2 repository in a regular Maven build?
The problem is, I could not find a way of streamlining the process. I'd need to manually install the re-packaged dependency from the question given above to local Maven repository so that I can reference that in other projects. I'd like to seamlessly integrate artefacts from p2 repositories to my Maven based setup. m4e does not look like the smooth solution I'm looking for: Ideally I'd like to distribute a set of directories which would do everything in response to a simple mvn clean install : pull libraries from p2 repo, pull other libraries from Maven repositories etc..
Is this doable via Maven and Tycho integration?
Update: first, clarification to the question: just being able to reference to P2 repositories does not help with the scenario where this reference needs to be used from another project. The library (or libraries) referenced from P2 repository must be re-packaged as a jar so that it can be referenced by other Maven projects. The referenced question does the packaging. However, it does not explain how this repackaged output (assembly) can be used from other projects. In my case, this turned out to be referencing the assembly from an aggregating POM, and inheriting form that POM for all projects that would like to use the library with the P2 repository origin.
Tycho projects can pull their dependencies from both p2 repositories and Maven repositories (see this related answer). This could be a solution for you, even if you are not building for an OSGi runtime: Most OSGi bundles also work as "plain" JARs on the classpath.
Limitation: The artifacts referenced from Maven repositories also have to be OSGi bundles, so that Tycho considers them for dependency resolution. If this is not the case (and you can't find replacements which are OSGi bundles), you may be able to combine Tycho's dependency resolution with plain Maven plug-ins:
Use one of Tycho's packaging types (e.g. eclipse-feature) and specify the dependencies to the p2 artifacts in the file format for the packaging type (e.g. a feature.xml)
Additionally configure the plain Maven goals in your POM. Tycho injects the OSGi/p2 dependencies into the Maven model at runtime, so for example a maven-compiler-plugin:compile call would see both the Maven dependencies and the p2 dependencies.
The solution is to create a multi module setup with Maven, and declare a dependency on the outputs of EMF library re-packaging (from the question I've referenced) The parent pom for all projects has this:
<dependencies>
<dependency>
<groupId>com.mymodule</groupId>
<artifactId>myartifact</artifactId>
<version>0.0.1</version>
<classifier>repackaged</classifier>
</dependency>
</dependencies>
<modules>
<module>../mymodule</module>
</modules>
Which lets all modules that has this module as parents access the repackaged P2 artifacts.