1 5 package com.tc.object; 6 7 import bsh.EvalError; 8 import bsh.Interpreter; 9 import bsh.ParseException; 10 11 import com.tc.logging.CustomerLogging; 12 import com.tc.logging.TCLogger; 13 import com.tc.logging.TCLogging; 14 import com.tc.object.bytecode.Manageable; 15 import com.tc.object.bytecode.TransparentAccess; 16 import com.tc.object.dna.api.DNA; 17 import com.tc.object.dna.api.DNAException; 18 import com.tc.object.dna.api.DNAWriter; 19 import com.tc.object.field.TCField; 20 import com.tc.util.Assert; 21 import com.tc.util.Conversion; 22 import com.tc.util.Util; 23 24 import gnu.trove.TLinkable; 25 26 import java.io.IOException ; 27 import java.lang.ref.ReferenceQueue ; 28 29 33 public abstract class TCObjectImpl implements TCObject { 34 private static final TCLogger logger = TCLogging.getLogger(TCObjectImpl.class); 35 36 private static final int ACCESSED_OFFSET = 1; 37 private static final int IS_NEW_OFFSET = 2; 38 private static final int AUTOLOCKS_DISABLED_OFFSET = 4; 39 private static final int EVICTION_IN_PROGRESS_OFFSET = 8; 40 41 private long version = 0; 42 43 private final ObjectID objectID; 44 protected final TCClass tcClazz; 45 private WeakObjectReference peerObject; 46 private TLinkable next; 47 private TLinkable previous; 48 private byte flags = 0; 49 private static final TCLogger consoleLogger = CustomerLogging.getConsoleLogger(); 50 51 protected TCObjectImpl(ReferenceQueue queue, ObjectID id, Object peer, TCClass clazz) { 52 this.objectID = id; 53 this.tcClazz = clazz; 54 setPeerObject(new WeakObjectReference(id, peer, queue)); 55 } 56 57 public boolean isShared() { 58 return true; 59 } 60 61 public boolean isNull() { 62 return peerObject == null || getPeerObject() == null; 63 } 64 65 public ObjectID getObjectID() { 66 return objectID; 67 } 68 69 protected ClientObjectManager getObjectManager() { 70 return tcClazz.getObjectManager(); 71 } 72 73 public Object getPeerObject() { 74 return peerObject.get(); 75 } 76 77 protected void setPeerObject(WeakObjectReference pojo) { 78 this.peerObject = pojo; 79 Object realPojo; 80 if ((realPojo = peerObject.get()) instanceof Manageable) { 81 Manageable m = (Manageable) realPojo; 82 m.__tc_managed(this); 83 } 84 } 85 86 public TCClass getTCClass() { 87 return tcClazz; 88 } 89 90 97 public void hydrate(DNA from, boolean force) throws ClassNotFoundException { 98 synchronized (getResolveLock()) { 99 boolean isNewLoad = isNull(); 100 createPeerObjectIfNecessary(from); 101 102 Object po = getPeerObject(); 103 if (po == null) return; 104 try { 105 tcClazz.hydrate(this, from, po, force); 106 if (isNewLoad) performOnLoadActionIfNecessary(po); 107 } catch (ClassNotFoundException e) { 108 logger.warn("Re-throwing Exception: " , e); 109 throw e; 110 } catch (IOException e) { 111 logger.warn("Re-throwing Exception: " , e); 112 throw new DNAException(e); 113 } 114 } 115 } 116 117 private void performOnLoadActionIfNecessary(Object pojo) { 118 TCClass tcc = getTCClass(); 119 if (tcc.hasOnLoadExecuteScript() || tcc.hasOnLoadMethod()) { 120 String eval = tcc.hasOnLoadExecuteScript() ? tcc.getOnLoadExecuteScript() : "self." + tcc.getOnLoadMethod() 121 + "()"; 122 resolveAllReferences(); 123 124 ClassLoader prevLoader = Thread.currentThread().getContextClassLoader(); 125 Thread.currentThread().setContextClassLoader(pojo.getClass().getClassLoader()); 126 try { 127 Interpreter i = new Interpreter(); 128 i.setClassLoader(tcc.getPeerClass().getClassLoader()); 129 i.set("self", pojo); 130 i.eval("setAccessibility(true)"); 131 i.eval(eval); 132 } catch (ParseException e) { 133 consoleLogger.error("Unable to parse OnLoad script: " + pojo.getClass() + " error: " + e.getMessage() 138 + " stack: " + e.getScriptStackTrace()); 139 logger.error("Unable to parse OnLoad script: " + pojo.getClass() + " error: " + e.getMessage() + " line: " 140 + " stack: " + e.getScriptStackTrace()); 141 } catch (EvalError e) { 142 consoleLogger.error("OnLoad execute script failed for: " + pojo.getClass() + " error: " + e.getErrorText() 144 + " line: " + e.getErrorLineNumber() + "; " + e.getMessage() + "; stack: " 145 + e.getScriptStackTrace()); 146 logger.error("OnLoad execute script failed for: " + pojo.getClass() + " error: " + e.getErrorText() + " line: " 147 + e.getErrorLineNumber() + "; " + e.getMessage() + "; stack: " + e.getScriptStackTrace()); 148 } finally { 149 Thread.currentThread().setContextClassLoader(prevLoader); 150 } 151 } 152 } 153 154 protected synchronized void setFlag(int offset, boolean value) { 155 flags = Conversion.setFlag(flags, offset, value); 156 } 157 158 private synchronized boolean getFlag(int offset) { 159 return Conversion.getFlag(flags, offset); 160 } 161 162 private void createPeerObjectIfNecessary(DNA from) { 163 if (isNull()) { 164 setPeerObject(getObjectManager().createNewPeer(tcClazz, from)); 166 } 167 } 168 169 public void setReference(String fieldName, ObjectID id) { 170 throw new AssertionError ("shouldn't be called"); 171 } 172 173 public void setValue(String fieldName, Object obj) { 174 try { 175 TransparentAccess ta = (TransparentAccess) getPeerObject(); 176 if (ta == null) { 177 return; 179 } 180 clearReference(fieldName); 181 TCField field = getTCClass().getField(fieldName); 182 if (field == null) { 183 logger.warn("Data for field:" + fieldName + " was recieved but that field does not exist in class:"); 184 return; 185 } 186 if (obj instanceof ObjectID) { 187 setReference(fieldName, (ObjectID) obj); 188 if (!field.isFinal()) { 189 ta.__tc_setfield(field.getName(), null); 190 } 191 } else { 192 ta.__tc_setfield(field.getName(), obj); 194 } 195 } catch (Exception e) { 196 throw new com.tc.object.dna.api.DNAException(e); 198 } 199 } 200 201 public int clearReferences(int toClear) { 202 synchronized (getResolveLock()) { 203 try { 204 Object po = getPeerObject(); 205 Assert.assertFalse(isNew()); if (po == null) return 0; 207 return clearReferences(po, toClear); 208 } finally { 209 setEvictionInProgress(false); 210 } 211 } 212 } 213 214 protected abstract int clearReferences(Object pojo, int toClear); 215 216 public final Object getResolveLock() { 217 return objectID; } 219 220 public void resolveArrayReference(int index) { 221 throw new AssertionError ("shouldn't be called"); 222 } 223 224 public ArrayIndexOutOfBoundsException checkArrayIndex(int index) { 225 throw new AssertionError ("shouldn't be called"); 226 } 227 228 public void clearArrayReference(int index) { 229 clearReference(Integer.toString(index)); 230 } 231 232 public void clearReference(String fieldName) { 233 } 235 236 public void resolveReference(String fieldName) { 237 } 239 240 public void resolveAllReferences() { 241 } 243 244 public void literalValueChanged(Object newValue, Object oldValue) { 245 throw new UnsupportedOperationException (); 246 } 247 248 public void setLiteralValue(Object newValue) { 249 throw new UnsupportedOperationException (); 250 } 251 252 255 public void dehydrate(DNAWriter writer) throws DNAException { 256 tcClazz.dehydrate(this, writer, getPeerObject()); 257 } 258 259 public synchronized void setVersion(long version) { 260 this.version = version; 261 } 262 263 public synchronized long getVersion() { 264 return this.version; 265 } 266 267 public String toString() { 268 return getClass().getName() + "@" + System.identityHashCode(this) + "[objectID=" + objectID + ", TCClass=" 269 + tcClazz + "]"; 270 } 271 272 public void objectFieldChanged(String classname, String fieldname, Object newValue, int index) { 273 try { 274 this.markAccessed(); 275 if (index == NULL_INDEX) { 276 clearReference(fieldname); 278 } else { 279 clearArrayReference(index); 280 } 281 getObjectManager().getTransactionManager().fieldChanged(this, classname, fieldname, newValue, index); 282 } catch (Throwable t) { 283 Util.printLogAndRethrowError(t, logger); 284 } 285 } 286 287 public void objectFieldChangedByOffset(String classname, long fieldOffset, Object newValue, int index) { 288 String fieldname = tcClazz.getFieldNameByOffset(fieldOffset); 289 objectFieldChanged(classname, fieldname, newValue, index); 290 } 291 292 public String getFieldNameByOffset(long fieldOffset) { 293 return tcClazz.getFieldNameByOffset(fieldOffset); 294 } 295 296 public void booleanFieldChanged(String classname, String fieldname, boolean newValue, int index) { 297 objectFieldChanged(classname, fieldname, new Boolean (newValue), index); 298 } 299 300 public void byteFieldChanged(String classname, String fieldname, byte newValue, int index) { 301 objectFieldChanged(classname, fieldname, new Byte (newValue), index); 302 } 303 304 public void charFieldChanged(String classname, String fieldname, char newValue, int index) { 305 objectFieldChanged(classname, fieldname, new Character (newValue), index); 306 } 307 308 public void doubleFieldChanged(String classname, String fieldname, double newValue, int index) { 309 objectFieldChanged(classname, fieldname, new Double (newValue), index); 310 } 311 312 public void floatFieldChanged(String classname, String fieldname, float newValue, int index) { 313 objectFieldChanged(classname, fieldname, new Float (newValue), index); 314 } 315 316 public void intFieldChanged(String classname, String fieldname, int newValue, int index) { 317 objectFieldChanged(classname, fieldname, new Integer (newValue), index); 318 } 319 320 public void longFieldChanged(String classname, String fieldname, long newValue, int index) { 321 objectFieldChanged(classname, fieldname, new Long (newValue), index); 322 } 323 324 public void shortFieldChanged(String classname, String fieldname, short newValue, int index) { 325 objectFieldChanged(classname, fieldname, new Short (newValue), index); 326 } 327 328 public void objectArrayChanged(int startPos, Object [] array, int length) { 329 this.markAccessed(); 330 for (int i = 0; i < length; i++) { 331 clearArrayReference(startPos + i); 332 } 333 getObjectManager().getTransactionManager().arrayChanged(this, startPos, array, length); 334 } 335 336 public void primitiveArrayChanged(int startPos, Object array, int length) { 337 this.markAccessed(); 338 getObjectManager().getTransactionManager().arrayChanged(this, startPos, array, length); 339 } 340 341 public void setNext(TLinkable link) { 342 this.next = link; 343 } 344 345 public void setPrevious(TLinkable link) { 346 this.previous = link; 347 } 348 349 public TLinkable getNext() { 350 return this.next; 351 } 352 353 public TLinkable getPrevious() { 354 return this.previous; 355 } 356 357 public void markAccessed() { 358 setFlag(ACCESSED_OFFSET, true); 359 } 360 361 public void clearAccessed() { 362 setFlag(ACCESSED_OFFSET, false); 363 } 364 365 public boolean recentlyAccessed() { 366 return getFlag(ACCESSED_OFFSET); 367 } 368 369 public int accessCount(int factor) { 370 throw new UnsupportedOperationException (); 372 } 373 374 public synchronized boolean getAndResetNew() { 375 if (getFlag(IS_NEW_OFFSET)) { 376 setFlag(IS_NEW_OFFSET, false); 377 return true; 378 } 379 return false; 380 } 381 382 public synchronized void setIsNew() { 383 if (getFlag(IS_NEW_OFFSET)) { throw new IllegalStateException ("new flag already set"); } 384 setFlag(IS_NEW_OFFSET, true); 385 } 386 387 public boolean isNew() { 388 return getFlag(IS_NEW_OFFSET); 389 } 390 391 public void disableAutoLocking() { 395 setFlag(AUTOLOCKS_DISABLED_OFFSET, true); 396 } 397 398 public boolean autoLockingDisabled() { 399 return getFlag(AUTOLOCKS_DISABLED_OFFSET); 400 } 401 402 private void setEvictionInProgress(boolean value) { 403 setFlag(EVICTION_IN_PROGRESS_OFFSET, value); 404 } 405 406 private boolean isEvictionInProgress() { 407 return getFlag(EVICTION_IN_PROGRESS_OFFSET); 408 } 409 410 public synchronized boolean canEvict() { 411 boolean canEvict = isEvictable() && !(isNew() || isEvictionInProgress()); 412 if (canEvict) { 413 setEvictionInProgress(true); 414 } 415 return canEvict; 416 } 417 418 protected abstract boolean isEvictable(); 419 420 } 421 | Popular Tags |