Creating a Java application that downloads its own dependencies - java

I'm interested in how to distribute a Java application that has a lot of dependencies (specified in a pom.xml in Maven).
Obviously it would be possible to just package everything in one big .jar file. However that seems wasteful, since an update of the application would require sending a new copy of all the dependencies as well.
So I'm looking for a way of distributing the app that does the following:
Only includes the core application in the main .jar file
Downloads dependencies as needed when the .jar file is run
Keeps copies of the dependencies locally, so that if an application update is distributed the dependencies don't need to be downloaded again
What's the best way of achieving this?

Can you just use Maven, with something like described at Maven Run Project ?
This is how I have some of my own applications setup within my own network. I've never needed to worry about messing with the classpaths or downloading / providing dependencies for programs setup like this for a long time. This approach also meets all of your criteria.

you can distribute your file using the web start technology (aka distribute a jnlp file). i believe this will handle most of this functionality for you, including updatability.

Related

Managing dependencies between web application

Is there any way to manage dependencies between different JavaEE projects?
But not on the traditional sense of WAR1 depends of JAR1 and JAR2, and WAR2 depends of JAR1, and so on... if this was the problem I could have used Maven, or ANT/Ivy, or ....
What I need is a way to say that if I need WAR1, I also need WAR2 and WAR3. And I also need to specify the version of each of those projects.
I'm currently using ANT + Jenkins on the deploy cycle, but I'm opened to other alternatives if they would make my job easier.
I would make a maven module/ant task that creates a zip distribution file combining required war files with specified versions.

Are there best practices in using bower in a source-controlled, mavenized, java web application

I'm quite new to bower but not web application development. Previously, I've just downloaded the required JavaScript and CSS files from third-party libraries/frameworks and placed them into my web application's src/main/webapp/scripts (or equivalent) folder. This ensures that only the files needed by the web application are deployed.
With my default setup, the entire bower_components directory will be committed to source control and if I follow the examples for referencing a bower package, e.g.,
<script src="/bower_components/jquery/jquery.js"></script>
I'm going to end up deploying the entire bower_components directory with my web application. This seems like huge overkill (especially were I to use jQuery UI because all the themes are downloaded into bower).
Is there a best practices in using bower with a web application such that the application isn't bloated with unnecessary third-party library files? Please remember that this is also Java and Maven web application.
Seeing that you tagged maven on this question, I completely disagree with checking in 3rd party libraries, after having tasted the goodness of maven dependency management :) no matter whether it is a jar or js.
This is something that we've been trying to reconcile at my work as there doesn't seem to be a natural way to do js dependencies in maven. Specifically for bower there looks to be a good maven plugin here:
https://bitbucket.org/cofarrell/bower-maven-plugin
for which you can specify the target directory. I haven't used it yet, but I would want to have it bring in the js files to my target directory so I don't have to put it in my source. If we move forward with this, this is what I envision.
If you're interested I have more to add (since there's not a lot out there about this topic)... We are currently using maven "js" artifacts so we can leverage maven's dependency management with our 3rd party js. A plugin that we've forked to do this for us is at:
https://github.com/cameroncan/js-import-maven-plugin.
It does its job, but was built for our use case. Please submit issues if you find it is in need of genericizing. We do have to manually upload these artifacts to nexus, but that hasn't been too big of an issue.
A big advantage of using the maven dependency mechanism is the transitive dependency resolution. We have our js broken out into different modules and without maven, there will likely be collisions with the versions of our js files, resulting in a big mess in the final app that pulls all of the js dependencies in.
I just read some articles on this subject and it seems that Bower itself recommends "checking-in" the bower_components into source control:
"...you should always check installed packages into source control.”
From the articles I read, I kind of get the following:
If your project is to be consumed by others (eg: as a bower package too), then don't include bower_components in source control
If your project is to be deployed, include bower_components in source control
You can use bower-installer which is a node package to control which files to be copied to your static resources folder from the downloaded distribution package folder. Please look into below link.
https://www.npmjs.com/package/bower-installer
I followed below steps to select which files to be copied to my lib folder
1) Install bower-installer by runnnig npm install -g bower-installer command
2) Create 'bower_components' folder outside of your src folder.
3) Edit bower.json configuration file(in the 'bower_component's folder ) and specify path for each js library components.
4) Run bower-installer from terminal

Sharing a Spring MVC project

I need to do a Java web project. I'm going to be using Eclipse.
I thought of using Spring MVC. As far as I can tell - it's gonna require me to add some "extra" stuff to a "clean" Java web project. I don't mind that - the thing is - one of the project requirements is - that I'll be able to send the project to someone else - that doesn't have any extra installation and/or configuration - and he will be able to compile the project.
Is that possible with Spring MVC? Does the Spring MVC framework is just a "JAR" like addition to the project - therefore - the project can be shared without a problem?
Thanks.
Short answer: yes, you are right.
To use Spring in your Java web project, you generally need to add two things:
the appropriate Spring configuration file(s) (XML)
the appropriate Spring JAR files (traditionally placed in /WEB-INF/lib, the same as other JARs). By the way, it is NOT a single JAR file, but several JAR files.
That is all there is to it.
Spring has nothing to do with "sharing the project".
To "share" the project with someone else, you put it on the SCM of your choice and your collaborators will be able to get the code and work on it.
Building the project is a different aspect. To correctly compile the project you have to make sure that all the classes and/or jars are visible in the classpath (and runtime if you want to execute the code). Spring is made of a bunch of jars that, depending on which classes of the framework you use, must be in the classpath (eg. putting them in the /WEB-INF/lib directory). You may version them as well, or just version the configuration (I'm thinking about Maven for example, that will take care of resolving the dependencies).
Another piece of the puzzle is making all of this work in your IDE. This is a matter of taste. I prefer not to version ide-specific files (in the case of Eclipse, .settings and .project files/folders). You can do that, making sure you do not use absolute path anywhere, and technically you will be able to import the project without problems from another machine.
Yes.
If the other person has nothing extra installed and configured, namely no build tool, you need to put every needed Spring and other Jar into a folder, typically called "lib" and tell him to add them into his compile process. If he just uses the JDK he will get an enormous command line. It is much better to use a build tool like Maven or Ant+Ivy for building and dependency resolution. But that would be an "extra installation" per your question.
If he has Eclipse installed like you have and you use Eclipse internal for building:
Put the JARs in a lib folder
Configure the build path
Make a local test build
Export the project as zip (File menu > Export)
" The other person needs to import the project into his workspace
The exported project should not have any absolute paths as long as you didn't set some deliberately in the build path.
This works but is not exactly best practice. Installing a build tool like Maven is absolutely worth the time and should be preferred under any circumstances. It will save you a lot of time and nerves.

How to share common resources between many webapplications?

I have 4 web applications. But images, css, javascripts are the same.
When I do changes in one project after I need propagate changes to all projects.
What the best way - create common jar only with resoures or use something similar to links in SVN or else?
Thanks.
I had the same requirement and got exactly what I needed using Bower and a small Perl script.
The problem with doing a simple copy of files across your shared projects is if for any reason in the future you need one of your projects to temporarily have a slightly modified version, you will essentially either break your project or your deploy routine. It's a much cleaner way to manage shared resources across projects by placing them in their own version controlled repository so each project can refer to a particular version either "latest" or "1.0.0" etc... now the solution:
Bower is a package manager which can, among other things, help manage retrieval/dependencies of git repositories. You can fetch git repositories from urls or even local paths on a drive. So all the files that need to be shared across projects I place them in their own individual git repository. Bower can then fetch a particular version of the shared content. The only problem is that bower copies them all in one particular sub-directory which is not always ideal.
Script(bower-redeployer) so then I use this perl script to deploy the fetched shared resources to the right location in my project.
With the maven resources plugin, you can specify a copy-resources goal that will copy the common resources into the specified projects prior to building the war files.
I've also seen the use of a common directory that is links (ln -s) during the build. This avoids the space and time load of creating physical copies of the resources.
Couple of suggestions...
Put them in a common jar file
Put them on shared URL(s)
(Promoting user710818's comment to an answer)
Consider using the Maven WAR plugin's overlay feature as described in the following links. From the first link,
Overlays are used to share common resources across multiple web applications. The dependencies of a WAR project are collected in WEB-INF/lib, except for WAR artifacts which are overlayed on the WAR project itself.
http://maven.apache.org/plugins/maven-war-plugin/overlays.html
http://java.dzone.com/articles/mavens-war-overlay-what-are
http://www.manydesigns.com/en/portofino/portofino3/tutorials/using-maven-overlays

Deploying Java Files

What are the best practices (and enabling tools) to deploy Java standalone applications along with any required jar dependencies, config files, and launch scripts?
Are there any Maven plugins that easies publishing binary releases, so that users don't need to use maven for example?
Are there any Maven plugins that easies publishing binary releases, so that users don't need to use maven for example?
Use the Maven Assembly Plugin to create a binary distribution as zip/tar.gz/tar.bz2 of your project. This plugin is extremely flexible - at the price of some complexity - and you can do almost anything you want. Then deploy (in the maven sense) the produced artifact, upload it somewhere, etc.
As for dependency, I just use maven dependency copy plugin and copy all dependencies into a ./lib folder, and supply a launch script that uses the class path wildcard (that way you can change your dependencies as much as you want and don't have to change the launch script). As for configuration files, I put it in a ./config folder and again include it in my app's classpath in the launch script (The former admittedly only works for > java 1.6).
So in the end almost all my app has the following structure:
mystuff.jar launch.sh
./lib
./config
Then I'll just zip up the whole thing and give it to my users. The whole process is probably easy to automate using maven, but I confess that I do it by hand :p
If you prefer and the licenses permit, you could also just bundle all dependencies into a single jar (with expanded dependencies inside) using the assembly plugin. This tends to make the jar bulky and giving the users an updated app. more difficult. Also I had issues with it several time because of class files getting overwritten or something so I personally stick to the ./lib folder.
There's launch4j, which, if you can get it to work, will bundle up a Java app into an executable for your platform.
If your deployment target supports RPM files, I strongly suggest you investigate the rpm-maven-plugin. It allows you to easily map your project artifacts , including dependencies, to a RPM package.
I've been using it with great success to medium-scale application deployment.
You can use Oracle's ant or maven scripts:
http://docs.oracle.com/javafx/2/deployment/jfxpub-deployment.htm
The above will not only compile your code and create jar files, but it will also create binary executable (windows exe file or Mac app file). It can also create native installers. In addition it lets you include JVM with your distribution so the end use doesn't need to install Java.
Take a look at the Appassembler Maven Plugin. You may also want to combine it with the Assembly Maven Plugin.
Use the appassembler plugin to generate a set of "programs" by specifying executable names and main classes. You can also have it prepend and create an etc directory in which you can add configuration files.
If generating the directory with the start-up scripts and directory of binary files isn't enough, you can use the assembly plugin to copy over additional files (say your configuration files) into the appropriate directory and/or package your application into an archive.

Categories

Resources