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


On speaking in URLs

December 3, 2010

speaking-in-urls-2.jpgI’ve seen about five examples just today where speaking in URLs (I spoke about that before, slide 27) would have saved people from misunderstandings, and avoided wasting our collective time.

When writing about something that has an URL on a project’s mailing list, for example, pointing to it precisely makes a big difference. You will save people’s time, avoid misunderstandings and over time create a goldmine of linked information on the Web. It’s not a web without links, ok?

Writing https://issues.apache.org/jira/browse/SLING-931 (or at least SLING-931 if that’s the local convention) is so much clearer than writing about “the jcrinstall web console problem”. You might know what the latter is right now, but how about 6 months later when someone finds your message in the mailing lists archives?

Of course, all your important technical things have stable URLs, right?


Why the ASF disagrees with Oracle, straight from the Anonymous Coward’s mouth

November 16, 2010

An Anonymous Coward (as they call them) on Slashdot provides the clearest explanation I’ve seen so far.

I’m only quoting the original comment here, see the discussion on Slashdot for follow-ups:

The problem is that to be a compatible Java implementation you must pass the TCK. To get a hold of the TCK you must agree that your Java implementation has a limited field of use, namely desktop computers. That means you have to add a clause to your licence that tells your users where they can use the software – no such clause exists in any open source licence I’m aware of.

Sure you can use the OpenJDK, you can even fork it, but therein lies the problem… you can’t, because if you do and you want to claim it’s a compatible implementation you have to pass the TCK. So you have to licence the TCK, then you have to add a field of use restriction to your licence, but that’s incompatible with the GPL that the OpenJDK GPL requires you to licence under.

End result, you can have Oracle Java or ‘Open’JDK

The ASF don’t have a political axe to grind with the GPL, aren’t firing a salvo in some imaginary war based on their view of free; It’s about a contractual obligation Oracle has to release the TCK to the ASF. An obligation Sun had and failed to meet and that Oracle continues to fail to meet.

The ASF was re-elected to the JCP with 95% of the vote. No other elected member had anywhere near that. The members spoke with their vote and consequently the ASF leaving the JCP would be big news in a war with Oracle, nobody else. The ASF is outside core Java and the work of the JCP probably the biggest single contributor to the Java ecosystem. Their threat to leave the JCP would seriously damage it and Oracle’s commitment to opensource’s credibility.

You can only have Oracle Java or ‘Open’JDK – there’s no way out until Oracle honors the agreement.

I have also started collecting a list of links about the whole thing, at delicious.com/bdelacretaz/oraclemess.


Generating hard to guess content URLs in Sling

October 27, 2010

In RESTful apps, it is often useful to create hard to guess URLs, as a simple privacy device.

Here’s a self-explaining example (with hardcoded parameters) of how to do that in Sling.

After installing this component, an HTTP POST to a node named ‘foo’ creates a child node with a somewhat long hex string as its name, instead of the usual simple names generated by Sling.

package foo;

import java.util.Random;

import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.servlets.post.NodeNameGenerator;

/** Example that generates hard-to-guess node names in Sling,
 * for nodes added under nodes named 'foo' 
 * 
 * To test, build and install a bundle that includes this component,
 * and run
 * <pre>
 *   curl -X MKCOL http://admin:admin@localhost:4502/foo
 *   curl -F title=bar http://admin:admin@localhost:4502/foo/
 * </pre>
 * The output of the second curl call should return something like
 * <pre>
 *   Content created /foo/dd712dd234637bb9a9a3b3a10221eb1f
 * </pre>
 * Which is the path of the created node. 
 */
@Component
@Service
public class FooNodeNameGenerator implements NodeNameGenerator {
    private static final Random random = new Random(System.currentTimeMillis());
    
    /** @inheritDoc */
    public String getNodeName(
            SlingHttpServletRequest request, 
            String parentPath, 
            boolean requirePrefix, 
            NodeNameGenerator defaultNng) 
    {
        if(parentPath.endsWith("/foo")) {
            final StringBuilder name = new StringBuilder();
            for(int i=0; i < 2; i++) {
                name.append(Long.toHexString(random.nextLong()));
            }
            return name.toString();
        }
        return null;
    }
}

Pragmatic validation metrics for third-party software components

October 22, 2010

Earlier this week at the IKS general assembly I was asked to present a set of industrial validation metrics for the open source software components that IKS is producing.

Being my pragmatic self, I decided to avoid any academic/abstract stuff and focus on concrete metrics that help us provide value-adding solutions to our customers in the long term.

Here’s the result, for a hypothetical FOO software component.

Metrics are numbered VMx to make it clear what we’ll be arguing about when it comes to evaluating IKS software.

VM1
Do I understand what FOO is?
VM2
Does FOO add value to my product?
VM3
Is that added value demonstrable/sellable to my customers?
VM4
Can I easily run FOO alongside with or inside my product?
VM5
Is the impact of FOO on runtime infrastructure requirements acceptable?
VM6
How good is the FOO API when it comes to integrating with my product?
VM7
Is FOO robust and functional enough to be used in production at the enterprise level?
VM8
Is the FOO test suite good enough as a functionality and non-regression “quality gate”?
VM9
Is the FOO licence (both copyright and patents) acceptable to me?
VM10
Can I participate in FOO’s development and influence it in a fair and balanced way?
VM11
Do I know who I should talk to for support and future development of FOO?
VM12
Am I confident that FOO still going to be available and maintained once the IKS funding period is over?

VM1 can be surprisingly hard to fulfill when working on researchy/experimental stuff ;-)

Suggestions for improvements are welcome in this post’s comments, as usual.

Thanks to Alex Conconi who contributed VM11.


Twitter is the new CB…but it’s missing the channels!

September 29, 2010

When I was a kid, Citizen Band Radio (aka “CB”) was all the rage if you could afford it.

Those small unlicensed two-way radios have a relatively short range, actually extremely short if you compare to the global range of Twitter today. And they don’t have that many channels, 40 in most cases if I remember correctly. That works as long as the density of CB users is not too high in a given area.

For general chat, CB etiquette requires you to start by calling on a common channel for whoever you want to talk to, and, once you find your partner(s), quickly agree on a different channel to move to, to avoid hogging the common channel.

That “agree on a different channel to move to” feature is key to sharing a limited medium efficiently. As the Twitter population grows, the timeline that I’m getting is more and more crowded, with more and more stuff that I’m not interested in, although I’m willing to follow the general flow of a lot of people.

The global reach of services like Twitter and ubiquitous Internet access makes CB mostly obsolete today.

Twitter is the new CB, in many ways.

What Twitter lacks, however, are the channels, as in:

Could you guys at SXSW move to the #c.sxsw channel and stop boring us with your conference chitchat? We’re jealous, ok? Thanks.

Direct messages don’t work for that, as they are limited to two users. A bit like a point-to-point channel, like the telephone, as opposed to multipoint as the CB provides.

Twitter channels can also be very useful for data, like weather stations or other continuous data sources that can benefit from hierachically organized channels. But let’s keep that discussion for another post. Like my mom said, one topic, one post (not sure it was her actually).

What does Twitter need to support channels?

I think the following rule is sufficient:

Any message that contains a hashtag starting with #c. is not shown in the general timeline, except to people who are explicitely mentioned with their @id in the message.

Such messages can then be retrieved by searching for channel hashtags, including partial hashtag values to support hierarchies.

Using hierachical channel names by convention opens interesting possibilities. The ApacheCon conference general channel would be #c.apachecon for example, the java track #c.apachecon.j, etc.

This channel filtering could of course be implemented in Twitter clients (@stephtara, remember you said you were going to mention that to @loic?), but in my opinion implementing it on the server side makes more sense as it’s a generally useful feature.

Then again, I’m a server-side guy ;-)

Opinions welcome, of course.


So Java is more complex than Scala? You must be kidding

August 26, 2010

My esteemed colleague Michael Duerig posts about Scala code being simpler than java.

His Scala example is beautiful, no question about it:

object ScalaMain {
  case class Person(name: String, age: Int)

  val persons = List(
    Person("Boris", 40),
    Person("Betty", 32),
    Person("Bambi", 17))

  val (minors, majors) = persons.partition(_.age <= 18) 

  def main(args: Array[String]) = {
    println (minors.mkString(", "))
    println (majors.mkString(", "))
  }
}

Though I wonder how many Scala programmers are actually able to come up with such concise and elegant code.

Michi’s corresponding java example, however, is…let’s say horrible. Like making things as complex and bloated as they can be.

Here’s my (slightly) more elegant Java version:

import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;

public class Person extends HashMap<String, Object> {
    
    public Person(String name, int age) {
        put("name", name);
        put("age", age);
    }
    
    public static void main(String args[]) {
        final Person [] persons = {
            new Person("Boris", 40),
            new Person("Betty", 32),
            new Person("Bambi", 17),
        };
        
        List<Person> minors = new ArrayList<Person>();
        List<Person> majors = new ArrayList<Person>();
        
        for(Person p : persons) {
            if( (Integer)p.get("age") <= 18 ) {
                minors.add(p);
            } else {
                majors.add(p);
            }
        }
        
        System.out.println(minors);
        System.out.println(majors);
        
        // Output:
        // [{age=17, name=Bambi}]
        // [{age=40, name=Boris}, {age=32, name=Betty}]
    }
}

Not bad hey? 37 lines all included, and although Java does require more boilerplate code, it’s not too bad.

All this is kinda tongue in cheek, ok? We could start all sorts of flame wars about type safety, generics and dynamic programming – my point is just that elegant and ugly code can be written in any language.

Scala definitely helps with conciseness, but in my opinion Java does not require things to be as bloated as some of those language wars examples show.

I’m on my way to Michi’s office to sort this out face to face as well ;-)

Update: face to face discussion went well, we agreed to not start religious wars…and in the meantime, here are two additional (and more serious) posts on the subject: