KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > objectserver > managedobject > ManagedObjectImpl


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

4 package com.tc.objectserver.managedobject;
5
6 import com.tc.io.TCByteBufferOutputStream;
7 import com.tc.object.ObjectID;
8 import com.tc.object.dna.api.DNA;
9 import com.tc.object.dna.api.DNACursor;
10 import com.tc.object.dna.api.DNAException;
11 import com.tc.object.dna.impl.DNAEncoding;
12 import com.tc.object.dna.impl.DNAWriterImpl;
13 import com.tc.object.dna.impl.ObjectDNAWriterImpl;
14 import com.tc.object.dna.impl.ObjectStringSerializer;
15 import com.tc.object.tx.TransactionID;
16 import com.tc.objectserver.api.ObjectInstanceMonitor;
17 import com.tc.objectserver.core.api.ManagedObject;
18 import com.tc.objectserver.core.api.ManagedObjectState;
19 import com.tc.objectserver.impl.ManagedObjectReference;
20 import com.tc.objectserver.managedobject.bytecode.ClassNotCompatableException;
21 import com.tc.objectserver.mgmt.ManagedObjectFacade;
22 import com.tc.text.PrettyPrintable;
23 import com.tc.text.PrettyPrinter;
24 import com.tc.util.Assert;
25 import com.tc.util.Conversion;
26
27 import gnu.trove.TLinkable;
28
29 import java.io.IOException JavaDoc;
30 import java.io.ObjectInputStream JavaDoc;
31 import java.io.ObjectOutputStream JavaDoc;
32 import java.io.PrintWriter JavaDoc;
33 import java.io.Serializable JavaDoc;
34 import java.io.StringWriter JavaDoc;
35 import java.util.Set JavaDoc;
36
37 /**
38  * Responsible for maintaining the state of a shared object. Used for broadcasting new instances of an object as well as
39  * having changes applied to it and keeping track of references for garbage collection. If you add fields to this object
40  * that need to be serialized make sure you add them to the ManagedObjectSerializer
41  *
42  * @author steve TODO:: Remove Cacheable interface from this Object.
43  */

44 public class ManagedObjectImpl implements ManagedObject, ManagedObjectReference, Serializable JavaDoc, PrettyPrintable {
45   private static final DNAEncoding DNA_STORAGE_ENCODING = new DNAEncoding(DNAEncoding.STORAGE);
46
47   private final static byte IS_NEW_OFFSET = 1;
48   private final static byte IS_DIRTY_OFFSET = 2;
49   private final static byte REFERENCED_OFFSET = 4;
50   private final static byte REMOVE_ON_RELEASE_OFFSET = 8;
51   private final static byte PINNED_OFFSET = 16;
52   private final static byte PROCESS_PENDING_OFFSET = 32;
53
54   private final static byte INITIAL_FLAG_VALUE = IS_DIRTY_OFFSET | IS_NEW_OFFSET;
55
56   final ObjectID id;
57
58   long version;
59   transient ManagedObjectState state;
60
61   // TODO::Split this flag into two so that concurrency is maintained
62
private volatile transient byte flags = INITIAL_FLAG_VALUE;
63
64   // TODO:: Remove Cacheable interface from this Object and remove these two references
65
private transient TLinkable previous;
66   private transient TLinkable next;
67
68   private int accessed;
69
70   public ManagedObjectImpl(ObjectID id) {
71     Assert.assertNotNull(id);
72     this.id = id;
73   }
74   
75   /**
76    * This is here for testing, not production use.
77    */

78   public boolean isEqual(ManagedObject moi) {
79     if (this == moi) return true;
80     if (moi instanceof ManagedObjectImpl) {
81       ManagedObjectImpl mo = (ManagedObjectImpl) moi;
82       boolean rv = true;
83       rv &= id.equals(mo.id);
84       rv &= version == mo.version;
85       rv &= state.equals(mo.state);
86       return rv;
87     } else return false;
88   }
89
90   void setBasicIsNew(boolean b) {
91     setFlag(IS_NEW_OFFSET, b);
92   }
93
94   private void setBasicIsDirty(boolean b) {
95     setFlag(IS_DIRTY_OFFSET, b);
96   }
97
98   private synchronized void setFlag(int offset, boolean value) {
99     flags = Conversion.setFlag(flags, offset, value);
100   }
101
102   private synchronized boolean getFlag(int offset) {
103     return (flags & offset) == offset;
104   }
105
106   private boolean basicIsNew() {
107     return getFlag(IS_NEW_OFFSET);
108   }
109
110   private boolean basicIsDirty() {
111     return getFlag(IS_DIRTY_OFFSET);
112   }
113
114   public boolean isNew() {
115     return basicIsNew();
116   }
117
118   public boolean isDirty() {
119     return basicIsDirty();
120   }
121
122   public void setIsDirty(boolean isDirty) {
123     setBasicIsDirty(isDirty);
124   }
125
126   public ObjectID getID() {
127     return id;
128   }
129
130   public Set JavaDoc getObjectReferences() {
131     return state.getObjectReferences();
132   }
133
134   public void addObjectReferencesTo(ManagedObjectTraverser traverser) {
135     state.addObjectReferencesTo(traverser);
136   }
137
138   public void apply(DNA dna, TransactionID txnID, BackReferences includeIDs, ObjectInstanceMonitor instanceMonitor) {
139     boolean isNew = isNew();
140     String JavaDoc typeName = dna.getTypeName();
141     if (dna.isDelta() && isNew) {
142       // Assertion Error
143
throw new AssertionError JavaDoc("Newly created Object is applied with a delta DNA ! ManagedObjectImpl = "
144                                + this.toString() + " DNA = " + dna + " TransactionID = " + txnID);
145     }
146     if (isNew) {
147       instanceMonitor.instanceCreated(typeName);
148     }
149     this.version = dna.getVersion();
150     DNACursor cursor = dna.getCursor();
151
152     initializeStateIfNecessary(dna.getParentObjectID(), typeName, dna.getDefiningLoaderDescription(), cursor);
153     if (state == null) { throw new AssertionError JavaDoc(
154                                                   "Attempt to apply a transaction to a managed object with null state: "
155                                                       + this); }
156     try {
157       try {
158         state.apply(id, cursor, includeIDs);
159       } catch (ClassNotCompatableException cnce) {
160         // reinitialize state object and try again
161
reinitializeState(dna.getParentObjectID(), dna.getTypeName(), dna.getDefiningLoaderDescription(), cursor, state);
162         state.apply(id, cursor, includeIDs);
163       }
164     } catch (IOException JavaDoc e) {
165       throw new DNAException(e);
166     }
167     setIsDirty(true);
168     setBasicIsNew(false);
169   }
170
171   private void reinitializeState(ObjectID pid, String JavaDoc className, String JavaDoc loaderDesc, DNACursor cursor,
172                                  ManagedObjectState oldState) {
173     state = getStateFactory().recreateState(id, pid, className, loaderDesc, cursor, oldState);
174   }
175
176   private void initializeStateIfNecessary(ObjectID pid, String JavaDoc className, String JavaDoc loaderDesc, DNACursor cursor) {
177     if (state == null) {
178       state = getStateFactory().createState(id, pid, className, loaderDesc, cursor);
179     }
180   }
181
182   private ManagedObjectStateFactory getStateFactory() {
183     return ManagedObjectStateFactory.getInstance();
184   }
185
186   private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
187     if (state == null) { throw new AssertionError JavaDoc("Null state:" + this); }
188     out.defaultWriteObject();
189     out.writeByte(state.getType());
190     state.writeTo(out);
191   }
192
193   private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
194     in.defaultReadObject();
195     byte type = in.readByte();
196     this.state = getStateFactory().readManagedObjectStateFrom(in, type);
197     this.setBasicIsNew(false);
198     this.setBasicIsDirty(false);
199   }
200
201   public ManagedObjectState getManagedObjectState() {
202     return state;
203   }
204
205   /**
206    * Writes the data in the object to the DNA strand supplied.
207    */

208   public void toDNA(TCByteBufferOutputStream out, ObjectStringSerializer serializer) {
209     DNAWriterImpl writer = new ObjectDNAWriterImpl(out, id, getClassname(), serializer, DNA_STORAGE_ENCODING,
210                                                    getLoaderDescription(), version);
211     state.dehydrate(id, writer);
212     writer.finalizeDNA();
213   }
214
215   public String JavaDoc toString() {
216     // XXX: Um... this is gross.
217
StringWriter JavaDoc writer = new StringWriter JavaDoc();
218     PrintWriter JavaDoc pWriter = new PrintWriter JavaDoc(writer);
219     new PrettyPrinter(pWriter).visit(this);
220     return writer.getBuffer().toString();
221   }
222
223   public PrettyPrinter prettyPrint(PrettyPrinter out) {
224     PrettyPrinter rv = out;
225     out = out.print("ManagedObjectImpl").duplicateAndIndent().println();
226     out.indent().print("identityHashCode: " + System.identityHashCode(this)).println();
227     out.indent().print("id: " + id).println();
228     out.indent().print("className: " + getClassname()).println();
229     out.indent().print("version:" + version).println();
230     out.indent().print("state: ").visit(state).println();
231     out.indent().print("isDirty:" + this.basicIsDirty());
232     out.indent().print("isNew:" + this.basicIsNew());
233     out.indent().print("isReferenced:" + this.isReferenced()).println();
234     out.indent().print("next: " + (this.getNext() != null) + " prev: " + (this.getPrevious() != null));
235     return rv;
236   }
237
238   public ManagedObjectFacade createFacade(int limit) {
239     return state.createFacade(id, getClassname(), limit);
240   }
241
242   /**
243    * This is public for testing
244    */

245   public String JavaDoc getClassname() {
246     return state == null ? "UNKNOWN" : state.getClassName();
247   }
248
249   public String JavaDoc getLoaderDescription() {
250     return state == null ? "UNKNOWN" : state.getLoaderDescription();
251   }
252
253   public ManagedObjectReference getReference() {
254     return this;
255   }
256
257   /*********************************************************************************************************************
258    * ManagedObjectReference Interface
259    */

260   public ManagedObject getObject() {
261     return this;
262   }
263
264   public boolean getProcessPendingOnRelease() {
265     return getFlag(PROCESS_PENDING_OFFSET);
266   }
267
268   public void setProcessPendingOnRelease(boolean b) {
269     setFlag(PROCESS_PENDING_OFFSET, b);
270   }
271
272   public boolean isRemoveOnRelease() {
273     return getFlag(REMOVE_ON_RELEASE_OFFSET);
274   }
275
276   public void markReference() {
277     setFlag(REFERENCED_OFFSET, true);
278   }
279
280   public void unmarkReference() {
281     setFlag(REFERENCED_OFFSET, false);
282   }
283
284   public boolean isReferenced() {
285     return getFlag(REFERENCED_OFFSET);
286   }
287
288   /**
289    * Pins this reference in the cache.
290    */

291   public void pin() {
292     setFlag(PINNED_OFFSET, true);
293   }
294
295   public void unpin() {
296     setFlag(PINNED_OFFSET, false);
297   }
298
299   /**
300    * Determines whether or not this reference is pinned in the ObjectManager's cache. This allows the object manager to
301    * lookup multiple objects one at a time without evicting them from the cache.
302    */

303   public boolean isPinned() {
304     return getFlag(PINNED_OFFSET);
305   }
306
307   /*********************************************************************************************************************
308    * ManagedObjectReference::Cacheable interface XXX:: Most of these methods are not synchronized (except when accessing
309    * the flag field which can be accessed from multiple threads) 'coz it is expected that these are called under the
310    * scope of a bigger sync block (from evictionPolicy)
311    */

312
313   public void setRemoveOnRelease(boolean removeOnRelease) {
314     setFlag(REMOVE_ON_RELEASE_OFFSET, removeOnRelease);
315   }
316
317   public void markAccessed() {
318     accessed++;
319   }
320
321   public void clearAccessed() {
322     accessed = 0;
323   }
324
325   public boolean recentlyAccessed() {
326     return accessed > 0;
327   }
328
329   public int accessCount(int factor) {
330     accessed = accessed / factor;
331     return accessed;
332   }
333
334   public ObjectID getObjectID() {
335     return getID();
336   }
337
338   public TLinkable getNext() {
339     return next;
340   }
341
342   public TLinkable getPrevious() {
343     return previous;
344   }
345
346   public void setNext(TLinkable next) {
347     this.next = next;
348   }
349
350   public void setPrevious(TLinkable previous) {
351     this.previous = previous;
352   }
353
354   public synchronized boolean canEvict() {
355     return !(isPinned() || isReferenced() || isNew());
356   }
357
358 }
359
Popular Tags