KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > object > PortabilityImpl


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
3  * notice. All rights reserved.
4  */

5 package com.tc.object;
6
7 import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
8
9 import com.tc.aspectwerkz.reflect.impl.java.JavaClassInfo;
10 import com.tc.object.bytecode.TransparentAccess;
11 import com.tc.object.config.DSOClientConfigHelper;
12 import com.tc.util.Assert;
13 import com.tc.util.ClassUtils;
14 import com.tc.util.NonPortableReason;
15
16 import java.lang.reflect.Proxy JavaDoc;
17 import java.util.ArrayList JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Map JavaDoc;
21
22 public class PortabilityImpl implements Portability {
23
24   private static final Class JavaDoc OBJECT_CLASS = Object JavaDoc.class;
25   private static final List JavaDoc nonInstrumentedClass = new ArrayList JavaDoc();
26
27   static {
28     nonInstrumentedClass.add("java.lang.Object");
29     nonInstrumentedClass.add("java.lang.Number");
30     nonInstrumentedClass.add("java.util.AbstractList");
31     nonInstrumentedClass.add("java.util.AbstractCollection");
32     nonInstrumentedClass.add("java.lang.Enum");
33     nonInstrumentedClass.add("java.lang.reflect.AccessibleObject");
34     nonInstrumentedClass.add("java.util.concurrent.locks.AbstractQueuedSynchronizer");
35     nonInstrumentedClass.add("java.util.concurrent.locks.AbstractQueuedSynchronizer$Node");
36   }
37
38   private final LiteralValues literalValues = new LiteralValues();
39   private final Map portableCache = new ConcurrentHashMap();
40   private final Map physicalCache = new ConcurrentHashMap();
41   private final DSOClientConfigHelper config;
42
43   public PortabilityImpl(DSOClientConfigHelper config) {
44     this.config = config;
45   }
46
47   private List JavaDoc getHierarchy(Class JavaDoc start) {
48     List JavaDoc classes = new ArrayList JavaDoc();
49     while (start != null && start != OBJECT_CLASS) {
50       classes.add(start);
51       start = start.getSuperclass();
52     }
53     return classes;
54   }
55
56   public NonPortableReason getNonPortableReason(final Class JavaDoc topLevelClass) {
57     final List JavaDoc classes = getHierarchy(topLevelClass);
58
59     // check if any class in the class hierarchy is not-adaptable (like java.lang.Thread etc.)
60
for (Iterator JavaDoc i = classes.iterator(); i.hasNext();) {
61       Class JavaDoc class2Inspect = (Class JavaDoc) i.next();
62       if (config.isNeverAdaptable(JavaClassInfo.getClassInfo(class2Inspect))) {
63         if (class2Inspect == topLevelClass) {
64           return new NonPortableReason(topLevelClass, NonPortableReason.CLASS_NOT_ADAPTABLE);
65         } else {
66           NonPortableReason reason = new NonPortableReason(topLevelClass, NonPortableReason.SUPER_CLASS_NOT_ADAPTABLE);
67           reason.addErroneousSuperClass(class2Inspect);
68           return reason;
69         }
70       }
71     }
72
73     // Now check if it is a subclass of logically managed class
74
for (Iterator JavaDoc i = classes.iterator(); i.hasNext();) {
75       Class JavaDoc class2Inspect = (Class JavaDoc) i.next();
76
77       if (class2Inspect == topLevelClass) {
78         continue;
79       }
80
81       // if a parent class simply wasn't included, don't report this a logical subclass issue until it really is
82
if (!config.shouldBeAdapted(JavaClassInfo.getClassInfo(class2Inspect))) {
83         break;
84       }
85
86       if (config.isLogical(class2Inspect.getName())) {
87         NonPortableReason reason = new NonPortableReason(topLevelClass,
88                                                          NonPortableReason.SUBCLASS_OF_LOGICALLY_MANAGED_CLASS);
89         reason.addErroneousSuperClass(class2Inspect);
90         return reason;
91       }
92     }
93
94     // Finally check for the set of types that weren't instrumented
95
byte reasonCode = NonPortableReason.UNDEFINED;
96     List JavaDoc uninstrumentedSupers = new ArrayList JavaDoc();
97     for (Iterator JavaDoc i = classes.iterator(); i.hasNext();) {
98       Class JavaDoc class2Inspect = (Class JavaDoc) i.next();
99       if (class2Inspect == topLevelClass) {
100         if (!isPortableClass(class2Inspect)) {
101           Assert.assertTrue(reasonCode == NonPortableReason.UNDEFINED);
102           if (class2Inspect.getClassLoader() == null) {
103             reasonCode = NonPortableReason.CLASS_NOT_IN_BOOT_JAR;
104           } else {
105             reasonCode = NonPortableReason.CLASS_NOT_INCLUDED_IN_CONFIG;
106           }
107         }
108       } else {
109         if (reasonCode == NonPortableReason.UNDEFINED) {
110           reasonCode = NonPortableReason.SUPER_CLASS_NOT_INSTRUMENTED;
111         }
112         if (!isPortableClass(class2Inspect)) {
113           uninstrumentedSupers.add(class2Inspect);
114         }
115       }
116     }
117
118     if (reasonCode == NonPortableReason.UNDEFINED) {
119       // this indicates an error in our code
120
throw new AssertionError JavaDoc("Could not determine non-portable reason for type hierarchy: " + classes);
121     }
122
123     NonPortableReason reason = new NonPortableReason(topLevelClass, reasonCode);
124     for (Iterator JavaDoc i = uninstrumentedSupers.iterator(); i.hasNext();) {
125       reason.addErroneousSuperClass((Class JavaDoc) i.next());
126     }
127     return reason;
128   }
129
130   /*
131    * This method does not rely on the config but rather on the fact that the class has to be instrumented at this time
132    * for the object to be portable. For Logical Objects it still queries the config.
133    */

134   public boolean isPortableClass(Class JavaDoc clazz) {
135     String JavaDoc clazzName = clazz.getName();
136     Boolean JavaDoc isPortable = (Boolean JavaDoc) portableCache.get(clazzName);
137     if (isPortable != null) { return isPortable.booleanValue(); }
138
139     boolean bool = literalValues.isLiteral(clazzName) || config.isLogical(clazzName) || clazz.isArray()
140                    || Proxy.isProxyClass(clazz) || ClassUtils.isEnum(clazz) || isClassPhysicallyInstrumented(clazz)
141                    || isInstrumentationNotNeeded(clazzName) || ClassUtils.isPortableReflectionClass(clazz)
142                    || config.isPortableModuleClass(clazz);
143     portableCache.put(clazzName, Boolean.valueOf(bool));
144     return bool;
145   }
146
147   public boolean isInstrumentationNotNeeded(String JavaDoc clazzName) {
148     return nonInstrumentedClass.contains(clazzName);
149   }
150
151   public boolean isClassPhysicallyInstrumented(Class JavaDoc clazz) {
152     // this method should only return true if this class "directly" implements
153
// the interface in question. It specifically does *NOT* walk the class hierarchy looking
154
// for the interface. This always means you can't just say instanceof here
155

156     String JavaDoc clazzName = clazz.getName();
157     Boolean JavaDoc isPhysicalAdapted = (Boolean JavaDoc) physicalCache.get(clazzName);
158     if (isPhysicalAdapted != null) { return isPhysicalAdapted.booleanValue(); }
159
160     boolean rv = false;
161     Class JavaDoc interfaces[] = clazz.getInterfaces();
162     if (interfaces == null || interfaces.length == 0) return false;
163     for (int i = 0; i < interfaces.length; i++) {
164       if (interfaces[i] == TransparentAccess.class) {
165         rv = true;
166         break;
167       }
168     }
169
170     physicalCache.put(clazzName, Boolean.valueOf(rv));
171     return rv;
172   }
173
174   public boolean isPortableInstance(Object JavaDoc obj) {
175     if (obj == null) return true;
176     return isPortableClass(obj.getClass());
177   }
178
179 }
180
Popular Tags