Received: from datsunx.us.oracle.com (datsunx [10.132.180.90]) by datsun.us.oracle.com (8.14.2+Sun/8.14.2) with ESMTP id o94JOQsd020172 for ; Mon, 4 Oct 2010 12:24:26 -0700 (PDT) Received: from [IPv6:::1] (localhost [IPv6:::1] (may be forged)) by datsunx.us.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id o94JRn4o002832; Mon, 4 Oct 2010 12:27:49 -0700 (PDT) Message-ID: <4CAA2AB5.8030604@oracle.com> Date: Mon, 04 Oct 2010 12:27:49 -0700 From: Bill Shannon User-Agent: Mozilla/5.0 (X11; U; SunOS i86pc; en-US; rv:1.9.2.7) Gecko/20100817 Lightning/1.0b2 Thunderbird/3.1.1 MIME-Version: 1.0 To: Java Community Process JSR #316 Expert List Subject: maven artifact naming and versioning Content-Type: multipart/mixed; boundary="------------010000030405050700080501" This is a multi-part message in MIME format. --------------010000030405050700080501 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Expert group members, We've been using Maven to build the Java EE reference implementation (GlassFish) for some time, and we've seen increased use of Maven by Java developers. We've also noticed that we haven't been very consistent about our usage of Maven, and in particular about how we name and version the Maven artifacts that we produce. Since our Maven artifacts are also OSGi bundles, we have many of the same issues with OSGi naming and versioning. I wrote the attached document containing rules and guidelines for Oracle Spec Leads to address these inconsistencies. We intend to transition all of our artifacts to the scheme described here, and we'll encourage other Spec Leads, particularly Spec Leads that contribute to the Java EE reference implementation, to do likewise. But before we commit to this new approach, I'd like to get feedback from anyone else who has experience in this area. Our JCP specs don't say anything about Maven artifacts, so this is not really a spec issue. Still, we'd like your feedback. Please feel free to forward this to anyone else in your company who may be interested in providing feedback. Feedback received by the end of October will be most useful. Thanks. Bill --------------010000030405050700080501 Content-Type: text/plain; name="maven-naming5" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="maven-naming5" Maven and OSGi packaging, naming, and versioning rules Version 5 - 10/4/2010 Bill Shannon This note describes our general rules for choosing Maven, OSGi, and jar file manifest names and version numbers for implementation artifacts related to Java standard technologies. Not all Java standards will produce all artifacts described here, but if they do they should use the approach described here. These are the rules that the spec lead for a Java specification should follow for the reference implementation; compatible implementations will use different names. A given technology will commonly produce two artifacts: - an API jar file The API jar file typically includes only the JCP-defined classes/interfaces/etc. that define the API, that is, usually just the javax.* class files. The purpose of the API jar file is *only* to allow programs to be compiled against the API without the risk of depending on non-API classes. The API jar file is *not* intended to be used at runtime (although in some cases it may be), and it is *not* intended to be a portable implementation of the API classes that can be used by others to derive their own implementation of the specification (although in some cases it will be). An extreme example of an API jar file is the "javaee.jar" file that we produce, which contains *no* code at all for any of the classes, and is not a valid class file for use at runtime. It is suitable only for reference by the compiler. Most other API jar files will not take this extreme approach. - an implementation jar file If the Java specification defines a standalone version of the technology, the implementation jar file will be such a standalone implementation of the specification, and will meet all the compatibility requirements of the specification. The implementation jar file typically includes all the classes from the API jar file, plus whatever implementation classes are need to produce a complete runtime. In some cases the implementation jar file might contain only the implementation artifacts, and depend on the API jar file for the API definitions, although this is discouraged for standalone implementations. Not all specifications will define a standalone version, and even when they do a standalone version following the recommendations described here might not be available. For example, while the Servlet spec allows for a standalone implementation, we do not produce a standalone Servlet implementation packaged as a single jar file. There might still be a standalone Servlet implementation, e.g., composed of multiple jar files, but we don't define naming or packaging for that here. - Naming To illustrate the general approach, we'll use three existing technologies: - Connectors, a technology only available as a part of GlassFish - JSF, a technology closely associated with GlassFish, but available independently - JavaMail, a technology included with GlassFish, but widely used independently The general approach is described using the following "variables": API_PACKAGE - the primary Java package defining the API IMPL_NAMESPACE - the primary Java package or namespace used by the implementation of the API, or with which the implementation of the API is associated STANDALONE_IMPL - a boolean indicating whether a standalone implementation is available; if false, no implementation jar file is defined Given these variables, the following names should be used: API jar file: ${API_PACKAGE}-api.jar OSGi Bundle-SymbolicName: ${API_PACKAGE}-api Maven group ID, artifact ID: ${API_PACKAGE}:${API_PACKAGE}-api jar Extension-Name: ${API_PACKAGE} Implementation jar file: ${API_PACKAGE}.jar OSGi Bundle-SymbolicName: ${IMPL_NAMESPACE}.${API_PACKAGE} Maven group ID, artifact ID: ${IMPL_NAMESPACE}:${API_PACKAGE} jar Extension-Name: ${API_PACKAGE} These names are appropriate for the reference implementation of a specification. Compatible implementations should create an implementation jar file named ${IMPL_NAMESPACE}.${API_PACKAGE}.jar. Compatible implementations should not produce an API jar file. The jar file names above are the names that should be used for jar files that are made available in a download bundle, such as a zip file distribution for the technology. Note that, when building with Maven, the jar file names will include the version number, as described in the following section. Note that the above would produce both an API jar and an implementation jar with the same jar Extension-Name. In the case where an implementation jar file depends on the API jar file (rather than including the API definitions), the API jar file should *not* have an Extension-Name header. ISSUE: Since the API jar file is not usable at runtime, should it have OSGi or jar extension metadata? pro - some *are* usable at runtime, and they should have it, so it would be more consistent for all to have it pro - even if not usable at runtime, it provides a sort of documentation that tools could read con - it might encourage people to use the jar file in ways we don't intend For now, I'm leaning on the side of "pro". Applying these rules to our three examples, we get: Connectors: API_PACKAGE=javax.resource IMPL_NAMESPACE=org.glassfish STANDALONE_IMPL=false API jar file: javax.resource-api.jar OSGi Bundle-SymbolicName: javax.resource-api Maven group ID, artifact ID: javax.resource:javax.resource-api jar Extension-Name: javax.resource JSF: API_PACKAGE=javax.faces IMPL_NAMESPACE=org.glassfish STANDALONE_IMPL=true API jar file: javax.faces-api.jar OSGi Bundle-SymbolicName: javax.faces-api Maven group ID, artifact ID: javax.faces:javax.faces-api jar Extension-Name: javax.faces Implementation jar file: javax.faces.jar OSGi Bundle-SymbolicName: org.glassfish.javax.faces Maven group ID, artifact ID: org.glassfish:javax.faces jar Extension-Name: javax.faces JavaMail: API_PACKAGE=javax.mail IMPL_NAMESPACE=com.sun.mail STANDALONE_IMPL=true API jar file: javax.mail-api.jar OSGi Bundle-SymbolicName: javax.mail-api Maven group ID, artifact ID: javax.mail:javax.mail-api jar Extension-Name: javax.mail Implementation jar file: javax.mail.jar OSGi Bundle-SymbolicName: com.sun.mail.javax.mail Maven group ID, artifact ID: com.sun.mail:javax.mail jar Extension-Name: javax.mail For technologies that are closely associated with GlassFish, the org.glassfish name should be used as IMPL_NAMESPACE. For technologies that are more independent of GlassFish, a name should be chosen based on the Java packages used for the implementation, or the web site hosting the project. - Version numbers In addition to names, we also need to specify version numbers for each of the artifacts produced. The version numbers of the API are specified through the JCP. Two common approaches are used for the version numbers of the implementation: 1. The implementation version tracks the API version, using a "dot-dot" version number to distinguish versions of the implementation that all implement the same API version. This approach is most often used when the implementation is primarily intended to be only the reference implementation of the given technology. 2. The implementation version number is completely independent of the API version number. This approach is most often used when the implementation has a purpose different from, or larger than, being just a reference implementation of a specification. For example, The GlassFish version number is independent of the version numbers of any specification implemented by GlassFish. A version number is a Dewey-decimal number of two or three components, either . or ... We define the following additional variables: SPEC_VERSION - version number of the JCP specification, always of the form . SPEC_IMPL_VERSION - version number of the API classes, derived from SPEC_VERSION by adding an optional micro version number IMPL_VERSION - version number of the implementation Having a separate SPEC_VERSION and SPEC_IMPL_VERSION allows the API definition classes to be updated (e.g., to fix spec or implementation bugs) in cases where the corresponding spec has not changed. In case #1 above, SPEC_IMPL_VERSION and IMPL_VERSION will have the same value. In case #2 above, SPEC_IMPL_VERSION will need to be maintained and updated separately from IMPL_VERSION. Adding the version number information to our general rules, we get: API jar file: ${API_PACKAGE}-api.jar OSGi Bundle-SymbolicName: ${API_PACKAGE}-api OSGi bundle specversion: ${SPEC_VERSION} OSGi Bundle-Version: ${SPEC_IMPL_VERSION} Maven group ID, artifact ID: ${API_PACKAGE}:${API_PACKAGE}-api Maven version: ${SPEC_IMPL_VERSION} Maven API jar file: ${API_PACKAGE}-api-${SPEC_IMPL_VERSION}.jar jar Extension-Name: ${API_PACKAGE} jar Specification-Version: ${SPEC_VERSION} jar Implementation-Version: ${SPEC_IMPL_VERSION} Implementation jar file: ${API_PACKAGE}.jar OSGi Bundle-SymbolicName: ${IMPL_NAMESPACE}.${API_PACKAGE} OSGi bundle specversion: ${SPEC_VERSION} OSGi Bundle-Version: ${IMPL_VERSION} Maven group ID, artifact ID: ${IMPL_NAMESPACE}:${API_PACKAGE} Maven version: ${IMPL_VERSION} Maven imp jar file: ${API_PACKAGE}-${IMPL_VERSION}.jar jar Extension-Name: ${API_PACKAGE} jar Specification-Version: ${SPEC_VERSION} jar Implementation-Version: ${IMPL_VERSION} Note that Oracle is separately planning to submit a JSR to define how versioning works for OSGi bundles corresponding to Java specifications. A key part of that proposal is to use a "specversion" attribute to define the specification version that a bundle implements or requires. I've used that approach above. The proposed JSR will also define how the Bundle-Version should be chosen; since that part of the proposed JSR is less clear, I haven't tried to accommodate it above, although once it's defined we should use it here. It will likely require defining a new "COMPAT_VERSION" variable to express the compatibility characteristics of a bundle. For technologies that are closely associated with GlassFish, and especially for technologies that are built with the main GlassFish workspace, the version number of the implementation should track the version number of GlassFish. Applying the above rules to our examples gives: Connectors: API_PACKAGE=javax.resource IMPL_NAMESPACE=org.glassfish STANDALONE_IMPL=false SPEC_VERSION=1.6 SPEC_IMPL_VERSION=1.6 API jar file: javax.resource-api.jar OSGi Bundle-SymbolicName: javax.resource-api OSGi bundle specversion: 1.6 OSGi Bundle-Version: 1.6 Maven group ID, artifact ID: javax.resource:javax.resource-api Maven version: 1.6 Maven API jar file: javax.resource-api-1.6.jar jar Extension-Name: javax.resource jar Specification-Version: 1.6 jar Implementation-Version: 1.6 JSF: API_PACKAGE=javax.faces IMPL_NAMESPACE=org.glassfish STANDALONE_IMPL=true SPEC_VERSION=2.0 SPEC_IMPL_VERSION=2.0 IMPL_VERSION=2.0 API jar file: javax.faces-api.jar OSGi Bundle-SymbolicName: javax.faces-api OSGi bundle specversion: 2.0 OSGi Bundle-Version: 2.0 Maven group ID, artifact ID: javax.faces:javax.faces-api Maven version: 2.0 Maven API jar file: javax.faces-api-2.0.jar jar Extension-Name: javax.faces jar Specification-Version: 2.0 jar Implementation-Version: 2.0 Implementation jar file: javax.faces.jar OSGi Bundle-SymbolicName: org.glassfish.javax.faces OSGi bundle specversion: 2.0 OSGi Bundle-Version: 2.0 Maven group ID, artifact ID: org.glassfish:javax.faces Maven version: 2.0 Maven imp jar file: javax.faces-2.0.jar jar Extension-Name: javax.faces jar Specification-Version: 2.0 jar Implementation-Version: 2.0 JavaMail: API_PACKAGE=javax.mail IMPL_NAMESPACE=com.sun.mail STANDALONE_IMPL=true SPEC_VERSION=1.4 SPEC_IMPL_VERSION=1.4.3 IMPL_VERSION=1.4.3 API jar file: javax.mail-api.jar OSGi Bundle-SymbolicName: javax.mail-api OSGi bundle specversion: 1.4 OSGi Bundle-Version: 1.4.3 Maven group ID, artifact ID: javax.mail:javax.mail-api Maven version: 1.4.3 Maven API jar file: javax.mail-api-1.4.3.jar jar Extension-Name: javax.mail jar Specification-Version: 1.4 jar Implementation-Version: 1.4.3 Implementation jar file: javax.mail.jar OSGi Bundle-SymbolicName: com.sun.mail.javax.mail OSGi bundle specversion: 1.4 OSGi Bundle-Version: 1.4.3 Maven group ID, artifact ID: com.sun.mail:javax.mail Maven version: 1.4.3 Maven imp jar file: javax.mail-1.4.3.jar jar Extension-Name: javax.mail jar Specification-Version: 1.4 jar Implementation-Version: 1.4.3 Note that the Maven API jar file name contains the *implementation* version number. This allows the API definitions to be updated, e.g., to fix bugs, even though the API *specification* hasn't changed. - Version numbers for non-final specifications While a Java standard specification is under development, we need to be able to publish artifacts corresponding to the non-final specification. Maven version rules define a version number with a modifier as being "less then", or older than a version number without a modifier. This allows us to use modifiers for these intermediate versions without confusion with the final version number. Ideally, the modifiers would correspond to the JCP stages, but since modifiers sort lexicographically this won't work. Unfortunately, this makes it difficult to determine (e.g.) which artifact corresponds to the Proposed Final Draft version of the specification. Unfortunately, OSGi defines modifiers as being "greater than" the base version number, as does the jar extension spec. This prevents us from using modifiers in the same way as we would with Maven. Instead, we adopt a convention that a "micro" version number of "99" means a non-final version of the following version number. Some variables to define the new version numbers: BUILD_NUMBER - the number of a particular build of a technology, e.g., "01", "02", etc. SPEC_VERSION - version number of the last final JCP specification, always of the form . IMPL_VERSION - version number of the previous final implementation OSGI_IMPL_VERSION - IMPL_VERSION truncated to . NEW_SPEC_VERSION - the version number of the specification under development NEW_IMPL_VERSION - the version number of the implementation that will be used when the implementation is final This gives us the general rules for versioning a non-final artifact: API jar file: ${API_PACKAGE}-api.jar OSGi Bundle-SymbolicName: ${API_PACKAGE}-api OSGi bundle specversion: ${SPEC_VERSION}.99.b${BUILD_NUMBER} OSGi Bundle-Version: ${SPEC_VERSION}.99.b${BUILD_NUMBER} Maven group ID, artifact ID: ${API_PACKAGE}:${API_PACKAGE}-api Maven version: ${NEW_SPEC_VERSION}-b${BUILD_NUMBER} jar Extension-Name: ${API_PACKAGE} jar Specification-Version: ${SPEC_VERSION}.99.${BUILD_NUMBER} jar Implementation-Version: ${NEW_SPEC_VERSION}-b${BUILD_NUMBER} Implementation jar file: ${API_PACKAGE}.jar OSGi Bundle-SymbolicName: ${IMPL_NAMESPACE}.${API_PACKAGE} OSGi bundle specversion: ${SPEC_VERSION}.99.b${BUILD_NUMBER} OSGi Bundle-Version: ${OSGI_IMPL_VERSION}.99.b${BUILD_NUMBER} Maven group ID, artifact ID: ${IMPL_NAMESPACE}:${API_PACKAGE} Maven version: ${NEW_IMPL_VERSION}-b${BUILD_NUMBER} jar Extension-Name: ${API_PACKAGE} jar Specification-Version: ${SPEC_VERSION}.99.${BUILD_NUMBER} jar Implementation-Version: ${NEW_IMPL_VERSION}-b${BUILD_NUMBER} Let's apply these rules to our examples: Connectors: API_PACKAGE=javax.resource IMPL_NAMESPACE=org.glassfish STANDALONE_IMPL=false BUILD_NUMBER=01 SPEC_VERSION=1.6 NEW_SPEC_VERSION=2.0 (making this up) API jar file: javax.resource-api.jar OSGi Bundle-SymbolicName: javax.resource-api OSGi bundle specversion: 1.6.99.b01 OSGi Bundle-Version: 1.6.99.b01 Maven group ID, artifact ID: javax.resource:javax.resource-api Maven version: 2.0-b01 jar Extension-Name: javax.resource jar Specification-Version: 1.6.99.01 jar Implementation-Version: 2.0-b01 JSF: API_PACKAGE=javax.faces IMPL_NAMESPACE=org.glassfish STANDALONE_IMPL=true BUILD_NUMBER=01 SPEC_VERSION=2.0 SPEC_IMPL_VERSION=2.0.2 IMPL_VERSION=2.0.2 OSGI_IMPL_VERSION=2.0 NEW_SPEC_VERSION=2.1 NEW_IMPL_VERSION=2.1 API jar file: javax.faces-api.jar OSGi Bundle-SymbolicName: javax.faces-api OSGi bundle specversion: 2.0.99.b01 OSGi Bundle-Version: 2.0.99.b01 Maven group ID, artifact ID: javax.faces:javax.faces-api Maven version: 2.1-b01 jar Extension-Name: javax.faces jar Specification-Version: 2.0.99.01 jar Implementation-Version: 2.1-b01 Implementation jar file: javax.faces.jar OSGi Bundle-SymbolicName: org.glassfish.javax.faces OSGi bundle specversion: 2.0.99.b01 OSGi Bundle-Version: 2.0.99.b01 Maven group ID, artifact ID: org.glassfish:javax.faces Maven version: 2.1-b01 jar Extension-Name: javax.faces jar Specification-Version: 2.0.99.01 jar Implementation-Version: 2.1-b01 JavaMail: API_PACKAGE=javax.mail IMPL_NAMESPACE=com.sun.mail STANDALONE_IMPL=true BUILD_NUMBER=01 SPEC_VERSION=1.4 SPEC_IMPL_VERSION=1.4.4 IMPL_VERSION=1.4.4 OSGI_IMPL_VERSION=1.4 NEW_SPEC_VERSION=1.5 NEW_IMPL_VERSION=1.5 API jar file: javax.mail-api.jar OSGi Bundle-SymbolicName: javax.mail-api OSGi bundle specversion: 1.4.99.b01 OSGi Bundle-Version: 1.4.99.b01 Maven group ID, artifact ID: javax.mail:javax.mail-api Maven version: 1.5-b01 jar Extension-Name: javax.mail jar Specification-Version: 1.4.99.01 jar Implementation-Version: 1.5-b01 Implementation jar file: javax.mail.jar OSGi Bundle-SymbolicName: com.sun.mail.javax.mail OSGi bundle specversion: 1.4.99.b01 OSGi Bundle-Version: 1.4.99.b01 Maven group ID, artifact ID: com.sun.mail:javax.mail Maven version: 1.5-b01 jar Extension-Name: javax.mail jar Specification-Version: 1.4.99.01 jar Implementation-Version: 1.5-b01 - Dependencies If the API definition of a given technology depends on the API of another technology, the API jar file should represent that dependency. Likewise, if the implementation of a given technology depends on the API or implementation of another technology, the implementation jar file should represent that dependency. The dependency should be represented using each of the relevant module technologies: -- Maven dependencies Maven dependencies should be represented in the pom.xml file for the artifact that has the dependency. API jar files should only have dependencies on other API jar file artifacts. Implementation jar files should generally have dependencies on other implementation jar file artifacts. Note that such implementation dependencies might include artifacts not defined by a JCP specification, such as Apache Commons modules. Because versions of JCP specifications are generally maintained to be upwards compatible, a dependency on an API jar artifact should include a version reference that specifies the minimum version of the dependent technology, as defined by the specification, with no maximum version number, e.g., "[1.6,)". On the other hand, implementations often depend intimately on the implementation details of dependent implementations. The version reference of a dependent implementation might be very specific or open-ended. -- OSGi dependencies We strongly recommend the use of the OSGi Import-Package header to specify dependencies. The version references should be as described above for Maven. ISSUE: We hope to provide more detailed recommendations for OSGi versioning in the future. -- jar extension dependencies The manifest of the API and implementation jar files should be used to specify dependencies on other extensions, using the extension names defined by this document. The mechanism is defined by this document: http://java.sun.com/javase/6/docs/technotes/guides/extensions/ Note that specification version references always use a "greater than or equal to" comparison. An API jar should use only Specification-Version references. An implementation jar might also use Implementation-Vendor-Id and Implementation-Version references. ISSUE: Should we include specification of *all* the jar extension headers, including Implementation-Vendor and Implementation-Vendor-Id? In addition to using the jar extension manifest headers to specify dependencies, the jar Class-Path header should be used. The simple names of the dependent jar files (using the names specified by this document) should be included in the Class-Path header. The Class-Path header of an API jar file should only include other API jar files. The Class-Path header of an implementation jar file might include other implementation jar files. - Non-standalone implementations For technologies that don't define a standalone implementation (e.g., Connectors), or for which no standalone implementation is produced (e.g., Servlets), we don't define the naming, packaging, or versioning of the implementation artifacts. In general, we would expect the implementation to follow the conventions of the larger project or product in which it is embedded. For example, the Connector and Servlet implementation artifacts follow the conventions used by other implementation artifacts that are part of GlassFish. - Source code jar files When licensing allows, we recommend that source code jar files be published to the Maven repository using the Maven convention of: Maven API jar file: ${API_PACKAGE}-api-${SPEC_IMPL_VERSION}-sources.jar Maven imp jar file: ${API_PACKAGE}-${IMPL_VERSION}-sources.jar - Special considerations for GlassFish For technologies that are included in the GlassFish workspace, it is sometimes necessary to separate the API definitions from the API implementation, e.g., in order to avoid circular dependencies between modules. In such cases, separate API and implementation jar files may be generated and delivered with GlassFish. These artifacts are not intended to be reused outside of GlassFish, and may have artifact names and version numbers that are specific to GlassFish. If a standalone version of these technologies is also made available, it should follow the rules described in this document. It might be necessary to repackage the artifacts to do so. - Transition Many of our existing artifacts are not following the guidelines above. Switching to these guidelines may disrupt users of current products and thus doing so should be done carefully and with sufficient notification to users. For example, if version 1.4 of the JavaMail implementation was previously available at http://download.java.net/maven/2/javax/mail, and version 1.5 is published at http://download.java.net/maven/2/com/sun/mail/javax/mail, users may not notice that a new version is available, or may not be able to find it easily. During a transition period it may be reasonable to publish artifacts using the existing conventions of the project, as well as publishing new artifacts with the same content using the guidelines described here. Alternatively, the Maven relocation feature described at http://maven.apache.org/guides/mini/guide-relocation.html may be used to redirect users to the new location for the artifacts. How long the transition phase should be maintained can be different for different projects, but generally should be measured in years, not months. - Maven hints If a Maven build is set up to produce an implementation jar file as defined above (that includes both the API classes and the implementation classes), an API jar file can be produced using a pom.xml of the following form: ${IMPL_NAMESPACE} all ${IMPL_VERSION} 4.0.0 ${API_PACKAGE} ${API_PACKAGE}-api ${SPEC_IMPL_VERSION} jar ${API_PACKAGE} API jar maven-dependency-plugin unpack process-sources unpack ${API_PACKAGE} ${API_PACKAGE} ${$IMPL_VERSION} ${project.build.outputDirectory} javax/**, META-INF/* maven-jar-plugin ${project.artifactId} ${project.build.outputDirectory}/META-INF/MANIFEST.MF ISSUE: Need Maven example for relocation --------------010000030405050700080501--