|
|
|||||||||||||||||||||||||||||||||||||||||||||
Stanley Ho's Blog
Versioning in the Java Module System (Part 2)Posted by stanleyh on May 29, 2008 at 04:13 PM | Permalink | Comments (5)This is the second of two articles about versioning in the Java Module System. The first article was about version format and policies.
Version rangesIn the Java Module System, modules describe their dependencies on other modules, and on particular versions of those other modules. Versions and version ranges, like all syntactic elements, are fundamentally matters of taste, but we have tried in the Java Module System to make common versioning tasks easy and advanced versioning tasks possible.
First, the Java Module System (in the forthcoming JSR 277 EDR2) adopts the OSGi syntax for version range intervals. [ and ] mean the bound is inclusive and ( and ) mean the bound is exclusive: [1.2.3, 4.5.6) ~ 1.2.3 <= x < 4.5.6
(1.2.3, 4.5.6] ~ 1.2.3 < x <= 4.5.6
(1.2.3, 4.5.6) ~ 1.2.3 < x < 4.5.6
[1.2.3, 4.5.6] ~ 1.2.3 <= x <= 4.5.6
All these intervals have the same meaning in the Java Module System as they do in OSGi.
Where the Java Module System differs from OSGi is in the interpretation of a single version. OSGi interprets a single version like 1.2.3 as "1.2.3 or greater" (OSGi R4.1 3.2.5). To get precisely version 1.2.3, you must write [1.2.3,1.2.3]. Adopting an implicit range is certainly concise, and use of exact versions is sufficiently rare that their [...,...] overhead is not too bad. But millions of programmers will first encounter versions via the Java Module System and it is best to adopt the simplest possible interpretation of any term. There is no doubt that someone seeing 1.2.3 for the first time thinks "exactly 1.2.3", so that is how the Java Module System interprets it. Ranges are denoted with explicit symbols. '+' means "or greater": 1+ ~ [1, infinity) ~ 1 <= x < infinity
1.2+ ~ [1.2, infinity) ~ 1.2 <= x < infinity
1.2.3+ ~ [1.2.3, infinity) ~ 1.2.3 <= x < infinity
1.2.3.4+ ~ [1.2.3.4, infinity) ~ 1.2.3.4 <= x < infinity
'*' means any version in a particular release family:
1.* ~ [1, 2) ~ 1 <= x < 2
1.2.* ~ [1.2, 1.3) ~ 1.2 <= x < 1.3
1.2.3.* ~ [1.2.3, 1.2.4) ~ 1.2.3 <= x < 1.2.4
Clearly, + and * in the Java Module System can express the same versions as intervals in OSGi, but without writing an ",infinity)" interval or adopting unintuitive "open versions" (1.2.3 == "1.2.3 or greater") to avoid the infinity interval.
The Java Module System also allows groups of ranges to be expressed, separated by ';'. These "union ranges" are separated by ';' because it works in command line expressions, unlike ',' and '&' ! 1.* ; [2.0, 2.7.3) ~ 1.0.0 <= x < 2.7.3
[1.2.3.4, 2.0) ; 2.* ; 3+ ~ 1.2.3.4 <= x < infinity
One feature you might expect are exclusive ranges, e.g. to express that the 2.5 product family was a disaster and should not be used. You might want to write:
[1, 3) - 2.5.*The Java Module System does not directly support exclusive ranges because it is easy to express them with union ranges: [1, 2.5) ; [2.6, 3)Or if you prefer to use a closed interval (this lets you avoid writing down the dreaded version 2.5): [1, 2.4.*] ; [2.6, 3)Now suppose the problem is narrowed down from 2.5 to 2.5.1: [1, 3) - 2.5.1.*You can express this with: [1, 2.5.1) ; [2.5.2, 3)or [1, 2.5.0.*] ; [2.5.2, 3)Happily, the precision of the exclusion does not affect the length of the union.
The cardinality of the exclusion does affect the length of the union, so excluding two version ranges: [1, 3) - 2.5.1.* - 2.6.8.*is expressible with: [1, 2.5.1) ; [2.5.2, 2.6.8) ; [2.6.9, 3)or [1, 2.5.0.*] ; [2.5.2, 2.6.7.*] ; [2.6.9, 3)The number of exclusive ranges, i.e. 2.5.1.* and 2.6.8.*, is the same as the number of ranges in the union. All the Java Module System really needs is unions (;) not exclusive ranges per se. Just as well, because taking the union of normal ranges and exclusive ranges could get pretty complicated.
In summary, we think it is reasonable for the Java Module System to let version numbers be version numbers, and introduce simple syntax (+, *) to denote ranges. Intervals work as they do in OSGi. Complex scenarios can use ; to group ranges and intervals.
Versioning in the Java Module System (Part 1)Posted by stanleyh on May 29, 2008 at 04:01 PM | Permalink | Comments (11)This is the first of two articles about versioning in the Java Module System. The second article is about version ranges.
Versioning in the Java Module SystemIn order for concrete module systems to interoperate, the abstract Java Module System defines a standard versioning scheme. Our aim as spec leads is not cause division or confusion with this scheme, but to support popular versioning practices while recognizing that versioning is new to most Java programmers. The JSR 277 Expert Group made a thorough examination of practices some time ago, and we also bring Sun's practices to the table.
Most people agree that three numbers are the core of a pragmatic versioning scheme. Most also agree that textual qualifiers best characterize qualitative behavior for a given version, e.g. "alpha release", "for customer X". The open questions are then:
Three numbers or four?The JDK uses four numbers like 1.2.2_18 or 1.4.2_16 because of its longstanding practice that the major version is 1. You can argue whether this is good practice, but it's the way the JDK is. And the JDK is not alone - Windows, .NET, Linux, Skype, Firefox and Thunderbird all use four numbers because it gives them room to breathe. If you took all the programs in the world and drew the distribution of how many use one, two, three, four or more version numbers, we suspect it would be roughly a normal distribution with a mean slightly past three.
So the JSR 277 EDR2 proposes the format of a version number as:
major[.minor[.micro[.update]]][-qualifier]
where major, minor, micro, and update are non-negative integers, i.e. 0 <= x <= java.lang.Integer.MAX_VALUE. qualifier is a string, and it can contain regular alphanumeric characters, -, and _.
(Interestingly, while you shouldn't use the qualifier to count bug fixes, it's possible in the Java Module System to do the reverse - use the bug fix "update" number in a four-number version as a kind of qualifier. A company could say that updates in the 10000-19999 range are performance-related bug fixes while updates in the 20000-29999 are fixes for a particular customer, etc. The qualifier is then available for build numbers or datestamps in text format. We don't necessarily recommend this scheme to everyone, any more than we recommend Sun's use of a fixed major number to everyone; but it's worth allowing this kind of flexibility given the incredible diversity of Java programs.)
Alex Blewitt recently characterized the JDK's fourth number as a "(failed) marketing exercise" because it allowed Sun to "hide" the fact that JDK x.y.z had n bug fixes after release (x.y.z.1 thru x.y.z.16 for JDK 1.4.2). This would be valid criticism if Sun had adopted OSGi versioning, since OSGi suggests bumping the third number for bug fixes. But that's in the context of three-number versions! We believe the guidance is really to bump the last number, which makes perfect sense. So Sun isn't "hiding" anything - the JDK has four numbers and we've bumped the fourth number over the years. Incorporating a bug fix in the first-class version number, rather than relegating it to the ranks of a qualifier, is responsible engineering. And Sun is hardly alone in using the fourth number for bug fixes.
For people who like more than four numbers, one option is to define the semantics of four numbers then allow an unbounded number of further numbers. Unfortunately, many tools will falter when presented with more than four numbers, so JSR 277 is sticking with four for now.
Qualifier semanticsAlex Blewitt also noted: "According to the documentation of 2006, the qualifier must be used for beta releases, and must not be used for released versions. In fact, the empty string for qualifier is deemed greater than any other value." The forthcoming JSR 277 EDR2 will not require the qualifier to indicate a beta version - that's a non-testable statement.
The Java Module System is sticking with the policy that "an empty string for qualifier is deemed greater than any other value". That is, we view a qualifier as somewhat subservient to "real" versions; a version without a qualifier is higher than the same version with a qualifier. 1.2.3 is higher than 1.2.3-alpha and 1.2.3-beta. This contrasts with OSGi, where 1.2.3 is less than 1.2.3.alpha and 1.2.3.beta. (OSGi R4.1 3.5.3)
Neither scheme is provably more "intuitive" than the other, but the Java Module System follows the traditional versioning policy of the JDK. It is worth examining that policy. (We mean the policy for real developer versions - 1.1.x thru 1.6.x - not the "product" versions - "Java 5.0", "Java SE 6" - used for marketing. Yes, we know the developer/product split is controversial.)
Consider a product which uses the qualifier to distinguish pre-FCS (pre-First Customer Ship) and FCS versions, e.g. 1.2.3-beta and 1.2.3-fcs. A programmer who wants to import the FCS version would have to know its exact qualifier, which is inconvenient considering each vendor will likely have their own FCS qualifier. An easier scheme, which is JDK policy, is to standardize on the unqualified version as the default "acceptable" version, and use qualifiers to denote pre-FCS versions.
If the FCS version is unqualified, how should post-FCS changes be described? The JDK policy is that once a product is given an FCS version, that version's code never changes again. Any code change raises a new version number. (Maybe with a qualifier, maybe not.) This makes support more manageable than if qualifiers express both pre-FCS and post-FCS information on the same version number.
This pair of policies let programmers easily distinguish between pre-FCS and FCS versions and between FCS and post-FCS versions.
How three numbers v. four numbers impacts qualifiersThe OSGi policy that a qualified version is preferred to an unqualified version runs into trouble with three-number versions.
Suppose you absolutely insist on using three numbers plus a qualifier. (We'll use '-' to clearly separate the qualifier from the numbers.) Pre-FCS, you have 1.2.3-alpha and 1.2.3-beta, then 1.2.3 for FCS. There are really two branches after FCS:
It's true that you could use a qualifier convention like "YYYYMMDDhhmmss-MILESTONE" to automatically put pre-FCS alpha builds before post-FCS customer patches. But in OSGi, 1.2.3 is less than any 1.2.3-20080601... version so you cannot use "just" 1.2.3 anymore; your public releases must show the qualifier with its build times and all. This is not necessarily desirable! And the more information you shoehorn into a qualifier, the easier it is to make a typing error and the harder it is for programmers to understand the meaning at a glance.
So, with only three numbers, post-FCS patches after 1.2.3 (branch 2) require either a complicated qualifier :-( or a move to 1.2.4-special. Let's assume a move to 1.2.4-special. Now, where do you do pre-FCS development of the public version after 1.2.3? (Branch 1.) If you do it as 1.2.4-alpha, 1.2.4-beta etc, you're immediately back to conventions for qualifiers on 1.2.4. Undesirable for the same reasons as above.
Using only three numbers plus a qualifier always requires complicated qualifier conventions. Four numbers gives you room to breathe.
We recognize that Sun's belief that a version without a qualifier is higher than the version with a qualifier is implicitly fond of four numbers. Four numbers allow post-FCS patches after 1.2.3 (branch 2) to go into 1.2.3.1-special (the qualifier is optional really) ... and mainstream development (branch 1) to proceed in the 1.2.4 family. Numbers and qualifiers cooperate to differentiate branches and document which branch is maintenance and which branch is mainstream development. What about interop?Module systems and frameworks which use more or less than four numbers should consider how their numbers map to the four available in the Java Module System, and whether their semantics for numbers and qualifiers agree with those of the Java Module System.
A five-number version a.b.c.d.e could map to a.b.c.d-ve where the qualifier is 'v' followed by the e number. A three-number version a.b.c could map to either:
Three numbers plus a numeric qualifier, a.b.c-d, work immediately in the Java Module System with the qualifier becoming the fourth number, a.b.c.d. Textual qualifiers are a bit complicated due to the qualifier semantics described earlier. Recall that evolving 1.2.3 to 1.2.3-special in OSGi causes the qualified 1.2.3-special to be preferred. If you map 1.2.3 to 1.2.3 and 1.2.3-special to 1.2.3-special, the Java Module System prefers 1.2.3. You should map textually-qualified versions like 1.2.3-special to 1.2.3.1-special, bumping the version number to force the (higher) qualified version to beat the (lower) unqualified version.
ConclusionThe Java Module System in the forthcoming JSR 277 EDR2 supports up to four numbers in a version for flexibility, and defines the semantics of a qualifier as somewhat subservient to numbers (1.2.3 beats 1.2.3-beta) for readability. Versions in the Java Module System are a superset of versions in OSGi, because a.b.c-qual is valid in both.Updates on Modularity in the Java platformPosted by stanleyh on May 04, 2008 at 09:55 AM | Permalink | Comments (3)There have been lots of exciting development and changes going on in the modularity areas recently. Modularity discussions in JSR 277 and JSR 294 expert groupsIn the past, the design work on modularity was split between two expert groups: JSR 294 was responsible for defining the language extension to support modularity in the Java programming language, while JSR 277 was responsible for defining the deployment aspect of the module system. The original rationale was that each expert group would have members with the most appropriate expertise to design what's best in each area for the Java platform. As it turned out, there were situations when experts needed to work at both the language and deployment levels, and a single expert group would have been more effective. To help make the discussions of modularity in Java more effective, Alex Buckley (the spec lead of JSR 294) has joined me to become a co-spec lead in JSR 277. In case you don't know Alex, he is *THE* language guy responsible for the Java Language Specification and the Java VM Specification, and I am very excited about this change. Our plan is to have all Java modularity discussions to occur in the 277 expert group from now on, and we hope this simplification will benefit everyone. JSR 277 early draft review 2 specification (Coming soon)Alex and I are currently in the middle of producing the JSR 277 early draft review 2 specification for the expert group to review and discuss. This specification will be quite different from the original JSR 277 early draft in the following ways: 1. New language support based on Alex's latest proposal. If you haven't been following the language discussion around modularity, the most significant change is that there will be a new module keyword in the Java programming language:
module org.foo.app;
package org.foo.app;
module class Main {
...
}
Defining a Java module will be as easy as declaring a module name using the new keyword. But ... what if you want to create a deployment module with metadata that could be used in the module system? Well, it will be as simple as defining a Java module with metadata annotations:
//
// org/foo/app/module-info.java
//
@Version("1.0")
@ImportModules({
@ImportModule(name="org.foo.library", version="1.0+")
})
@MainClass("org.foo.app.Main")
module org.foo.app;
I won't dive into all the details here, but hope the example gives you some idea. 2. Incorporates inputs from EDR feedbacks and EG discussions on existing design and new features. Since the original early draft was published, we have received many constructive feedbacks and most of them will be addressed in the upcoming specification. In addition, the specification will include details about resource modules (for internationalization), service/service-provider modules, etc. that have been defined by the expert group. 3. Reorganizes the specification to make the separation between the abstract module system framework and concrete module system implementation explicitly clear. The original early draft actually has two separate parts: a framework for abstract module system, and a concrete module system implementation based on JAM (JAva Module). However, the distinction in that early draft was not clear because the focus of the original early draft was to gather feedbacks on the overall design rather than individual pieces. Bryan Atsatt, a very valuable contributor in the EG, recently suggested that a clear distinction between the two would help reduce a lot of confusion, and we agreed. This reorganization will happen and it will be one of the most obvious changes in the upcoming specification. 4. Validates the specification with the reference implementation. We have been building the reference implementation (RI) through the Modules project in OpenJDK for quite some time now. The current RI has already implemented most of the functionalities as described in the upcoming EDR2, and we hope to bring the Modules project on par with the EDR2 around the same time when the specification is published. Stay tuned for more details. Support OSGi bundles in the Java Module SystemMandy Chung and I have been working on a draft specification for supporting OSGi bundles in the Java Module System, and we have just made it available for the expert group to review and discuss. We understand that people who have invested heavily in OSGi would like to preserve their existing investment going forwards, and this is what we hope the support for OSGi bundles will enable. Check out Mandy's blog if you want to learn more. JavaOne 2008JavaOne is around the corner again. This year, Alex and I will be presenting a session and a BOF on modularity: TS-6185: Modularity in Java™ Platform BOF-5032: Modularity in the Java™ Platform We'll go over the Java Module System from the language and deployment perspectives in details, and this will be a very technical and interesting talk. If you are attending JavaOne next week, we hope to see you in the session and BOF! - Stanley
|
July 2008
Search this blog:CategoriesCommunity: Java EnterpriseCommunity: Java Specification Requests Community: JavaDesktop Community: JDK Deployment J2EE J2SE JavaOne JSR Open Source Programming Security Archives
May 2008 Recent EntriesVersioning in the Java Module System (Part 2) Versioning in the Java Module System (Part 1) Updates on Modularity in the Java platform | ||||||||||||||||||||||||||||||||||||||||||||
|
|