001: /*
002: * Copyright (C) 2004, 2005, 2006 Joe Walnes.
003: * Copyright (C) 2006, 2007, 2008 XStream Committers.
004: * All rights reserved.
005: *
006: * The software in this package is published under the terms of the BSD
007: * style license a copy of which has been included with this distribution in
008: * the LICENSE.txt file.
009: *
010: * Created on 09. May 2004 by Joe Walnes
011: */
012: package com.thoughtworks.xstream.core;
013:
014: import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider;
015: import com.thoughtworks.xstream.converters.reflection.ReflectionProvider;
016:
017: import java.lang.ref.WeakReference;
018: import java.lang.reflect.Field;
019: import java.security.AccessControlException;
020: import java.text.AttributedString;
021: import java.util.HashMap;
022: import java.util.Map;
023:
024: public class JVM {
025:
026: private ReflectionProvider reflectionProvider;
027: private transient Map loaderCache = new HashMap();
028:
029: private final boolean supportsAWT = loadClass("java.awt.Color") != null;
030: private final boolean supportsSwing = loadClass("javax.swing.LookAndFeel") != null;
031: private final boolean supportsSQL = loadClass("java.sql.Date") != null;
032:
033: private static final String vendor = System
034: .getProperty("java.vm.vendor");
035: private static final float majorJavaVersion = getMajorJavaVersion();
036: private static final boolean reverseFieldOrder = isHarmony()
037: || (isIBM() && !is15());
038:
039: static final float DEFAULT_JAVA_VERSION = 1.3f;
040:
041: /**
042: * Parses the java version system property to determine the major java version,
043: * i.e. 1.x
044: *
045: * @return A float of the form 1.x
046: */
047: private static final float getMajorJavaVersion() {
048: try {
049: return Float.parseFloat(System
050: .getProperty("java.specification.version"));
051: } catch (NumberFormatException e) {
052: // Some JVMs may not conform to the x.y.z java.version format
053: return DEFAULT_JAVA_VERSION;
054: }
055: }
056:
057: public static boolean is14() {
058: return majorJavaVersion >= 1.4f;
059: }
060:
061: public static boolean is15() {
062: return majorJavaVersion >= 1.5f;
063: }
064:
065: public static boolean is16() {
066: return majorJavaVersion >= 1.6f;
067: }
068:
069: private static boolean isSun() {
070: return vendor.indexOf("Sun") != -1;
071: }
072:
073: private static boolean isApple() {
074: return vendor.indexOf("Apple") != -1;
075: }
076:
077: private static boolean isHPUX() {
078: return vendor.indexOf("Hewlett-Packard Company") != -1;
079: }
080:
081: private static boolean isIBM() {
082: return vendor.indexOf("IBM") != -1;
083: }
084:
085: private static boolean isBlackdown() {
086: return vendor.indexOf("Blackdown") != -1;
087: }
088:
089: private static boolean isHarmony() {
090: return vendor.indexOf("Apache Software Foundation") != -1;
091: }
092:
093: /*
094: * Support for sun.misc.Unsafe and sun.reflect.ReflectionFactory is present
095: * in JRockit versions R25.1.0 and later, both 1.4.2 and 5.0 (and in future
096: * 6.0 builds).
097: */
098: private static boolean isBEAWithUnsafeSupport() {
099: // This property should be "BEA Systems, Inc."
100: if (vendor.indexOf("BEA") != -1) {
101:
102: /*
103: * Recent 1.4.2 and 5.0 versions of JRockit have a java.vm.version
104: * string starting with the "R" JVM version number, i.e.
105: * "R26.2.0-38-57237-1.5.0_06-20060209..."
106: */
107: String vmVersion = System.getProperty("java.vm.version");
108: if (vmVersion.startsWith("R")) {
109: /*
110: * We *could* also check that it's R26 or later, but that is
111: * implicitly true
112: */
113: return true;
114: }
115:
116: /*
117: * For older JRockit versions we can check java.vm.info. JRockit
118: * 1.4.2 R24 -> "Native Threads, GC strategy: parallel" and JRockit
119: * 5.0 R25 -> "R25.2.0-28".
120: */
121: String vmInfo = System.getProperty("java.vm.info");
122: if (vmInfo != null) {
123: // R25.1 or R25.2 supports Unsafe, other versions do not
124: return (vmInfo.startsWith("R25.1") || vmInfo
125: .startsWith("R25.2"));
126: }
127: }
128: // If non-BEA, or possibly some very old JRockit version
129: return false;
130: }
131:
132: private static boolean isHitachi() {
133: return vendor.indexOf("Hitachi") != -1;
134: }
135:
136: private static boolean isSAP() {
137: return vendor.indexOf("SAP AG") != -1;
138: }
139:
140: public Class loadClass(String name) {
141: try {
142: WeakReference reference = (WeakReference) loaderCache
143: .get(name);
144: if (reference != null) {
145: Class cached = (Class) reference.get();
146: if (cached != null) {
147: return cached;
148: }
149: }
150:
151: Class clazz = Class.forName(name, false, getClass()
152: .getClassLoader());
153: loaderCache.put(name, new WeakReference(clazz));
154: return clazz;
155: } catch (ClassNotFoundException e) {
156: return null;
157: }
158: }
159:
160: public synchronized ReflectionProvider bestReflectionProvider() {
161: if (reflectionProvider == null) {
162: try {
163: if (canUseSun14ReflectionProvider()) {
164: String cls = "com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider";
165: reflectionProvider = (ReflectionProvider) loadClass(
166: cls).newInstance();
167: } else if (canUseHarmonyReflectionProvider()) {
168: String cls = "com.thoughtworks.xstream.converters.reflection.HarmonyReflectionProvider";
169: reflectionProvider = (ReflectionProvider) loadClass(
170: cls).newInstance();
171: }
172: if (reflectionProvider == null) {
173: reflectionProvider = new PureJavaReflectionProvider();
174: }
175: } catch (InstantiationException e) {
176: reflectionProvider = new PureJavaReflectionProvider();
177: } catch (IllegalAccessException e) {
178: reflectionProvider = new PureJavaReflectionProvider();
179: } catch (AccessControlException e) {
180: // thrown when trying to access sun.misc package in Applet context.
181: reflectionProvider = new PureJavaReflectionProvider();
182: }
183: }
184: return reflectionProvider;
185: }
186:
187: private boolean canUseSun14ReflectionProvider() {
188: return (isSun() || isApple() || isHPUX() || isIBM()
189: || isBlackdown() || isBEAWithUnsafeSupport()
190: || isHitachi() || isSAP())
191: && is14() && loadClass("sun.misc.Unsafe") != null;
192: }
193:
194: private boolean canUseHarmonyReflectionProvider() {
195: return isHarmony();
196: }
197:
198: public static boolean reverseFieldDefinition() {
199: return reverseFieldOrder;
200: }
201:
202: /**
203: * Checks if the jvm supports awt.
204: */
205: public boolean supportsAWT() {
206: return this .supportsAWT;
207: }
208:
209: /**
210: * Checks if the jvm supports swing.
211: */
212: public boolean supportsSwing() {
213: return this .supportsSwing;
214: }
215:
216: /**
217: * Checks if the jvm supports sql.
218: */
219: public boolean supportsSQL() {
220: return this .supportsSQL;
221: }
222:
223: private Object readResolve() {
224: loaderCache = new HashMap();
225: return this ;
226: }
227:
228: public static void main(String[] args) {
229: boolean reverse = false;
230: Field[] fields = AttributedString.class.getDeclaredFields();
231: for (int i = 0; i < fields.length; i++) {
232: if (fields[i].getName().equals("text")) {
233: reverse = i > 3;
234: break;
235: }
236: }
237: if (reverse) {
238: fields = JVM.class.getDeclaredFields();
239: for (int i = 0; i < fields.length; i++) {
240: if (fields[i].getName().equals("reflectionProvider")) {
241: reverse = i > 2;
242: break;
243: }
244: }
245: }
246:
247: JVM jvm = new JVM();
248: System.out.println("XStream JVM diagnostics");
249: System.out.println("java.specification.version: "
250: + System.getProperty("java.specification.version"));
251: System.out.println("java.vm.vendor: " + vendor);
252: System.out.println("Version: " + majorJavaVersion);
253: System.out.println("XStream support for enhanced Mode: "
254: + (jvm.canUseSun14ReflectionProvider() || jvm
255: .canUseHarmonyReflectionProvider()));
256: System.out.println("Supports AWT: " + jvm.supportsAWT());
257: System.out.println("Supports SQL: " + jvm.supportsSQL());
258: System.out
259: .println("Reverse field order detected (may have failed): "
260: + reverse);
261: }
262: }
|