001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.util.runtime;
006:
007: import java.lang.reflect.Method;
008: import java.util.Properties;
009: import java.util.regex.Matcher;
010: import java.util.regex.Pattern;
011:
012: /**
013: * Stores parsed version information
014: */
015: public final class VmVersion {
016:
017: private static final Pattern JVM_VERSION_PATTERN = Pattern
018: .compile("^(\\p{Digit})\\.(\\p{Digit})\\.(\\p{Digit})(?:[-_](.+))?$");
019: private static final Pattern IBM_SERVICE_RELEASE_PATTERN = Pattern
020: .compile("^[^-]+-\\p{Digit}{8}[^\\p{Space}]*\\p{Space}*\\(.*(SR\\p{Digit}+).*\\)$");
021:
022: private final String vmVersion;
023: private final int mega;
024: private final int major;
025: private final int minor;
026: private final String patch;
027: private final boolean isIBM;
028: private final boolean isJRockit;
029:
030: /**
031: * Construct with system properties, which will be parsed to determine version. Looks at properties like java.version,
032: * java.runtime.version, jrockit.version, java.vm.name, and java.vendor.
033: *
034: * @param Properties Typically System.getProperties()
035: * @throws UnknownJvmVersionException If JVM version is unknown
036: * @throws UnknownRuntimeVersionException If Java runtime version is unknown
037: */
038: public VmVersion(final Properties props)
039: throws UnknownJvmVersionException,
040: UnknownRuntimeVersionException {
041: this (javaVersion(props), runtimeVersion(props),
042: isJRockit(props), isIBM(props));
043: }
044:
045: /**
046: * Construct with specific version information
047: *
048: * @param vendorVersion Version pattern like 1.4.2_12
049: * @param runtimeVersion Runtime version pattern like 1.4.2_12-269
050: * @param isJRockit True if BEA JRockit JVM
051: * @param isIBM True if IBM JVM
052: * @throws UnknownJvmVersionException If JVM version is unknown
053: * @throws UnknownRuntimeVersionException If Java runtime version is unknown
054: */
055: private VmVersion(final String vendorVersion,
056: final String runtimeVersion, final boolean isJRockit,
057: final boolean isIBM) throws UnknownJvmVersionException,
058: UnknownRuntimeVersionException {
059: this .isIBM = isIBM;
060: this .isJRockit = isJRockit;
061: final Matcher versionMatcher = JVM_VERSION_PATTERN
062: .matcher(vendorVersion);
063: if (versionMatcher.matches()) {
064: mega = Integer.parseInt(versionMatcher.group(1));
065: major = Integer.parseInt(versionMatcher.group(2));
066: minor = Integer.parseInt(versionMatcher.group(3));
067: String version_patch = versionMatcher.groupCount() == 4 ? versionMatcher
068: .group(4)
069: : null;
070: if (isIBM) {
071: final Matcher serviceReleaseMatcher = IBM_SERVICE_RELEASE_PATTERN
072: .matcher(runtimeVersion);
073: if (serviceReleaseMatcher.matches()) {
074: String serviceRelease = serviceReleaseMatcher
075: .groupCount() == 1 ? serviceReleaseMatcher
076: .group(1).toLowerCase() : null;
077: if (null == version_patch && null == serviceRelease) {
078: patch = null;
079: } else if (null == version_patch) {
080: patch = serviceRelease;
081: } else if (null == serviceRelease) {
082: patch = version_patch;
083: } else {
084: patch = version_patch + serviceRelease;
085: }
086: } else {
087: throw new UnknownRuntimeVersionException(
088: vendorVersion, runtimeVersion);
089: }
090: } else {
091: patch = version_patch;
092: }
093: } else {
094: throw new UnknownJvmVersionException(vendorVersion);
095: }
096: this .vmVersion = this .mega + "." + this .major + "."
097: + this .minor + (null == patch ? "" : "_" + patch);
098: }
099:
100: /**
101: * Given the history of SunOS and Java version numbering by Sun, this will return '1' for a long time to come. Mega
102: * version = 1 in 1.2.3
103: *
104: * @return Mega version
105: */
106: public int getMegaVersion() {
107: return mega;
108: }
109:
110: /**
111: * Get major version (ie 2 in 1.2.3)
112: *
113: * @return Major version
114: */
115: public int getMajorVersion() {
116: return major;
117: }
118:
119: /**
120: * Get minor version (ie 3 in 1.2.3)
121: *
122: * @return Minor version
123: */
124: public int getMinorVersion() {
125: return minor;
126: }
127:
128: /**
129: * Get patch level (ie 12 in 1.2.3_12)
130: *
131: * @return Patch level
132: */
133: public String getPatchLevel() {
134: return patch;
135: }
136:
137: /**
138: * @return True if JDK 1.4
139: */
140: public boolean isJDK14() {
141: return mega == 1 && major == 4;
142: }
143:
144: /**
145: * @return True if JDK 1.5
146: */
147: public boolean isJDK15() {
148: return mega == 1 && major == 5;
149: }
150:
151: /**
152: * @return True if JDK 1.6
153: */
154: public boolean isJDK16() {
155: return mega == 1 && major == 6;
156: }
157:
158: /**
159: * @return True if JDK 1.7
160: */
161: public boolean isJDK17() {
162: return mega == 1 && major == 7;
163: }
164:
165: /**
166: * @return True if IBM JVM
167: */
168: public boolean isIBM() {
169: return isIBM;
170: }
171:
172: /**
173: * @return True if BEA JRockit
174: */
175: public boolean isJRockit() {
176: return isJRockit;
177: }
178:
179: /**
180: * @param o Other version
181: * @return True if other version has identical version string
182: */
183: public boolean equals(final Object o) {
184: if (!(o instanceof VmVersion)) {
185: return false;
186: }
187:
188: final VmVersion other = (VmVersion) o;
189: return vmVersion.equals(other.vmVersion);
190: }
191:
192: public int hashCode() {
193: return vmVersion.hashCode();
194: }
195:
196: public String toString() {
197: return vmVersion;
198: }
199:
200: private static String javaVersion(Properties props) {
201: return props.getProperty("java.version",
202: "<error: java.version not specified in properties>");
203: }
204:
205: private static String runtimeVersion(Properties props) {
206: if (this VMisIBM()) {
207: // It's not safe to read "java.runtime.version" from system properties until a certain point in startup
208: // Specifically there is a race to set this prop in com.ibm.misc.SystemIntialization.lastChanceHook() and the
209: // start of the management agent thread there (MNK-393)
210: return getIBMRuntimeVersion();
211: } else {
212: return props
213: .getProperty("java.runtime.version",
214: "<error: java.runtime.version not specified in properties>");
215: }
216: }
217:
218: static boolean this VMisIBM() {
219: return isIBM(System.getProperties());
220: }
221:
222: private static String getIBMRuntimeVersion() {
223: try {
224: Class c = Class.forName("com.ibm.misc.JavaRuntimeVersion");
225: Method m = c.getDeclaredMethod("getValue", new Class[] {});
226: m.setAccessible(true);
227: return (String) m.invoke(c, new Object[] {});
228: } catch (Throwable t) {
229: throw new RuntimeException(t);
230: }
231: }
232:
233: private static boolean isIBM(Properties props) {
234: return props.getProperty("java.vendor", "").toLowerCase()
235: .startsWith("ibm ");
236: }
237:
238: private static boolean isJRockit(Properties props) {
239: return props.getProperty("jrockit.version") != null
240: || props.getProperty("java.vm.name", "").toLowerCase()
241: .indexOf("jrockit") >= 0;
242: }
243:
244: }
|