Friday, November 15, 2013

Beginner's guide to using Maven

I have been trying to convince a fellow Engineer for a long time that Maven is this great build tool that he needs to start using ASAP and is much more than just a replacement to ANT. He finally gave it a try and came back SCREAMING!!!

Why was he Screaming?

He was using Maven in the wrong way

Why is Maven this great tool?

In my opinion it is a great tool because it handles library dependancies on your behalf. Whenever I build a new application, I do not need to scan my hard drive for libraries and then add it to my IDE project classpath. 

I worked in an organisation that had a cool way of handling this situation using ANT. Everyone worked on a specified "workspace" structure. There were scripts that created the structure for you. The workspace contained libraries, scripts and slots. You developed in a slot and referenced libraries in your workspace/libraries folder. The libraries and scripts were all stored in a source control repository. This meant that if you had to use a new library, you would need to download it from the internet, commit it to the code repository, run an update on your workspace and reference it in your ant scripts.

It worked like a charm if you understood the process behind the madness. In a nutshell I found Maven to this ALL for you out-of-the-box. Let me not undersell this tool(Maven). This is but just one of its cool features (Dependancy Management). 

Why do people think that MAVEN is rubbish?

I have promoted Maven and managed to convince developers to start using it. They did and the part that was meant to help them, turned out to be the monster. The dependancy management was a mess.

This made me wonder how could a tool be great for some people and at the same time be a disaster for others?

I soon realised that there are actually 2 ways of using Maven:
  1. Self Development using Maven
  2. Group Development using Maven

Self Development using Maven

If you are a developer who flies solo, then just download Maven and you are good to go.

What is happening behind the scenes?

When you run Maven for the first time, it creates a local cache folder for you. This is located in your user directory and is called ".m2".

Unix:
 /Users/<user_name>/.m2  

Windows:
 C:\Users\<user_name>\.m2  

If you look into this folder you will find:

  • A settings.xml file which should not concern you at this time
  • A repository folder which contains dependencies that you used to build your projects

How do these dependancies end up here?

When you compile or build your code using Maven; Maven first checks that the dependancy exists in your local cache. If not, it connects to the internet and searches for the dependancy on the Maven Central Repository. If it finds the dependancy, it downloads it to your local cache. If not, it searches on the other repositories that the Maven Central repository is connected to or references. You should be able to download most of the libraries in this way.

Let us consider 2 other possible scenarios:

1. The dependancy required is another project of yours. It is a completely separate project and you have decided not to include it as a module within your current project. If this second project; which is a dependancy to your first project is a maven project then, by running: 
 mvn install  
you will not only build and compile the project but it also installs the output artefacts of each of the modules to your local cache.

2. The dependancy may or not be another project of yours. If it is your project and it is not in a Maven structure, then building or installing the project will have no value. The only thing you do have is the built library(jar). You can install this library manually into you local cache by running: 
 mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> -DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=<packaging>  

You can then add this dependancy details into your Maven POM(Project Object Model) file.

What is the Maven Central Repository? 

The Maven Central Repository is a Maven Artefact Repository hosted on the Internet that contains most of the common or often used java libraries. It some cases it is hosted on the Maven Central Repository and in other cases it references other Maven Artefact Repositories that hosts libraries themselves.

The above point is very interesting. I am saying that not only does a Maven Artefact Repository host libraries but it can also reference other Maven Artefact Repositories which has the same capability. This is huge!!! I guess you can call it chaining.

To summarise, this is what happens step by step:

Step 1 - Look for dependency in local cache, if not found, step 2 else if found then complete build process.
Step 2 - Look for dependency in Maven Central Repository, if not found then step 3 else if found, then it is downloaded to local cache.
Step 3 - Look for  dependency in remote repository or repositories, if found then it is downloaded to local cache otherwise Maven as expected stops processing and throws an error (Unable to find dependency).

Group Development using Maven

If you have a clear understanding of the above, you will by now have gathered why the above setup will not work for group development. Okay, it can work to some degree but it will be a mission!

The problem with the above setup is that every Developer in the group would need to manually add libraries into their local cache's when required. This can become tedious, error prone and amateur.

What can we do to solve this?

The answer is to install a Maven Artefact Repository for the organisation. I recommend using Sonatype Nexus. This is a dead simple installation. 

How to Install Nexus Artefact Repository

  • Download the latest war file
  • Deploy it on a Tomcat instance
  • Make sure that it can connect to the internet. You can check this by selecting Repositories and then checking that the Repository status is "In Service".

  • You might have to configure Proxy settings, if you connect to the internet via a Proxy Server. The default username is admin and the password is admin123. you can configure the proxy in the Administration --> Server settings

  • You will also need to enable a "Deployment" user. This user should have the ability to deploy or install artefacts to the Artefact Repository. Take notice of the roles applied here.
 

  • The next step is to get Maven to reference your newly configured Artefact Repository.
You can achieve this by configuring the "settings.xml" file. You can place this file in MAVEN_HOME/conf directory or .m2 directory. Maven first reads configuration from the .m2 location and if its not found it looks for the "settings.xml" file in the MAVEN_HOME/conf location.  

Getting Maven to call your own Artefact Repository

Use this as a temple and customise where necessary(You only need to change the deployment username & password and the host & port for this template to work):
1:  <?xml version="1.0" encoding="UTF-8"?>  
2:  <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"   
3:       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
4:       xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">  
5:   <pluginGroups>  
6:   </pluginGroups>  
7:   <proxies>  
8:   </proxies>  
9:  <!-- This is used when deploying or publishing to the Artefact Repository  
10:     The user must exist and must have deploy rights -->  
11:   <servers>  
12:       <server>  
13:            <id>snapshots</id>  
14:            <username>deployment</username>  
15:            <password>password</password>  
16:       </server>  
17:     <server>  
18:            <id>releases</id>  
19:            <username>deployment</username>  
20:            <password>password</password>  
21:       </server>  
22:       <server>  
23:            <id>milestones</id>  
24:            <username>deployment</username>  
25:            <password>password</password>  
26:       </server>  
27:       <server>  
28:            <id>thirdparty</id>  
29:            <username>deployment</username>  
30:            <password>password</password>  
31:       </server>  
32:   </servers>  
33:   <mirrors>  
34:    <mirror>  
35:     <id>public</id>  
36:     <mirrorOf>*</mirrorOf>  
37:     <name>Public Repositories</name>  
38:     <url>http://host:port/nexus/content/groups/public</url>  
39:    </mirror>   
40:   </mirrors>  
41:   <profiles>  
42:       <profile>  
43:     <id>custom-repository</id>  
44:     <repositories>  
45:      <repository>  
46:       <id>custom-repository-group</id>  
47:       <name>Custom Maven Repository Group</name>  
48:       <url>http://host:port/nexus/content/groups/public</url>  
49:       <layout>default</layout>  
50:       <releases>  
51:        <enabled>true</enabled>  
52:        <updatePolicy>always</updatePolicy>  
53:       </releases>  
54:       <snapshots>  
55:        <enabled>true</enabled>  
56:        <updatePolicy>always</updatePolicy>  
57:       </snapshots>  
58:      </repository>  
59:     </repositories>  
60:     <pluginRepositories>  
61:      <pluginRepository>  
62:       <id>custom-repository-repository-group</id>  
63:       <name>Custom Maven Repository Group</name>  
64:       <url>http://host:port/nexus/content/groups/public</url>  
65:       <layout>default</layout>  
66:       <releases>  
67:        <enabled>true</enabled>  
68:        <updatePolicy>always</updatePolicy>  
69:       </releases>  
70:       <snapshots>  
71:        <enabled>true</enabled>  
72:        <updatePolicy>always</updatePolicy>  
73:       </snapshots>  
74:      </pluginRepository>  
75:             <pluginRepository>  
76:         <id>public</id>  
77:          <url>http://host:port/nexus/content/groups/public</url>  
78:           <snapshots>  
79:             <enabled>true</enabled>  
80:           </snapshots>  
81:                      <releases>  
82:                           <enabled>true</enabled>  
83:                           <updatePolicy>always</updatePolicy>  
84:                      </releases>  
85:        </pluginRepository>  
86:     </pluginRepositories>  
87:    </profile>  
88:   </profiles>  
89:   <activeProfiles>  
90:    <activeProfile>custom-repository</activeProfile>  
91:   </activeProfiles>  
92:  </settings>  

If you require further clarity I guess the Official Maven Site does have more information.

Once you have all this in place, you have modified the process mentioned above to the following:
Step 1 - Look for dependency in local cache, if not found, step 2 else if found then complete build process.
Step 2 - Look for dependency in the Custom Maven Repository, if not found then step 3 else if found, then it is downloaded to local cache.
Step 3 - Look for  dependency in remote repository or repositories, if found then it is downloaded to local cache otherwise Maven as expected stops processing and throws an error (Unable to find dependency).
This looks almost the same barring the fact that we are now referencing our own Artefact Repository instead of the Maven Central Artefact Repository. 

What if you wish to download an Artefact that is not referenced by the Maven Central Repository or your own Repository

Consider these scenarios:
  • You organisation is huge and you require a library from another section or department that hosts their own Artefact Repository.
  • You require a library from a Maven Artefact Repository hosted online.
Just add it as a another Hosted Repository on Nexus:

What are the advantages of Hosting your own Artefact Repository

  • Saving Bandwidth (It only downloads the artefact from the internet once. When request again the call does not go over the internet)
  • Control over libraries used
  • Building a standard for all Developers
  • Storing Organisation specific Milestones and Releases

Why do I need to configure a Deployment user on Nexus

This is to store your own custom Organisation specific Milestones and Releases (libraries). You can upload these custom libraries in the following ways:
  1. Using the Maven Release plugin, when creating a Release or Milestone. Check out this tutorial 
  2. Upload the Artefact to Maven manually via the front end

Conclusion

I strongly believe that Maven and an Artefact Repository go together like toothpaste & a toothbrush. You can use them separately but to get the most benefit, you got to combine them even if you are flying solo.

If you are adding dependancy libraries to your project in any other way than specifying them in your POM file, you are using Maven in the wrong way!

As always, I would love to hear some of your comments or questions. I can also provide my services if you require.

  




No comments:

Post a Comment