HowTo: Quickly resolve what an Sling/OSGi bundle needs.

30 10 2012

Resolving dependencies for an OSGi bundle can be hard at times, especially if working with legacy code. The sure-fire way of finding all the dependencies is to spin the bundle up in an OSGi container, but that requires building the bundle and deploying it. Here is a quick way of doing it with maven, that may at first sound odd.

If your building your bundle with maven, you will be using the BND tool via the maven-bundle-plugin. This analyses all the byte code that is going into the bundle to work out what will cross over the class-loader boundary. BND via the maven-bundle-plugin has a default import rule of ‘*’. ie import everything. If you are trying to control which dependencies are embedded, which are ignored and which are imported, this can be a hinderance. Strange though it sounds, if you remove it life will be easier. BND will immediately report everything that it needs to import that can’t be imported. It will refuse to build which is a lot faster than generating a build that won’t deploy. The way BND reports is also useful. It tells you exactly what it can’t find and this gives you a list of packages to import, ignore or embed. Once you think you have your list of package imports down to a set that you expect to come from other bundles in your container, turn the ‘*’ import back on and away you go.

In maven that means editing the pom.xml eg:

...
 <plugin>
   <groupId>org.apache.felix</groupId>
   <artifactId>maven-bundle-plugin</artifactId>
   <version>2.3.6</version>
   <extensions>true</extensions>
   <configuration>
     <instructions>
       <Import-Package>
         <!-- add ignore packages before the * as required eg. !org.testng.annotations, -->
         * <!-- comment the * out to cause BND to report everything its not been told to import -->
       </Import-Package>
       <Private-Package>
         <!-- add packages that you want to appear as raw classes in the jar as private packages Note, they dont have to source code in the project, they can be anywhere on the classpath for the project, but be careful about resources eg org.apache.sling.commons.cache.infinispan.* -->
       </Private-Package>
       <DynamicImport-Package>sun.misc.*</DynamicImport-Package>
       true</Embed-Transitive>

           <!-- embed dependencies (by artifact ID, including transitives if Embed-Transitive is true) that you dont want exposed to OSGi -->
       </Embed-Dependency>
     </instructions>
   </configuration>
 </plugin>

The OSGi purists will tell us that it’s heresy to embed anything but sometimes with legacy systems it’s just too painful to deal with the classloader issues.

There is probably a better way of doing this, if so, do tell.


				




HowTo: add more than one source directory into a maven build

29 07 2009

There are more project builds that use code generators to convert model files or interface descriptions into code and associated resources. The normal approach is to generate the code every time and place it in the …./target area of the build so that its gets built duging maven’s compile phase. However there are times when you want to generate the code rarely, and have it form part of the code base. If this is the case, then putting it in the man source tree, with all the hand crafted code can be dangerous and confusing. Ideally generated code, even if you keep it for a long time, should really go in its own source tree. eg …/src-generated.

The problem is, by default, maven only allows one source tree per project, and building a jar just for the generated code base might be too painful. There is no standard pom way of adding further source trees into the main maven build, but there is the maven build-helper-maven-plugin, that can amongst other things, inject additional source and resource locations into the build. The example below adds generated sources, tests and resources into a standard build.

<plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>build-helper-maven-plugin</artifactId>
 <version>1.4</version>
 <executions>
   <execution>
     <id>add-wsdl-source</id>
   <phase>generate-sources</phase>
   <goals>
     <goal>add-source</goal>
   </goals>
   <configuration>
     <sources>
       <source>${basedir}/src-generated/src</source>
     </sources>
   </configuration>
 </execution>
 <execution>
   <id>add-wsdl-test-source</id>
   <phase>generate-sources</phase>
   <goals>
     <goal>add-test-source</goal>
   </goals>
   <configuration>
     <sources>
       <source>${basedir}/src-generated/test</source>
     </sources>
   </configuration>
 </execution>
 <execution>
   <id>add-wsdl-resource</id>
   <phase>generate-sources</phase>
   <goals>
     <goal>add-resource</goal>
   </goals>
   <configuration> 
     <resources>
       <resource>
         <directory>${basedir}/src-generated/resources</directory>
         <targetPath>target/classes</targetPath>
       </resource>
     </resources>
   </configuration>
 </execution>
 </executions>
 </plugin>




Running specific Maven Test with JVM Args

21 09 2007

I have some long running tests in search, but I wouldnt want anyone to run them as part of the normal build. The tests dont have the word Test in the classname which prevents them from running, but they can be invoked on the command line with -Dtest=classname

mvn -Dtest=SearchSoak test

Also I have found that its necessary sometimes to add jvm args to the unit test, reconfiguring the Surefire plugin makes this possible, in the pom

...
  <properties>
    <deploy.target/>
    <maven.test.jvmargs> </maven.test.jvmargs>
  </properties>
...
<build>
...
 <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <forkMode>pertest</forkMode>
          <argLine>${maven.test.jvmargs}</argLine>
        </configuration>
      </plugin>
    </plugins>
...
</build>

And then to run with a heap dump and YourKit connection

export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:/Applications/YourKit Java Profiler 6.0.16.app/bin/mac"mvn -Dtest=SearchSoak \
   -Dmaven.test.jvmargs='-XX:+HeapDumpOnOutOfMemoryError -agentlib:yjpagent' \
   test




mvn eclipse:eclipse does some cool things

13 05 2007

Not having tried this much before I wasn’t certain what it did exactly, but once you have fully populated pom’s in you project, a quick mvn will sync all the .settings, .project and .classpath files that eclipse uses suitable for use in eclipse. The really great bits are, 1) it knows about transitive deps and adds those where necessary 2) it know about source code and if you do a mvn -DdownloadSources=true eclipse:eclipse it will download the sources, wire in the javadoc etc. It also knows about projects in the same package, referencing those directly.

Potentially, if we adopted the layout structure that the plugin builds, we wouldn’t need to have any .classpath, .project or .settings files in SVN, as all developers would to would be a quick mvn -DdownloadSources=true eclipse:eclipse to generate all the eclipse specific files from the pom.xml’s.

This would be a huge benefit reducing the work syncing the eclipse settings and allow those who want to use Idea or another supported IDE to do the equivalent.