Working with Maven and SpringSource dm Server

March 8th, 2009

Since I am a big Maven fan one of the things that pained me when starting to work with the dm Server was that the tooling for managing project dependencies was all based around Eclipse.  The STS 2.0 RC discussed by Christian Dupuis here now has support for a separate test classpath using a proprietary TEST.MF.  To me this still poses a problem when you start thinking about Continous Integration testing.  Currently there is going to be duplication and you will need to keep the classpath understood by your build system and your IDE in synch manually. It is however surprisingly easy to setup Maven and dm Server to play nice, so before posting the code for my recent Spring Integration with dm Server demo from the UK Spring User Group I thought I would walk through setting up dm Server with Maven.

The first thing you need to decide is where you are going to have your shared repository which will be populated by Maven and used by dm Server to resolve dependencies.  You can configure dm Server to use the default Maven repository under your home directory, however for reasons of clarity I prefer to maintain  a separate repository.  So, assuming you have downloaded dm Server and unzipped it, the first thing you will need to do is modify the provisioning configuration in DM_SERVER/config/server.config. By default there is no section for provisioning here with convention being used, so after the osgiConsole section define a section as below.

"osgiConsole": {
    "enabled": true,
    "port": 2401
},
"provisioning" : {
    "searchPaths": [
        "repository/bundles/subsystems/{name}/{bundle}.jar",
        "repository/bundles/ext/{bundle}",
        "${user.home}/servers/dm-server-maven-repo/**/{bundle}.jar",
        "repository/libraries/ext/{library}",
        "repository/libraries/usr/{library}"
    ]
}
}

To test this we will create a simple project which uses Apache Commons lang StrSubstitor class to print the simple message given as an example in the Javadoc for commons lang “You are running with java.version = ${java.version} and os.name = ${os.name}.”)

To create the sample Maven project we can use the Maven archetype plugin so go to the command prompt in the directory where you want to create the test project.

  1. At the command prompt “mvn archetype:generate”
  2. Then select the number relating to maven-archetype-quickstart , 15 by default but may vary according to your setup
  3. Enter a groupId “org.jpartner” in my case
  4. Enter an artifactId “mavenDmHello”
  5. Hit enter to accept the default version “1.0-SNAPSHOT”
  6. For package I used the same value as groupId so “org.jpartner” in my case

Ok, so now we need to open up the pom.xml that has been created for use by the archetype plugin, so change directory to mavenDmHello and open pom.xml in your preferred text editor. After the URL element and before the dependency element add in the below xml fragment to allow Maven to resolve dependencies from the SpringSource Enterprise Bundle Repository, which you can browse here http://www.springsource.com/repository.

<repositories>
    <repository>
        <id>com.springsource.repository.bundles.release</id>
        <name>SpringSource Bundle Releases</name>
        <url>http://repository.springsource.com/maven/bundles/release</url>
    </repository>
    <repository>  <id>com.springsource.repository.bundles.external</id>
        <name>SpringSource External Bundle Releases</name>
        <url>http://repository.springsource.com/maven/bundles/external</url>
    </repository>
</repositories>

To declare the dependency on Apache Commons Lang we are adding the version from the SpringSource repository to ensure we get an OSGi compatible jar, hence the non-standard artifactId.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>com.springsource.org.apache.commons.lang</artifactId>
     <version>2.4.0</version>
</dependency>

In order to tell Maven to use the non-standard local repository location we could configure the location in our global settings.xml. However, since this will effect all our maven projects, for the moment we will set up a separate settings.xml file. In the root of the created project create a file called settings.xml with the content below.

<settings>
   <localRepository>${user.home}/servers/dm-server-maven-repo</localRepository>
</settings>

To tell Maven about our new settings.xml we pass the -s so running mvn -s./settings.xml install will download our dependency on Commons Lang into our new repository. Maven will of course download a whole host of other things as well.

Next we will create a class in our project which makes use of StrSubstitor to make sure everything is working as expected. So create a greeter class as below.

package org.jpartner;

import org.apache.commons.lang.text.StrSubstitutor;

public class Greeter{
   public Greeter(){
      String replaced =
         StrSubstitutor.replaceSystemProperties(
            "You are running with java.version" +
                " = ${java.version} and os.name = ${os.name}.");
      System.out.println(replaced);
   }
   
}

We can then use the standard mechanism to have an instance of our Greeter class created at runtime. So under src/main/resources create a directory structure META-INF/spring and inside the spring directory create a file called greeter.xml as below.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation=
  "http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd">


   <bean id="greeter" class="org.jpartner.Greeter" />

</beans>

The next thing we need to do is provide an OSGi compatible manifest importing the org.apache.commons.lang.text.StrSubstitutor. Because Maven will auto generate a manifest we also need to configure the maven-jar-plugin to use our provided manifest. We do this by adding the build section as below to our pom.xml.

<build>
   <plugins>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <configuration>
         <archive>
            <manifestFile>
               ${basedir}/src/main/resources/META-INF/MANIFEST.MF
            </manifestFile>
         </archive>
         </configuration>
      </plugin>
   </plugins>
</build>

Then create the MANIFEST.MF in the META-INF directory as below. We declare our import of the commons lang package containing the StrSubstitutor

Manifest-Version: 1.0
Bundle-Name: Service_interfaces Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: mavenDmHello
Bundle-Version: 1.0.0
Import-Package: org.apache.commons.lang.text;version="[2.4.0,3.0.0)"

Now start up the dm Server using the script under DM_SERVER/bin. Run mvn install again to create a jar containing our new manifest. Then simply copy the jar created in the maven target directory to the DM_SERVER/pickup. You should see dm Server output as below.


[2009-03-08 20:39:22.735] fs-watcher Processing ‘INITIAL’ event for file ‘mavenDmHello-1.0-SNAPSHOT.jar’.
[2009-03-08 20:39:23.504] fs-watcher Deployment of ‘mavenDmHello’ version ‘1′ completed.

A tail of the serviceability log DM_SERVER//serviceability/trace/mavenDmHello-1/trace.log will show something similar to below, showing that we are successfully using Maven to populate the repository for use with dm Server.


[2009-03-08 20:39:23.482] server-dm-4 amework.beans.factory.support.DefaultListableBeanFactory.unknown I Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@65d0e7e9: defining beans [greeter]; root of factory hierarchy
[2009-03-08 20:39:23.493] server-dm-4 System.out I You are running with java.version = 1.6.0_07 and os.name = Mac OS X.

So now we have dependencies working with Maven however we are still creating the manifest by hand. The SpringSource Maven bundlor plugin can be used to help with that and I will be posting an example using that soon.

Filed under: Maven, Spring

Leave a Reply