KickJava   Java API By Example, From Geeks To Geeks.

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


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 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 JavaDoc;
27 import java.lang.ref.ReferenceQueue JavaDoc;
28
29 /**
30  * Implementation of TCObject interface.
31  * <p>
32  */

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 JavaDoc queue, ObjectID id, Object JavaDoc 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 JavaDoc getPeerObject() {
74     return peerObject.get();
75   }
76
77   protected void setPeerObject(WeakObjectReference pojo) {
78     this.peerObject = pojo;
79     Object JavaDoc 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   /**
91    * Reconstitutes the object using the data in the DNA strand. XXX: We may need to signal (via a different signature or
92    * args) that the hydration is intended to initialize the object from scratch or if it's a delta. We must avoid
93    * creating a new instance of the peer object if the strand is just a delta.
94    *
95    * @throws ClassNotFoundException
96    */

97   public void hydrate(DNA from, boolean force) throws ClassNotFoundException JavaDoc {
98     synchronized (getResolveLock()) {
99       boolean isNewLoad = isNull();
100       createPeerObjectIfNecessary(from);
101
102       Object JavaDoc po = getPeerObject();
103       if (po == null) return;
104       try {
105         tcClazz.hydrate(this, from, po, force);
106         if (isNewLoad) performOnLoadActionIfNecessary(po);
107       } catch (ClassNotFoundException JavaDoc e) {
108         logger.warn("Re-throwing Exception: " , e);
109         throw e;
110       } catch (IOException JavaDoc e) {
111         logger.warn("Re-throwing Exception: " , e);
112         throw new DNAException(e);
113       }
114     }
115   }
116
117   private void performOnLoadActionIfNecessary(Object JavaDoc pojo) {
118     TCClass tcc = getTCClass();
119     if (tcc.hasOnLoadExecuteScript() || tcc.hasOnLoadMethod()) {
120       String JavaDoc eval = tcc.hasOnLoadExecuteScript() ? tcc.getOnLoadExecuteScript() : "self." + tcc.getOnLoadMethod()
121                                                                                   + "()";
122       resolveAllReferences();
123
124       ClassLoader JavaDoc 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         // Error Parsing script. Use e.getMessage() instead of e.getErrorText() when there is a ParseException because
134
// expectedTokenSequences in ParseException could be null and thus, may throw a NullPointerException when
135
// calling
136
// e.getErrorText().
137
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         // General Error evaluating script
143
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       // TODO: set created and modified version id
165
setPeerObject(getObjectManager().createNewPeer(tcClazz, from));
166     }
167   }
168
169   public void setReference(String JavaDoc fieldName, ObjectID id) {
170     throw new AssertionError JavaDoc("shouldn't be called");
171   }
172
173   public void setValue(String JavaDoc fieldName, Object JavaDoc obj) {
174     try {
175       TransparentAccess ta = (TransparentAccess) getPeerObject();
176       if (ta == null) {
177         // Object was GC'd so return which should lead to a re-retrieve
178
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         // clean this up
193
ta.__tc_setfield(field.getName(), obj);
194       }
195     } catch (Exception JavaDoc e) {
196       // TODO: More elegant exception handling.
197
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 JavaDoc po = getPeerObject();
205         Assert.assertFalse(isNew()); // Shouldnt clear new Objects
206
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 JavaDoc pojo, int toClear);
215
216   public final Object JavaDoc getResolveLock() {
217     return objectID; // Save a field by using this one as the lock
218
}
219
220   public void resolveArrayReference(int index) {
221     throw new AssertionError JavaDoc("shouldn't be called");
222   }
223
224   public ArrayIndexOutOfBoundsException JavaDoc checkArrayIndex(int index) {
225     throw new AssertionError JavaDoc("shouldn't be called");
226   }
227
228   public void clearArrayReference(int index) {
229     clearReference(Integer.toString(index));
230   }
231
232   public void clearReference(String JavaDoc fieldName) {
233     // do nothing
234
}
235
236   public void resolveReference(String JavaDoc fieldName) {
237     // do nothing
238
}
239
240   public void resolveAllReferences() {
241     // override me
242
}
243
244   public void literalValueChanged(Object JavaDoc newValue, Object JavaDoc oldValue) {
245     throw new UnsupportedOperationException JavaDoc();
246   }
247
248   public void setLiteralValue(Object JavaDoc newValue) {
249     throw new UnsupportedOperationException JavaDoc();
250   }
251
252   /**
253    * Writes the data in the object to the DNA writer supplied.
254    */

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 JavaDoc toString() {
268     return getClass().getName() + "@" + System.identityHashCode(this) + "[objectID=" + objectID + ", TCClass="
269            + tcClazz + "]";
270   }
271
272   public void objectFieldChanged(String JavaDoc classname, String JavaDoc fieldname, Object JavaDoc newValue, int index) {
273     try {
274       this.markAccessed();
275       if (index == NULL_INDEX) {
276         // Assert.eval(fieldname.indexOf('.') >= 0);
277
clearReference(fieldname);
278       } else {
279         clearArrayReference(index);
280       }
281       getObjectManager().getTransactionManager().fieldChanged(this, classname, fieldname, newValue, index);
282     } catch (Throwable JavaDoc t) {
283       Util.printLogAndRethrowError(t, logger);
284     }
285   }
286
287   public void objectFieldChangedByOffset(String JavaDoc classname, long fieldOffset, Object JavaDoc newValue, int index) {
288     String JavaDoc fieldname = tcClazz.getFieldNameByOffset(fieldOffset);
289     objectFieldChanged(classname, fieldname, newValue, index);
290   }
291
292   public String JavaDoc getFieldNameByOffset(long fieldOffset) {
293     return tcClazz.getFieldNameByOffset(fieldOffset);
294   }
295
296   public void booleanFieldChanged(String JavaDoc classname, String JavaDoc fieldname, boolean newValue, int index) {
297     objectFieldChanged(classname, fieldname, new Boolean JavaDoc(newValue), index);
298   }
299
300   public void byteFieldChanged(String JavaDoc classname, String JavaDoc fieldname, byte newValue, int index) {
301     objectFieldChanged(classname, fieldname, new Byte JavaDoc(newValue), index);
302   }
303
304   public void charFieldChanged(String JavaDoc classname, String JavaDoc fieldname, char newValue, int index) {
305     objectFieldChanged(classname, fieldname, new Character JavaDoc(newValue), index);
306   }
307
308   public void doubleFieldChanged(String JavaDoc classname, String JavaDoc fieldname, double newValue, int index) {
309     objectFieldChanged(classname, fieldname, new Double JavaDoc(newValue), index);
310   }
311
312   public void floatFieldChanged(String JavaDoc classname, String JavaDoc fieldname, float newValue, int index) {
313     objectFieldChanged(classname, fieldname, new Float JavaDoc(newValue), index);
314   }
315
316   public void intFieldChanged(String JavaDoc classname, String JavaDoc fieldname, int newValue, int index) {
317     objectFieldChanged(classname, fieldname, new Integer JavaDoc(newValue), index);
318   }
319
320   public void longFieldChanged(String JavaDoc classname, String JavaDoc fieldname, long newValue, int index) {
321     objectFieldChanged(classname, fieldname, new Long JavaDoc(newValue), index);
322   }
323
324   public void shortFieldChanged(String JavaDoc classname, String JavaDoc fieldname, short newValue, int index) {
325     objectFieldChanged(classname, fieldname, new Short JavaDoc(newValue), index);
326   }
327
328   public void objectArrayChanged(int startPos, Object JavaDoc[] 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 JavaDoc 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     // TODO:: Implement when needed
371
throw new UnsupportedOperationException JavaDoc();
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 JavaDoc("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   // These autlocking disable methods are checked in ManagerImpl. The one known use case
392
// is the Hashtable used to hold sessions. We need local synchronization,
393
// but we don't ever want autolocks for that particular instance
394
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