1 4 package com.tc.object; 5 6 import sun.misc.Unsafe; 7 8 import com.tc.exception.TCRuntimeException; 9 import com.tc.logging.TCLogger; 10 import com.tc.logging.TCLogging; 11 import com.tc.object.applicator.ChangeApplicator; 12 import com.tc.object.dna.api.DNA; 13 import com.tc.object.dna.api.DNAWriter; 14 import com.tc.object.dna.impl.ProxyInstance; 15 import com.tc.object.field.TCField; 16 import com.tc.object.field.TCFieldFactory; 17 import com.tc.object.loaders.Namespace; 18 import com.tc.object.tx.optimistic.OptimisticTransactionManager; 19 import com.tc.util.Assert; 20 import com.tc.util.ClassUtils; 21 import com.tc.util.ReflectionUtil; 22 import com.tc.util.UnsafeUtil; 23 24 import java.io.IOException ; 25 import java.lang.reflect.Constructor ; 26 import java.lang.reflect.Field ; 27 import java.lang.reflect.Modifier ; 28 import java.lang.reflect.Proxy ; 29 import java.util.ConcurrentModificationException ; 30 import java.util.HashMap ; 31 import java.util.Iterator ; 32 import java.util.LinkedList ; 33 import java.util.Map ; 34 35 42 public class TCClassImpl implements TCClass { 43 private final static TCLogger logger = TCLogging.getLogger(TCClassImpl.class); 44 private final static Unsafe unsafe = UnsafeUtil.getUnsafe(); 45 46 49 private final Class peer; 50 51 private final TCClass superclazz; 52 private final TCClassFactory clazzFactory; 53 private final TCField[] portableFields; 54 private final boolean indexed; 55 private final boolean isNonStaticInner; 56 private final boolean isLogical; 57 private final boolean isCallConstructor; 58 private final String onLoadScript; 59 private final String onLoadMethod; 60 private final ChangeApplicator applicator; 61 private final String parentFieldName; 62 private final Map declaredTCFieldsByName = new HashMap (); 63 private final Map tcFieldsByName = new HashMap (); 64 private final String loaderDesc; 65 private Constructor constructor = null; 66 private final Field parentField; 67 private final static SerializationUtil SERIALIZATION_UTIL = new SerializationUtil(); 68 private final boolean useNonDefaultConstructor; 69 private Map offsetToFields; 70 private final ClientObjectManager objectManager; 71 private final boolean isProxyClass; 72 private final boolean isEnum; 73 74 private final String logicalExtendingClassName; 75 private final Class logicalSuperClass; 76 77 TCClassImpl(TCFieldFactory factory, TCClassFactory clazzFactory, ClientObjectManager objectManager, Class peer, 78 Class logicalSuperClass, String loaderDesc, String logicalExtendingClassName, boolean isLogical, 79 boolean isCallConstructor, String onLoadScript, String onLoadMethod, boolean useNonDefaultConstructor) { 80 this.clazzFactory = clazzFactory; 81 this.objectManager = objectManager; 82 this.peer = peer; 83 this.loaderDesc = loaderDesc; 84 this.indexed = peer.isArray(); 85 86 boolean isStatic = Modifier.isStatic(peer.getModifiers()); 87 boolean mightBeInner = peer.getName().indexOf('$') != -1 && !isIndexed(); 88 this.parentField = mightBeInner && !isStatic ? findParentField() : null; 89 this.isNonStaticInner = parentField != null; 90 this.parentFieldName = parentField == null ? null : getName() + '.' + parentField.getName(); 91 92 this.isLogical = isLogical; 93 this.isProxyClass = Proxy.isProxyClass(peer) || ProxyInstance.class.getName().equals(peer.getName()); 94 this.isCallConstructor = isCallConstructor; 95 this.onLoadScript = onLoadScript; 96 this.onLoadMethod = onLoadMethod; 97 this.superclazz = findSuperClass(peer); 98 this.isEnum = ClassUtils.isEnum(peer); 99 this.logicalExtendingClassName = logicalExtendingClassName; 100 101 this.applicator = createApplicator(); 102 103 introspectFields(peer, factory); 104 this.portableFields = createPortableFields(); 105 this.useNonDefaultConstructor = isProxyClass || ClassUtils.isPortableReflectionClass(peer) || useNonDefaultConstructor; 106 this.logicalSuperClass = logicalSuperClass; 107 } 108 109 public Field getParentField() { 110 return parentField; 111 } 112 113 public boolean isNonStaticInner() { 114 return this.isNonStaticInner; 115 } 116 117 public Class getPeerClass() { 118 return this.peer; 119 } 120 121 private Field findParentField() { 122 Field[] fields = peer.getDeclaredFields(); 123 for (int i = 0; i < fields.length; i++) { 124 if (SERIALIZATION_UTIL.isParent(fields[i].getName())) return fields[i]; 125 } 126 return null; 127 } 128 129 private TCClass findSuperClass(Class c) { 130 Class superclass = c.getSuperclass(); 131 if (superclass != null) { return clazzFactory.getOrCreate(superclass, objectManager); } 132 return null; 133 } 134 135 private ChangeApplicator createApplicator() { 136 return clazzFactory.createApplicatorFor(this, indexed); 137 } 138 139 public void hydrate(TCObject tcObject, DNA dna, Object pojo, boolean force) throws IOException , 140 ClassNotFoundException { 141 148 final long localVersion = tcObject.getVersion(); 149 final long dnaVersion = dna.getVersion(); 150 151 if (force || (localVersion < dnaVersion)) { 152 tcObject.setVersion(dnaVersion); 153 applicator.hydrate(objectManager, tcObject, dna, pojo); 154 } else { 155 if (logger.isDebugEnabled()) { 156 logger.debug("IGNORING UPDATE, local object at version " + localVersion + ", dna update is version " 157 + dnaVersion); 158 } 159 } 160 161 } 162 163 public void dehydrate(TCObject tcObject, DNAWriter writer, Object pojo) { 164 try { 165 applicator.dehydrate(objectManager, tcObject, writer, pojo); 166 } catch (ConcurrentModificationException cme) { 167 String type = pojo == null ? "null" : pojo.getClass().getName(); 170 String toString = String.valueOf(pojo); 171 int ihc = System.identityHashCode(pojo); 172 logger.error("Shared object (presumably new) modified during dehydrate (type " + type + ", ihc " + ihc + "): " 173 + toString, cme); 174 throw cme; 175 } 176 } 177 178 public Class getComponentType() { 179 return peer.getComponentType(); 180 } 181 182 public boolean isEnum() { 183 return isEnum; 184 } 185 186 public String getName() { 187 if (isProxyClass) { return ProxyInstance.class.getName(); } 188 if (isEnum) { return LiteralValues.ENUM_CLASS_DOTS; } 189 return peer.getName(); 190 } 191 192 public String getExtendingClassName() { 193 String className = getName(); 194 if (this.logicalExtendingClassName != null) { 195 className = Namespace.createLogicalExtendingClassName(className, logicalExtendingClassName); 196 } 197 return className; 198 } 199 200 public TCClass getSuperclass() { 201 return superclazz; 202 } 203 204 public synchronized Constructor getConstructor() { 205 if (constructor == null) { 206 constructor = findConstructor(); 210 } 211 return constructor; 212 } 213 214 public boolean hasOnLoadExecuteScript() { 215 return onLoadScript != null; 216 } 217 218 public String getOnLoadExecuteScript() { 219 Assert.eval(hasOnLoadExecuteScript()); 220 return onLoadScript; 221 } 222 223 public String getOnLoadMethod() { 224 Assert.eval(hasOnLoadMethod()); 225 return onLoadMethod; 226 } 227 228 private Constructor findConstructor() { 229 Constructor rv = null; 230 231 if (isCallConstructor || isLogical) { 232 Constructor [] cons = peer.getDeclaredConstructors(); 233 for (int i = 0; i < cons.length; i++) { 234 Class [] types = cons[i].getParameterTypes(); 235 if (types.length == 0) { 236 rv = cons[i]; 237 rv.setAccessible(true); 238 return rv; 239 } 240 } 241 } 242 243 if (rv == null) { 244 rv = ReflectionUtil.newConstructor(peer, logicalSuperClass); 245 rv.setAccessible(true); 246 } 247 return rv; 248 } 249 250 public String getParentFieldName() { 251 return parentFieldName; 252 } 253 254 private void introspectFields(Class clazz, TCFieldFactory fieldFactory) { 255 Field[] fields = clazz.equals(Object .class) ? new Field[0] : clazz.getDeclaredFields(); 258 259 Field field; 260 TCField tcField; 261 for (int i = 0; i < fields.length; i++) { 262 field = fields[i]; 263 tcField = fieldFactory.getInstance(this, field); 265 declaredTCFieldsByName.put(field.getName(), tcField); 266 tcFieldsByName.put(tcField.getName(), tcField); 267 } 268 } 269 270 public String toString() { 271 return peer.getName(); 272 } 273 274 277 public TCField getField(String name) { 278 TCField rv = (TCField) tcFieldsByName.get(name); 279 if (rv == null && superclazz != null) { 280 rv = superclazz.getField(name); 281 } 282 return rv; 283 } 284 285 public TCField[] getPortableFields() { 286 return portableFields; 287 } 288 289 public TraversedReferences getPortableObjects(Object pojo, TraversedReferences addTo) { 290 return applicator.getPortableObjects(pojo, addTo); 291 } 292 293 private TCField[] createPortableFields() { 294 if (isLogical || !objectManager.isPortableClass(this.peer)) { return new TCField[0]; } 295 LinkedList l = new LinkedList (); 296 for (Iterator i = declaredTCFieldsByName.values().iterator(); i.hasNext();) { 297 298 TCField f = (TCField) i.next(); 299 if (f.isPortable()) { 300 l.add(f); 301 } 302 } 303 return (TCField[]) l.toArray(new TCField[l.size()]); 304 } 305 306 public Map connectedCopy(Object source, Object dest, Map visited, OptimisticTransactionManager txManager) { 307 return this.applicator.connectedCopy(source, dest, visited, objectManager, txManager); 308 } 309 310 public boolean isIndexed() { 311 return indexed; 312 } 313 314 public String getDefiningLoaderDescription() { 315 return loaderDesc; 316 } 317 318 public boolean isLogical() { 319 return isLogical; 320 } 321 322 public ClientObjectManager getObjectManager() { 323 return objectManager; 324 } 325 326 public TCObject createTCObject(ObjectID id, Object pojo) { 327 if (isLogical) { 328 return new TCObjectLogical(objectManager.getReferenceQueue(), id, pojo, this); 329 } else { 330 return new TCObjectPhysical(objectManager.getReferenceQueue(), id, pojo, this); 331 } 332 } 333 334 public boolean hasOnLoadMethod() { 335 return onLoadMethod != null; 336 } 337 338 public boolean isUseNonDefaultConstructor() { 339 return useNonDefaultConstructor; 340 } 341 342 public Object getNewInstanceFromNonDefaultConstructor(DNA dna) throws IOException , ClassNotFoundException { 343 Object o = applicator.getNewInstance(objectManager, dna); 344 345 if (o == null) { throw new AssertionError ("Can't find suitable constructor for class: " + getName() + "."); } 346 return o; 347 } 348 349 public String getFieldNameByOffset(long fieldOffset) { 350 Long fieldOffsetObj = new Long (fieldOffset); 351 if (offsetToFields == null) { 352 offsetToFields = new HashMap (); 353 if (unsafe != null) { 354 try { 355 Field[] fields = peer.equals(Object .class) ? new Field[0] : peer.getDeclaredFields(); 356 for (int i = 0; i < fields.length; i++) { 357 try { 358 if (!Modifier.isStatic(fields[i].getModifiers())) { 359 fields[i].setAccessible(true); 360 offsetToFields.put(new Long (unsafe.objectFieldOffset(fields[i])), fields[i]); 361 } 362 } catch (Exception e) { 363 } 365 } 366 } catch (Exception e) { 367 throw new TCRuntimeException(e); 368 } 369 } 370 } 371 Field field = (Field) this.offsetToFields.get(fieldOffsetObj); 372 if (field == null) { 373 if (superclazz != null) { 374 return superclazz.getFieldNameByOffset(fieldOffset); 375 } else { 376 throw new AssertionError ("Field does not exist for offset: " + fieldOffset); 377 } 378 } else { 379 StringBuffer sb = new StringBuffer (field.getDeclaringClass().getName()); 380 sb.append("."); 381 sb.append(field.getName()); 382 return sb.toString(); 383 } 384 } 385 386 public boolean isProxyClass() { 387 return isProxyClass; 388 } 389 } 390 | Popular Tags |