Skip to end of metadata
Go to start of metadata

Context

In a typical Maven case, the classifier may be used to classify an artifact as JDK-1.3 or JDK-1.4 for its target platform. In the case of J2ME, things get more complicated and such a single classifier becomes problematic because there can be many classifiers (which are referred to as requirements needed for the artifact to be used on the target platform). For example, the artifact may require libraries for MMS support or certain media support (JSR-135) to be able to build. To this day, Maven still has not adequately addressed this part of the Java world. We also have a similar case in the .NET world, where we are targeting different processors, framework versions, vendor implementations and so on. The general problem is taking Maven from supporting the J2SE world, which has great cross-platform support, to environments that are partially cross-platform.

Solution

The way NMaven currently handles this problem, is to use the public key token ID, from a signed .NET artifact, as the classifier. Then I can attach requirements (or attributes) to that classifier. For example, say that the value of my public key token ID is 4b435f4d76e2f0e6. I can associate with that value the following attributes: vendor=microsoft, frameworkVersion= 2.0. This has the implication that only signed artifacts can have artifact requirements. To understand this approach, requires understanding the constraints of the system. First there is only one classifier within the pom (and its associated dependency object within the Maven API). Second, the Global Assembly Cache - where Microsoft strong-named assemblies are stored for a global context - uses the public key token ID within the path of the assembly. Thus if I have a classifier (pom), some associated meta-data (RDF) tied to that classifier, and the classifier value (4b435f4d76e2f0e6) within the path of the assembly within the GAC, then I can always tell what the requirements are for an artifact, regardless of whether they are stored in the local repository or an external repository such as the GAC. If I need new requirements, I just sign the assembly with a different key, still having both artifacts in the GAC.

This .NET solution would not apply to Java's case, but I think that it is important to understand at least one context of the problem and how it is solved. Other contexts could also be drawn from the J2ME world. What I am convinced of - in the general case - is that using a GUID for the classifier and then having associated attributes tied to that GUID makes a lot of sense. If we take the case of multiple classifiers, then we would need more sophisticated matching process to tell whether two artifacts are indeed different. A GUID, as the classifier, allows two artifacts - with the same groupId, artifactId, version - to differentiate themselves by matching a single field. Then it is just a matter of associating the requirements to that classifier value/GUID.

The solution should be general enough to handle artifact requirements from any platform, including .NET, as well as J2ME foundations and profiles. The solution should also allow the artifact provider to add multiple requirements (probably through name-value pairs) to the artifact. This implies that we would need a pluggable matching framework that would allow the provider/framework developer to specify that requirements with certain names would use configured classes for handling of that match. For instance, if I specify name-value requirements as Software.NET.FrameworkVersion=1.1+ within the pom, then I should be able to configure the framework to invoke matcher class NetFrameworkVersionMatcher that knows how to determine the match. If we use a GUID for the classifier, this pluggable matching framework is not directly required for the expanded classifier support but is a necessary part to make it a fully working solution.

Votes

  • No labels

2 Comments

  1. It seems like there should be some distinction between an artifact content classifier (-sources, -javadoc) and a target platform classifier (-jdk14). Ideally the behaviour for the two would be different. For example, transitive dependencies make sense if the classifier is describing a target platform but they are not normally necessary for the content type classifiers.

    I'm not crazy about the idea of having a guid for a classifier since it's not descriptive by itself and relies on other metadata. And it's not really Java friendly. Would it make sense to have a standard set of platform classifiers similar to the way that RPMs work? Maybe there could be a "." between the artifact name and the platform classifier, so you could have something like:

    myproject-1.0.jar  -  platform independent jar
    myproject-1.0-sources.jar
    myproject-1.0.jdk13.jar  -  os independent jdk1.3 jar.
    myproject-1.0.jdk14-windows.jar  -  jdk and os dependent jar.

  2. If the artifact provider uses name-value pairs to describe the requirements of the artifact, then it is easy to make the distinction between content classifiers (-sources, -javadoc) and a target platform classifiers (-jdk14). For example, you could have Content.Type=Sources, Content.Type=JavaDoc or Content.Type=Binary. The framework would then know to apply requirement matching rules to those artifacts with the Content.Type=Binary but not to attempt any matches on other content types.

    Placing the classifier values within the artifact filename poses some problems. First, in the case of J2ME, the list of classifiers could number in the dozens. Thus embedding classifier values within the filename would not be feasible. Second, in the case of .NET, it is a problem putting the classifier into the artifact file name due to this enforcing certain loading rules of the CLR that you may not want.

    Some notion of a GUID is important so that assemblies can rely on a single ID to guarantee matching of the dependent artifact if they need it. This could just be another name-value pair (Content.ID=4b435f4d76e2f0e6) or it could be that all requirements are attached to the classifier with the GUID. In short, the GUID is a way to specify exact matches. If the artifact provider chooses not to include the GUID, then the matching engine kicks in and makes a best match based on a set of rules that take into account the capabilities of the build (or target) platform.