Redeploy OSGi bundles automatically with fizzed-watcher-maven-plugin

September 17, 2015

Being able to redeploy your OSGi bundles automatically when you make changes to their source code is very useful when developing Apache Sling applications, for example.

Today I tried the fizzed-watcher-maven-plugin on a Sling sample bundle, and it seems to work quite well. I just had to add the following to my POM:


<plugin>
  <groupId>com.fizzed</groupId>
  <artifactId>fizzed-watcher-maven-plugin</artifactId>
  <version>1.0.6</version>
  <configuration>
    <watches>
      <watch>
        <directory>src/main</directory>
      </watch>
    </watches>
    <goals>
      <param>clean</param>
      <param>install</param>
    </goals>
    <profiles>
      <param>autoInstallBundle</param>
    </profiles>
  </configuration>
</plugin>

And changing any file under src/main causes the bundle to be rebuilt and (via Sling’s default autoInstallBundle profile) reinstalled in my test Sling instance.

To start the plugin with that setup I used


mvn fizzed-watcher:run -Dsling.url=http://localhost:8080/system/console

See https://github.com/fizzed/maven-plugins for more info.

Filed under: very useful.


Transforming Maven POM properties with Groovy

February 11, 2011

We’re moving to fragment bundles in Sling instead of using system properties, for example to export packages from the JVM’s classpath.

If you have no idea what I’m talking about, bear with me – this is just about a simple Maven trick to transform POM properties using bits of Groovy script.

Basically, an OSGi fragment bundle is a jar file that contains just metadata under META-INF, especially META-INF/MANIFEST.MF that contains the OSGi bundle headers.

One of these headers is Bundle-Version, which does not support values like 5.4.2-SNAPSHOT which are common in Maven. The dash is invalid in an OSGi bundle version number, that value needs to be converted to 5.4.2.SNAPSHOT

To avoid having a separate bundle.version property in your POM, which if you’re like me you’ll forget to update before a release, here’s how to transform the value using a bit of Groovy scripting:

<plugin>
  <groupId>org.codehaus.groovy.maven</groupId>
  <artifactId>gmaven-plugin</artifactId>
  <version>1.0</version>
  <executions>
    <execution>
      <phase>generate-resources</phase>
        <goals>
          <goal>execute</goal>
      </goals>
      <configuration>
      <properties>
        <rawVersion>${pom.version}</rawVersion>
      </properties>
      <source>
        // Convert POM version to valid OSGi version identifier
        project.properties['osgi.version'] = 
          (project.properties['rawVersion'] =~ /-/).replaceAll('.')
      </source>
    </configuration>
  </execution>
 </executions>
</plugin>  

As usual in Maven POMs (though I think Maven 3.x can improve on that, feedback welcome) that’s a bit verbose to write, the actual Groovy code is just

project.properties['osgi.version'] = 
  (project.properties['rawVersion'] =~ /-/).replaceAll('.')

But even with the verbosity it’s cool to be able to do that without having to write a plugin. You can then use the ${osgi.version} property for the Bundle-Version header.

For the sake of completeness, here’s the other interesting part of that pom, which sets the required OSGi headers to create a fragment bundle. com.example,whatever is the package that we need to be exported by the system bundle.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>
      <index>true</index>
      <manifest>
        <addClasspath>false</addClasspath>
      </manifest>
      <manifestEntries>
        <Bundle-Version>${osgi.version}</Bundle-Version>
        <Bundle-Description>${project.description}</Bundle-Description>
        <Bundle-Name>${project.name}</Bundle-Name>
        <Bundle-DocURL>http://www.example.com/</Bundle-DocURL>
        <Bundle-ManifestVersion>2</Bundle-ManifestVersion>
        <Bundle-Vendor>YourCompanyAG</Bundle-Vendor>
        <Fragment-Host>system.bundle;extension:=framework</Fragment-Host>
        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
        <Export-Package>
          com.example,whatever;version=1.0,
      </Export-Package>
    </manifestEntries>
  </archive>
 </configuration>
</plugin>

Update: a complete sample pom is available at http://svn.apache.org/repos/asf/sling/trunk/samples/framework-fragment/pom.xml


Faster testing with the Maven CLI plugin

May 5, 2009

Although it’s not that new, I discovered Don Brown’s Maven CLI plugin only this morning, and played with mojavelinux‘ s enhanced version which supports -D parameters and profiles, among other things.

The great thing is to be able to run a simple test or test -D MyTest command quickly. You first start Maven with mvn cli:execute-phase, which gives you a maven2> command prompt to start Maven lifecycle phases. As Maven is already started, phases run much quicker than when starting from scratch.

In my experiments, the test command ran about five times faster than using mvn -o test, but the difference depends how fast your tests are, of course.

To setup the plugin, I’m adding the following to my settings.xml, so as to not interfere with project’s POMs, as the CLI is more an environment feature than a project thing:

<!-- 
  mvn settings.xml that enable the CLI plugin described at
  http://tinyurl.com/maven-cli-plugin
  (For example "mvn cli:execute-phase")
-->
<settings>
  <pluginGroups>
    <pluginGroup>org.twdata.maven</pluginGroup>
  </pluginGroups>
  <profiles>
    <profile>
      <id>cli-plugin</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <pluginRepositories>
        <pluginRepository>
          <id>repository.jboss.org</id>
          <name>JBoss Repository</name>
          <url>http://repository.jboss.org/maven2</url>
        </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>
</settings>

Find more info on the mojavelinux page.

Great tool – thanks Don Brown and mojavelinux!


Automating the generation of NOTICE files

June 3, 2008

ASF projects need to include the correct attributions for the dependencies that they redistribute, in NOTICE files (see the http example).

Creating those NOTICEs is a pain in a multi-module project like Sling, so considering the lazyness is a virtue principle, I decided yesterday to automate this based on the mvn dependency:resolve output.

The resulting mknotice script has been happily generating the millions (almost) of Sling NOTICE files today, and the output is much better than we we had before.

However, the mvn dependency:resolve is not always sufficient. In our dojo extensions modules, for example, the Dojo stuff is copied by Ant tasks run from Maven (which is supposed to be declarative, but that’s another story), without having a dependency at the Maven level.

Also, our Launchpad webapp copies dependencies that are embedded in the launchpad base module using the Maven dependency plugin, which only has a dependency to the launchpad base module, but not on what’s inside, obviously. Another case where the mknotice script fails to provide complete information.

For now, such cases are handled using local module.notice.txt files, to define additional notice entries.

As is often the case when one starts to quickly write a script to fix something, this has taken me much longer than expected. And the script is slow. And a Maven plugin would be better. But hey, it works ;-)