Google

Jul 18, 2014

Which Jar has a particular class? or from which jar a class was loaded? solving jar hell issues

The following 3 questions are frequently asked by Java developers as an industrial strength Java project will have 100+ jar files. How often have you come across a Java application that requires different versions of the same library? How often do you see exceptions like NoSuchMethodError or IllegalArgumentException. Here are some tips to solve the JAR hell problem. These 6 tips will go a long way in resolving your jar problems.

Q1. Which Jar has a particular class?

Tip#1: go to findJAR.com and search for the class file. For example, I want to find the jar file that has org.apache.commons.io.FileUtils



You can drill through to find a Maven download link.




Tip#2: Unix command "find" and grep

find ./lib -name "*.jar" -exec sh -c 'jar -tf {}|grep -H --label {} 'org.apache.commons.io.FileUtils'' \;




Tip#3: In Windows or DOS

 
for %i in (*.jar) do @jar tvf %i | find "org/apache/commons/io/FileUtils.class"



Q2. from which jar a class was loaded?

Tip#4. To identify from which jar a particular class was loaded from, add the following snippet of code to  a location where it gets executed.

   Class klass = org.apache.commons.io.FileUtils.class;

   CodeSource codeSource = klass.getProtectionDomain().getCodeSource();

    if ( codeSource != null) {
        System.out.println(codeSource.getLocation());
    }


At run time it will print the jar file from which "FileUtils" was loaded.

package test;

import java.security.CodeSource;

public class WhichJarLoadedTest {

 public static void main(String[] args) {
  Class klass = org.apache.commons.io.FileUtils.class;

  CodeSource codeSource = klass.getProtectionDomain().getCodeSource();

  if (codeSource != null) {
   System.out.println(codeSource.getLocation());
  }
 }

}


Output:

 file:/C:/Users/akumaras/workspace/WtsPlayProject/lib/commons-io-2.4.jar
 

 Q3. Why commons-io version 2.1 was chosen over version 2.4?


Tip #5: In Maven, due to its transitive dependencies behavior, multiple versions of same jar could be pulled in. You need to determine which jar is bringing in the this duplicate or wrong version of the jar and exclude it in the pom.xml file. The verbose flag instructs the dependency tree to display conflicting dependencies that were omitted from the resolved dependency tree. For example, to see why commons-io 2.0 was chosen over commons-io 2.4

  mvn dependency:tree -Dverbose -Dincludes=commons-io
  
The 3 handy commands to solve jar hell issues in maven are mvn dependency:tree, mvn dependency:analyze, and mvn help:effective-pom. The IDEs like eclipse provide tools to analyze dependencies. In eclipse, double click on a pom.xml file, and then select the "Dependency Hierachy" tab to analyze why a particular jar was chosen.

<dependency>
 <groupId>org.jboss.resteasy</groupId>
 <artifactId>resteasy-jaxrs</artifactId>
 <version>${resteasy.version}</version>
</dependency>



commons-io-1.4 is a very old version. Now to to exclude older version and include commons-io-2.4, you need to do the following in the pom.xml file.

  
<dependency>
 <groupId>org.jboss.resteasy</groupId>
 <artifactId>resteasy-jaxrs</artifactId>
 <version>${resteasy.version}</version>
 <exclusions>
      <exclusion>
          <groupId>commons-io</groupId>
          <artifactId>commons-io</artifactId>
      </exclusion>
 </exclusions> 
</dependency>
<dependency>
        <groupId>commons-io</groupId>
     <artifactId>commons-io</artifactId>
     <version>2.4</version>
</dependency>




Tip #6:  uber-jar is an "over-jar", and uber is the German word for above or over. uber-jar is defined as one that contains both your package and all its dependencies in one single JAR file (Note: jars cannot have other jars). The advantage is that you can distribute your uber-jar and not care at all whether or not dependencies are installed at the destination, as your uber-jar actually has no dependencies. Maven has a plugin known as the "Apache Maven Shade Plugin".

 This plugin can also be used in scenarios where you are using two jars X and Y. Y is a library and X has classes that uses some old classes from library Y with same names causing a jar hell issue.  You can solve your problem by renaming the package of the class that you don't want.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
        <phase>package</phase>
        <goals>
            <goal>shade</goal>
            </goals>
        <configuration>
                <relocations>
                    <relocation>
                            <pattern>com.myapp.MyClass</pattern>
                               <shadedPattern>com.myapp.rename.MyClass</shadedPattern>
                    </relocation>
                </relocations>
                    <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
        </configuration>
        </execution>
    </executions>
</plugin>


Labels: ,

Jul 13, 2014

Maven with Nexus for distribution management

Q. What is Nexus?
A. Nexus is a central repository manager that stores and organizes binary software components for use in development, deployment, and provisioning. Nexus becomes the deployment destination for the components that are created by your organization using Maven.

  • You can publish your own library or project JARs, WARs, EARs etc. both sanapshot and release versions using Nexus Pro. 
  • You can host your own repository to support your custom components and share those components with other users or computers on your network. 
  • Once your components are placed in the repository - they can be made available to all developers securely using access controls and SSL.
  • You can search for artifacts.




Q. How to configure maven to publish artifacts to Nexus?
A. To configure a Maven project to publish artifacts to Nexus, you'll need to add a distributionManagement element to your project's pom.xml.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mycompany</groupId>
    <artifactId>mycompany-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <distributionManagement>
        <snapshotRepository>
            <id>mycompany-snapshots</id>
            <name>mycompany Snapshots</name>
            <url>http://myhost:8080/nexus/content/repositories/mycompany-snapshots</url>
            <uniqueVersion>true</uniqueVersion>
        </snapshotRepository>
  <repository>
            <id>mycompany-releases</id>
            <name>mycompany Releases</name>
            <url>http://myhost:8080/nexus/content/repositories/mycompany-releases</url>
        </repository>
    </distributionManagement>

</project>


The child projects or modules will refer to the parent project

<parent>
  <groupId>com.mycompany</groupId>
  <artifactId>mycompany-parent</artifactId>
  <version>1.0.0</version>
</parent>


If your Nexus server requires authentication, you will also need to place your credentials in ~/.m2/settings.xml in a servers element.

<servers>
  <server>
    <id>deployment</id>
    <username>deployment</username>
    <password>deployment123</password>
  </server>
</servers>


Once you've configured your project's pom.xml and your Maven Settings, you can deploy your project with

mvn deploy


which will execute the build up to the deploy phase. When you run a deploy with a project that has a snapshot version, Maven will deploy to the repository defined in snapshotRepository, and when you run a build with a project that has a release version it will deploy to the repository defined in the repository element.


Q. What is the difference between snapshot versions and release versions?
A. The "SNAPSHOT" term means that the build is a snapshot of your code at a given time, which means downloading 1.0-SNAPSHOT  today might give a different file than downloading it yesterday or tomorrow. When you are ready to release your project, you will change 1.0-SNAPSHOT to 1.0 in the pom.xml file. The 1.0 is the release version. After release, any new developmwent work will stat using  1.1-SNAPSHOT and so on.

Labels:

Jul 12, 2014

Maven assembly plugin example

Maven assembly plugin is primarily intended to allow users to aggregate the project output along with its dependencies, modules, site documentation, and other files into a single distribution archive like zip, tar, tar.gz, war, etc. Another example where this is handy is to create deployable files for different environments like myapp-1.10-SNAPSHOT-dev.zip, myapp-1.10-SNAPSHOT-test.zip, and myapp-1.10-SNAPSHOT-prod.zip where each containing environment related properties files packaged.

3 steps to create an assembly

  1. choose or write the assembly descriptor files to use like dev-assembly.xml, prod-assembly.xml, etc
  2. configure the Assembly Plugin in your project's pom.xml, and include the above descriptor files
  3. run "mvn assembly:single" on your project.


For example:

The pom.xml file

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.app/groupId>
 <artifactId>myapp</artifactId>
 <packaging>war</packaging>
 <name>myapp</name>
 <version>1.10-SNAPSHOT</version> 
 
 ...
 
 <plugins>
     ....
     <plugin>
   <artifactId>maven-assembly-plugin</artifactId>
   <version>2.2.1</version>
   <executions>
    <execution>
     <id>assemble</id>
     <phase>package</phase>
     <configuration>
      <descriptors>
       <descriptor>assembly/dev-assembly.xml</descriptor>
       <descriptor>assembly/test-assembly.xml</descriptor>
       <descriptor>assembly/prod-assembly.xml</descriptor>
      </descriptors>
     </configuration>
     <goals>
      <goal>single</goal>
     </goals>
    </execution>
   </executions>
  </plugin>
 
 
 <plugins>
 
 ....
</project>


Now the dev-assembly.xml file

<assembly
 xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 
 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
 <id>dev</id>
 <includeBaseDirectory>false</includeBaseDirectory>
 <formats>
  <format>zip</format>
 </formats>
 <fileSets>
  <fileSet>
   <directory>config/dev</directory>
   <outputDirectory>/app-properties</outputDirectory>
  </fileSet>
  <fileSet>
   <directory>jboss-config/dev/deploy</directory>
   <outputDirectory>/ds</outputDirectory>
  </fileSet>
 </fileSets>
 <files>
  <file>
   <source>jboss-config/common/myapp-container.properties</source>
   <outputDirectory>/myapp-container-properties</outputDirectory>
   <destName>my-app-dev.properties</destName>
  </file>
 </files>
</assembly>


The prod environment prod-assembly.xml will have something like

<assembly
 xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 
 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
 <id>prod</id>
  <includeBaseDirectory>false</includeBaseDirectory>
 <formats>
  <format>zip</format>
 </formats>
 <fileSets>
  <fileSet>
   <directory>config/prod</directory>
   <outputDirectory>/app-properties</outputDirectory>
  </fileSet>
  <fileSet>
   <directory>jboss-config/prod/deploy</directory>
   <outputDirectory>/ds</outputDirectory>
  </fileSet>
 </fileSets>
 <files>
     <file>
      <source>jboss-config/common/myapp-container.properties</source>
      <outputDirectory>/container-properties</outputDirectory>
      <destName>my-app-prod.properties</destName>
    </file>
   </files>
</assembly>


The main goal in the assembly plugin is the single goal. It is used to create all assemblies.

Now to generate different packages like myapp-1.10-SNAPSHOT-dev.zip, myapp-1.10-SNAPSHOT-test.zip, and myapp-1.10-SNAPSHOT-prod.zip

mvn package


Labels:

Jul 11, 2014

Difference between Maven snapshot and release versions

Q. What is the difference between snapshot versions and release versions?
A. The term "SNAPSHOT" means the build is a snapshot of your code at a given time, which means downloading 1.0-SNAPSHOT  today might give a different file than downloading it tomorrow or day after. When you are ready to release your project, you will change 1.0-SNAPSHOT to 1.0 in the pom.xml file. The 1.0 is the release version. After release, any new development work will stat using 1.1-SNAPSHOT and so on.

"SNAPSHOT" also means unstable version. Unlike regular versions, Maven checks for a new SNAPSHOT version in a remote repository at least once a day by default or if you use -U flag to every time you build. A team working on a cash-service module will release SNAPSHOT of its updated code every day to repository - let's say cash-service:1.0-SNAPSHOT replacing an older cash-service:1.0-SNAPSHOT jar. In case of released versions, if Maven once downloaded the version say cash-service:1.0, it will never try to download a newer 1.0 available in repository. In order to download the updated code, the cash-service version needs to be upgraded to 1.1.

When you release artifacts to nexus, you can have a snapshotRepository and a repository for the releases.

 <distributionManagement>
        <snapshotRepository>
            <id>mycompany-snapshots</id>
            <name>mycompany Snapshots</name>
            <url>http://myhost:8080/nexus/content/repositories/mycompany-snapshots</url>
            <uniqueVersion>true</uniqueVersion>
        </snapshotRepository>
        <repository>
            <id>mycompany-releases</id>
            <name>mycompany Releases</name>
            <url>http://myhost:8080/nexus/content/repositories/mycompany-releases</url>
        </repository>
    </distributionManagement>


Q. Why do you need a SNAPSHOT version?
A. If a team working on a cash-service jar module keeps uploading a new version every other day, the other teams that depend on this cash-service module

  1. Need to be regularly notified so that they can update their pom.xml file to use the newer version.
  2. In large projects, it is not easy to keep communicating these version changes. Using the older versions can cause unforeseen build issues

If you have a "SNAPSHOT" version that regularly gets overridden by the team that is making the regular changes and the team that depends on the  cash-service module will also get their local repositories updated and use the latest code. This will alleviate the above 2 problems.


Q. Do you have control over the snapshot versions?
A. Yes.

For example, a cash-service-1.0.jar library is considered as a stable version, and if Maven finds it in the local repository, it will use this one for the current build.

Now, if you need a cash-service-1.0-SNAPSHOT.jar library, Maven will know that this version is not stable and is subject to changes since it a SNAPSHOT. So, Maven will try to find a newer version in the remote repositories, even if a version of this library is found on the local repository. However, this check is made only once per day by default, but you can modify this update policy.

<repository>
    <id>central</id>
    <url>...</url>
    <snapshots>
        <enabled>true</enabled>
        <updatePolicy>always</updatePolicy>
    </snapshots>
</repository>

The other possible updatePolicy values are daily (i.e. default), interval:30 (every 30 minutes), and never.

  • always: Maven will check for a newer SNAPSHOT version on every build.
  • daily: Once a day (this is the default unless you use -U flag with mvn clean package -U)
  • interval:XXX: an interval in minutes (XXX)
  • never: Maven will never try to retrieve another version from the remote repository. It will do that only if it doesn't exist locally. The SNAPSHOT version will be handled as the stable version.




You can also turn off this by setting enabled to false.

Even though Maven automatically fetches the latest SNAPSHOT on a daily basis by default, you can force maven to download latest snapshot build using -U switch to any maven command.

 mvn clean package -U


Labels:

Jun 19, 2014

Maven interview questions and answers

Q. What is the difference between a reactor pom and a parent pom?
A. The mechanism in Maven that handles multi-module projects is referred to as the reactor. A reactor pom is a pom.xml file you define with <modules>, and Maven will read all of these modules and build then in the correct order based on dependencies.

A parent pom is a pom from which other poms inherit via a <parent> section. Poms that inherit from a parent are referred to as “child poms.” There are different types of parent poms.



Q. How do you handle multi-module projects in Maven?
A. A multi-module project is defined by a parent POM referencing one or more sub modules. You can have different structures like

Approach 1. parent pom is in the project root

myproject/
  myproject-client/
  myproject-model/
  myproject-services/
  pom.xml


Approach 2. separate project for the parent pom

myproject/
  mypoject-parent/
    pom.xml
  myproject-client/
  myproject-model/
  myproject-services/



The parent pom.xml will define the modules that needs to be aggregated

<project xmlns="....">
 <description>MyApp</description>
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.myapp</groupId>
 <artifactId>myproject</artifactId>
 <version>1.0.0-RC1.0-SNAPSHOT</version>
 <packaging>pom</packaging>
 <name>MyProject</name>
    
    <scm>
        <url>http://sdlc/svn/myapp/myproject/trunk/</url>
        <connection>scm:svn:http://sdlc/svn/myapp/myproject/trunk</connection>
        <developerConnection>scm:svn:http://sdlc/svn/myapp/myproject/trunk</developerConnection>
    </scm>

 <modules>
  <module>model</module>
  <module>client</module>
  <module>services</module>
    </modules>
 
       
    .....
</project>


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="ns">
 <modelVersion>4.0.0</modelVersion>
 <artifactId>myproject-model</artifactId>
 <name>MyProject Model</name>
 <packaging>jar</packaging>
 <parent>
  <groupId>com.myapp</groupId>
  <artifactId>myproject</artifactId>
  <version>1.0.0-RC1.0-SNAPSHOT<</version>
        <relativePath>../pom.xml</relativePath>
 </parent>
 
    ...
</project>




Q. Which approach do you favor?
A. Approach 1 is the is the default maven convention for multi-module projects, and the intention is to be scalable to a large scale build.  If parent pom has its own life cycle, and if it can be released separately of the other modules, then approach 2 may be an option.

Q: What are the different aspects managed by Maven in the SDLC?
A: SCMs (Source control), Dependencies (i.e transitive dependencies), Builds, Releases, Documentation, and Distribution.

Q. What is the difference between "Dependency Management" and "Dependencies" as shown below in poms?

Parent pom with version defined
  
<dependencyManagement>
 <dependencies>
 
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>3.0.1</version>
   <scope>provided</scope>
  </dependency>
  
 </dependencies>
</dependencyManagement>


and child pom with no version.
       
<dependencies>
  
 <dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <scope>provided</scope>
 </dependency>
  
</dependencies>      


A. Dependency Management allows to consolidate and centralize the management of dependency versions without adding dependencies which are inherited by all children. It will be a a maintenance night-mare to change version numbers of all child poms in a large commercial project. dependencyManagement allows you to define a standard version of an artifact to use across multiple projects.

Q. What format does a maven repository use to uniquely identify an artifact in its repository?
A. [groupId]-[artifactId]-[version]-[classifier].[type]

groupId:  e.g. com.myapp
artifactId:  e.g. myproject
version: e.g. 1.0.0-RC1.0-SNAPSHOT
classifier:  e.g. sources, javadocs, bin and bundle (default: no classifier)
type:  pom,jar,war,ear (default is jar)


Q. What is an "attached artifact" and why would you need a "classifier"?
AAttached artifacts are additional related artifacts that get installed and deployed along with the “main” (e.g jar, war, or ear) artifact. These are most often, javadocs, sources, resouce bundles, properties files, etc, but can actually be any file.

Attached artifacts automatically share the same groupId, ArtifactId and version as the main artifact but they are distinguished with an additional Classifier field.

You may like:


Labels:

Apr 10, 2013

Maven - setting up profiles and tokenizing properties file

Maven is a popular build tools and often you have a requirement to tokenize the name/value pairs in a properties file so that right values can be substituted depending on for which environment (local, dev, test, uat, prod) you are building the package for.


For example, your properties file (portal.properties) under DEV environment might look like


portal.rest.path.accounts=@PORTAL_REST_PATH_ACCOUNT_SERVICE@
portal.rest.path.tax=@PORTAL_REST_PATH_TAX_SERVICE@
portal.logout.url=@PORTAL_LOGOUT_URL@


The values within "@" are tokens that needs to be replaced at build time. The properties files reside under src/main/resources folder as per the Maven structure.Here is a sample DEV resource myapp.properties that sits under /env/dev folder.

PORTAL_REST_PATH_ACCOUNT_SERVICE=http://DEV-1:8080/accounts_service
PORTAL_REST_PATH_TAX_SERVICE=http://DEV-1:8080/tax_service
PORTAL_LOGOUT_URL=https://smlogin-dev.myapp.net/siteminderagent/ssologout/Logout.html


Next step is to configure the pom.xml file in Maven. This is done via the profiles as shown below.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

   ....

    <profiles>
  
  <profile>
   <id>dev-tomcat</id>
   <build>
    <resources>
     <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
     </resource>
    </resources>
    <filters>
     <filter>env/dev/myapp.properties</filter>
    </filters>
   </build>
  </profile>
 </profiles>
 
 ....
 
</project>


    <build>
  <resources>
   <resource>
    <directory>src/main/resources</directory>
    <filtering>true</filtering>
   </resource>
  </resources>
 </build>


You also need to turn filtering on as shown below in the pom file.



Finally, you can invoke this profile with the -P option in the mvn command.

clean install tomcat:run -Dmaven.tomcat.port=8080 -Pdev-tomcat




There 3 types of Maven profiles.

  • Per Project profile: Defined in the pom.xml file as shown above.
  • Per User profile: Defined in Maven settings.xml file under %USER_HOME%/.m2
  • Global profile: Defined in Maven global settings.xml file under %M2_HOME%/conf/

and these profiles can be activated a number of ways

1. Via command line with -P option as shown above.

2. You can activate it via the Maven settings.xml file as shown below


<settings xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
   http://maven.apache.org/xsd/settings-1.0.0.xsd">
   <mirrors>
      <mirror>
         <id>maven.dev.snaponglobal.com</id>
         <name>Internal Artifactory Maven repository</name>
         <url>http://repo1.maven.org/maven2/</url>
         <mirrorOf>*</mirrorOf>
      </mirror>
   </mirrors>
   <activeProfiles>
      <activeProfile>dev-tomcat</activeProfile>
   </activeProfiles>
</settings>
 
All you have to do is type mvn install and the dev-tomcat profile will be kicked off

3. Via environment variables.

<profile>
   <id>dev-tomcat</id>
   <activation>
      <property>
         <name>env</name>
         <value>dev-tomcat</value>
      </property>
   </activation>
</profile>


4. Via operating system (OS)

<profile>
   <id>test</id>
   <activation>
      <os>
         <name>Windows </name>
         <family>Windows</family>
         <arch>x86</arch>
         <version>6.1<version>
      </os>
   </activation>
</profile>

5. Based on a missing file


<profile>
   <id>test</id>
   <activation>
      <file>
         <missing>target/generated-sources/wsdl</missing>
      </file>
   </activation>
</profile>


Q. Can you give an example where you used a profile?
A. Firstly, to tokenize properties as demonstrated in the beginning of the post. Secondly, in local development you set up a datasource for your tomcat server to use as shown below.

    
 <profiles>
  <!-- Used for running tomcat locally to do application testing by substituting 
   tokenized variables from a properties file-->
  <profile>
   <id>dev-tomcat</id>
   <build>
    <resources>
     <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
     </resource>
    </resources>
    <filters>
     <filter>src/main/filters/myapp.properties</filter>
    </filters>
    <plugins>
     <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>tomcat-maven-plugin</artifactId>
      <configuration>
          <!-- define your datasource here-->
       <contextFile>src/main/resources/tomcat-maven-plugin/context.xml</contextFile>
      </configuration>
     </plugin>
    </plugins>
   </build>
  </profile>
 </profiles>


The context.xml file will look like

<?xml version="1.0" encoding="ISO-8859-1"?>
<Context>
 <Resource
  name="jdbc/myapp_ds"
  type="javax.sql.DataSource"
  driverClassName="com.sybase.jdbc3.jdbc.SybDataSource"
  auth="Container"
  username="aes_service"
  password="service1"
  url="jdbc:sybase:Tds:myserver:5500/my_db?applicationname=myapp"
  initialSize="5"
  maxActive="5"
  maxIdle="1"
  minIdle="0"
  validationQuery="my_validateQuery"
  testOnBorrow="true"
  testOnReturn="false"
  testWhileIdle="false"
  poolPreparedStatements="false"
  removeAbandoned="false"
  logAbandoned="false"
   />
</Context>


Labels: ,

Oct 6, 2011

Maven interview questions and answers - inheritance vs aggregation



Q: How do you inherit dependencies or plugins  in Maven? How are sub modules aggregated?
A:

In Maven Inheritance, you will have a multi-module maven project where a centrally managed POM file contains all the “approved” versions of artifacts.  In this “parent” pom was a “dependencyManagement” section with all the preferred versions of libraries within the organization. When you build a child of this parent, Maven will retrieve this parent to merge the parent pom with the child pom. You can have a look to the entire pom.xml by running the command mvn help:effective-pom. This parent pom is also known as the reactor pom. The child modules like myproject-ui, myproject-security, etc will be inheriting the versions from the parent.

Like "dependencyManagement" the "pluginManagement" in parent contains plugin elements intended to configure child project builds that inherit from this one. However, this only configures plugins that are actually referenced within the plugins element in the children. The children have every right to override pluginManagement definitions.

As shown below, the child modules are aggregated. The principle is that every command that you run on on the parent (i.e. reactor pom) will also be run on all the sub-modules. The order of the modules will be defined by the Reactor, which will look at inter-modules dependencies to find which module must be built before the others. If there are no dependencies, then it will take the list of the modules as they are defined in the parent pom.xml.

Parent pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.myproject</groupId>
 <artifactId>myproject-parent-build</artifactId>
 <packaging>pom</packaging>
 <version>${myproject.version}</version>
 <name>${project.artifactId}</name>
 <url>http://www.myorganization.com</url>

 <properties>
     <myproject.version>1.0.0</myproject.version>
  <seam.version>2.2.2.Final</seam.version>
  ...
 </properties>

 <dependencyManagement>
  <dependencies>
   <!-- jboss seam dependencies -->
   <dependency>
    <groupId>org.jboss.seam</groupId>
    <artifactId>jboss-seam</artifactId>
    <version>${seam.version}</version>
   </dependency>
   ...
  </dependencies>
 </dependencyManagement>

 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.1</version>
    <configuration>
     <source>1.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>
   ...
  </plugins>

  <pluginManagement>
   <plugins>
    <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <version>2.1</version>
     <configuration>
      <source>1.6</source>
      <target>1.6</target>
     </configuration>
    </plugin>
    ...
   </plugins>
  </pluginManagement>
 </build>

 ...

 <modules>
  <module>myproject-security</module>
  <module>myproject-content</module>
  <module>myproject-data</module>
  <module>myproject-ui</module>
  <module>myproject-analytics</module>
 </modules>
 
</project>



Child pom.xml . The parent tag defines the parent to inherit form.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.myproject</groupId>
 <artifactId>myproject-ui</artifactId>
 <version>${myproject.version}</version>
 <packaging>war</packaging>
 <name>${project.artifactId}</name>
 <url>http://www.myorganization.com</url>
 <parent>
  <groupId>com.myproject</groupId>
   <artifactId>myproject-parent-build</artifactId>
  <version>${myproject.version}</version>
 </parent>

 <build>
  <finalName>cashonline</finalName>

  <pluginManagement>
   <plugins>
    <plugin>
     ...
    </plugin>
    ...
   </plugins>
  </pluginManagement>
 </build>

 <dependencies>
  <dependency>
   <groupId>org.jboss.seam</groupId>
   <artifactId>jboss-seam</artifactId>
   <exclusions>
    <exclusion>
     <groupId>javax.el</groupId>
     <artifactId>el-api</artifactId>
    </exclusion>
   </exclusions>
  </dependency>
  
  ...

 </dependencies>

 
</project>


Q. Is this inheritance of dependencies a good idea?
A. It is a good idea when you only have say 5-10 sub modules (i.e. child modules). But, if you have 50+ child modules inheriting from the parent dependency management or plugin management will cause a re-release of anything inheriting from it. For example, if you have 20+ projects inheriting org.jboss.seam jar, and if that jar goes from 2.2.2.Final to 2.3, then you will have to re-release the 20+ projects inheriting from it. It appears that as of version 2.0.9, there is a new scope on a dependency called import to aggregate dependencies without inheriting them.

The example below shows aggregation without the parent tag. The scope "import" aggregates the "myproject-parent-build".

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.myproject</groupId>
 <artifactId>myproject-ui</artifactId>
 <version>${myproject.version}</version>
 <packaging>war</packaging>
 <name>${project.artifactId}</name>
 <url>http://www.myorganization.com</url>
 
 <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.myproject</groupId>
                <artifactId>myproject-parent-build</artifactId>
                <version>${myproject.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
             ....
        </dependencies>
    </dependencyManagement>
 
 
 <dependencies>
  <dependency>
   <groupId>org.jboss.seam</groupId>
   <artifactId>jboss-seam</artifactId>
   <exclusions>
    <exclusion>
     <groupId>javax.el</groupId>
     <artifactId>el-api</artifactId>
    </exclusion>
   </exclusions>
  </dependency>
  
  ...

 </dependencies>

 
</project>


So, like you favor composition or aggregation over inheritance, in maven pom also favor aggregation over inheritance.


Q. What are the different dependency scopes have you used?
A. compile, provided, test, and import.

Compile means that you need the JAR for compiling and running the app. For a web application, as an example, the JAR will be placed in the WEB-INF/lib directory.

Provided means that you need the JAR for compiling, but at run time there is already a JAR provided by the environment so you don't need it packaged with your app. For a web app, this means that the JAR file will not be placed into the WEB-INF/lib directory.

Test 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.

import scope is used to aggregate the specified POM with the dependencies in that POM's "dependencyManagement" section. This scope is only used on a dependency of type pom in the section and available only from Maven version 2.0.9.


You could also read other Maven Interview Questions and Answers at Java build tools - why use Maven?

Labels: , ,