Category Archives: maven

Maven plugin for docker: embedding a Spring Boot application

We will take an example of how to use a Maven plugin for docker to embed a Spring Boot application. The Maven plugin that I am using is:

https://github.com/spotify/dockerfile-maven

These are the basic operations that I do with this plugin:

  1. Given a Dockerfile, I create a docker image by saying mvn dockerfile:build. This builds the docker image from the jar file in my target folder
  2. After building the docker file, I would like to push it to my docker hub repository by using the command mvn dockerfile:push.

This is how I define the docker plugin in my pom.xml:

Note that I have defined my docker repository details in the repository tag.

This is how the Dockerfile looks like:

Providing encrypted credentials to Maven

In addition to the above, I also need to provide my credentials for docker.io. And, of course, the password should be encrypted. Maven supports encryption. I have largely followed the below link:

https://maven.apache.org/guides/mini/guide-encryption.html

Step 1: Create a master password

Create a master password by typing:

Say, it gives you the below output:

{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=}

Create a file: ~/.m2/settings-security.xml with the following content:

Step 2: Create an encrypted password

Create the encrypted password for your docker.io user. Type:

Say, the output is:

{COQLCE6DU6GtcS5P=}

In the ~/.m2/settings.xml file, add the below lines under the servers tag.

Now, you should be all set. Use the below command to build the docker image and then push it:

Sources

A working example of this can be found here:

https://github.com/paawak/blog/tree/master/code/spring-boot-demo

Running Jetty 9 with Maven

Running Jetty through Maven is super simple. The only problem is lot of configurations were changed in Jetty 9. It is significantly different from, say, Jetty 6. I will keep it short. The below lines in pom.xml would get the job done:

Note that it defines a custom port and a context path as well.

Use the below command to run Jetty:

mvn jetty:run

The sources are available here:

https://github.com/paawak/blog/tree/master/code/simple-spring-rest

Maven: Creating deployable distribution: Part 2: creating fat jar

In the Part 1 of this, we had seen how to use the appassembler plugin to create a distribution tar. In this increment, we will see how to use the Maven assembly plugin to create a uber jar or fat jar. A uber jar or fat jar is a single jar having the contents of all the dependencies needed for the project. Again, we will be using the maven-distribution-example as reference. This project would need the project rmi-service-api to compile. We have created a profile called uber-jar:

The assembly plugin uses a pre-fabricated descriptor called jar-with-dependencies. This would condense all dependencies into the single fat jar.

Note there are 2 executions. The first one creates the uber jar and the second one takes that uber jar and the readme.txt and creates a zip file. It does this by using the below assembly descriptor (uber-jar-assembly-descriptor.xml):

The uber jar can be generated by:

mvn clean package -P uber-jar

The sources can be found here: https://github.com/paawak/blog/tree/master/code/maven-ant-assembly-example

Maven appassembler plugin: How to deal with path too long issue in Windows

Windows sucks! We all know that. Recently, I had one more reason to crib. I am using the Maven appassembler plugin to create a deployable distribution for my Rmi Server. I added a couple of more dependencies. And suddenly, the windows .bat file that is generated by the appassembler, suddenly wont launch. It was complaining that the path was too long!

Well, I visited the plugin’s home page and after struggling for 3 hrs, I was none the wiser.

Then, I chanced upon an article and with a little bit of tweaking, I was able to get it working. The trick is the following magic line:

 <useWildcardClassPath>true</useWildcardClassPath>

Before the fix

The run_rmi_server.bat looked like:

After the fix

The run_rmi_server.bat looks like:

Note that the path has been shortened by using *. This has been introduced in JDK 6: https://docs.oracle.com/javase/6/docs/technotes/tools/windows/classpath.html

Maven: Creating deployable distribution: Part 1: Using the Appassembler plugin

Context

Often, we have a standalone Java application, from which we want to create a deployable distribution having all the dependencies in one place and with a shell script or bat file which can be then invoked from the command prompt. The Mojo Appassembler plugin helps do just that. We will be using the maven-distribution-example as reference. This project would need the project rmi-service-api to compile.

Using the Appassembler plugin

We have created a profile called all-in-one which can be called to create our distribution:

This profile contains 2 parts:

  1. The appassembler plugin
    1. Collects all the maven dependencies in the target/appassembler/lib
    2. Generates the  .sh and .bat scripts to invoke the main class which is provided
  2. The maven assembly plugin which creates a tar archive from
    1. The appassembler directory
    2. readme.txt file

The maven assembly plugin works using the below assembly descriptor (all-in-one-assembly-descriptor.xml):

Next, we invoke Maven by:

mvn clean package -P all-in-one

Go to the tar file is generated in the target directory. You will find two directories inside the tar:

  1. bin: This contains the shell script and the bat file
  2. lib: This has all the dependant jars

You can now run the Rmi Server by invoking the shell or bat scripts from the prompt.

The sources can be found here: https://github.com/paawak/blog/tree/master/code/maven-ant-assembly-example

 

 

 

Invoking Ant from Maven: The Maven AntRun Plugin

Context

In my previous entries, Accessing Maven dependencies through Ant: Part 1 and Part 2 , I had been talking about how we can explore Maven dependencies from Ant. Here, we will talk about how we can do the reverse, that is, invoke Ant from within Maven. I guess this is the more common scenario of the two. Often we have encountered a legacy project which has Ant as the build tool, and we need to integrate that with Maven, often invoking the Ant’s build file from pom.xml. We will continue using our RMI Sever as an example.

We will actually use the Idiot’s paradigm © to demonstrate how to invoke Ant through Maven.

Using the Maven AntRun Plugin

Is pretty straight forward. I have created a Profile called AetherAntTaskExample, which looks like:

You invoke this by doing:

mvn clean package -P AetherAntTaskExample

The ant file is invoked and executed. The original pom.xml can be found here.

Accessing Maven dependencies through Ant: Part 2: The Aether Ant Tasks

Context

This is the 2nd increment of this series. Here is Part 1:

http://palashray.com/accessing-maven-dependencies-through-ant-part-1-the-maven-ant-tasks/

The context and the problem remains same: we want to access Maven dependencies through Ant. We will continue using the Rmi Server as an example.

What is Aether?

Aether is an API which facilitates accessing artifacts from various repositories like Maven, Nexus, Central, etc. From Maven 3 onwards, Maven is fully Aether compliant.

Disclaimer

I was not able to get Aether work on a complex Maven project having both Spring 2.x and 3.x: it invariably messes up. But with simpler modules, it seems to work fine. Though Aether is still very much bleeding edge and yet to stabilize, I believe thats the way to go, as it makes accessing artifacts language agnostic.

Using the Aether Ant Tasks

This is how my ant file build-with-aether-ant-task.xml looks like:

Invoking Ant

Use the following command:

ant -f build-with-aether-ant-task.xml -Dproject.name=rmi-server -Dproject.version=1.0

You should see a zip with all the dependencies in the target folder.

Accessing Maven dependencies through Ant: Part 1: The Maven Ant Tasks

Context

I have a project which is managed by Maven. Suppose for some reason, best know to me :), I want to do the following using Ant:

  1. Inspect the project’s dependencies
  2. Zip all the dependencies together

This can be achieved by using the Maven Ant Tasks.

Project Structure

We will take the Rmi Server as an example to demonstrate how we can access Maven dependencies in Ant through the Maven Ant Tasks.

The pom.xml looks like this:

Building the project with Ant

The following is how my ant file, build-with-maven-ant-task.xml, looks:

Invoking Ant

From the command prompt, issue the following command:

ant -f build-with-maven-ant-task.xml -Dproject.name=rmi-server -Dproject.version=1.0

In the target folder, you should see the rmi-server-1.0.zip, containing all the dependencies of the project.

 

 

The ultimate idiot’s handbook for build obfuscation

Prologue

This piece is dedicated to those demented souls, who bungle around our industry. Their only aim is to to make life complex and difficult for their co-workers. They are the Rube Goldbergs of the software industry. They have taken obfuscation and unnecessary complexity to a kind of art form. I have encountered many such instances over the years. This particular case is particularly interesting, as I spent weeks understanding the process, deciphering the actual requirements, unraveling layers upon layers of redundant and complex logic to finally come up with a workable solution.

Problem

We were using Maven 2 for our builds. I wanted to upgrade that to Maven 3. The damn thing would fail saying:

It turns out that apart from the regular Maven pom.xml, we also use an Ant build.xml.

Analysis

I ran with -X, and predictably:

I upgraded the maven ant task version, maven ant run plugin, and all that. Still no luck. I googled a bit and gathered that Maven 3.x onwards, there has been a change in how Maven interacts with its artifacts. It is now done through Aether. So, thats the reason why the maven-ant-task is not working in Maven 3.

Working with Aether-Ant

I some how managed to modify my ant script to use the AetherAntTask instead of the MavenAntTask. Everything was hunky dory, the build went fine, generated the zip with all dependencies and life was good. Till I decided to actually deployed the build. And thank my lucky stars that I did it. Though the build went fine, the application wont start. Apparently Aether messed up with some Spring dependencies which we working fine with the earlier MavenAntTask. It turns out Aether is still bleeding edge.

Solution

I had actually given up. Then after a couple of weeks, I was thinking about this problem again, and I spotted something very odd. The overall interaction looked something like this:

Existing build flow
Existing build flow

I am outlining the steps below:

  1. The build is kicked off by Maven
  2. Maven does the compilation, and also builds the jar out of the project. After that, it invokes Ant’s build.xml through the MavenAntPlugin
  3. Ant needs to access the Maven dependencies.  It does this trough the MavenAntTask or the AetherAntTask. Thereafter, it zips all these dependencies into a single archive.
  4. Maven picks up this zipped archive from Ant and all is good

What is odd here, is the fact that Maven already knows its own dependencies. So, why does it need to outsource that to Ant? That, I thought was the real obfuscation. I modified the flow as below:

  1. The build is kicked off by Maven
  2. Maven does the compilation, and also builds the jar out of the project.
  3. Before calling the Ant’s build.xml, Maven copies all its dependencies to a predefined directory using the Application Assembler plugin
  4. After that, it invokes Ant’s build.xml through the MavenAntPlugin
  5. Ant does not need to know Maven dependencies, as its already copied in a predefined directory. Ant zips all these dependencies from the predefined directory into a single archive.
  6. Maven picks up this zipped archive from Ant and all is good

I modified my pom.xml and build.xml according to the new strategy, and all worked fine! I was finally able to migrate to Maven 3.