001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.objectserver.managedobject;
006:
007: import com.tc.exception.TCRuntimeException;
008: import com.tc.logging.TCLogger;
009: import com.tc.logging.TCLogging;
010: import com.tc.object.ObjectID;
011: import com.tc.object.dna.api.DNA;
012: import com.tc.object.dna.api.DNACursor;
013: import com.tc.object.dna.api.DNAWriter;
014: import com.tc.object.dna.api.PhysicalAction;
015: import com.tc.objectserver.managedobject.bytecode.ClassNotCompatableException;
016: import com.tc.objectserver.mgmt.ManagedObjectFacade;
017: import com.tc.objectserver.mgmt.PhysicalManagedObjectFacade;
018: import com.tc.text.PrettyPrintable;
019: import com.tc.text.PrettyPrinter;
020:
021: import java.io.IOException;
022: import java.io.ObjectInput;
023: import java.io.ObjectOutput;
024: import java.io.PrintWriter;
025: import java.io.Serializable;
026: import java.io.StringWriter;
027: import java.util.HashMap;
028: import java.util.Map;
029: import java.util.Set;
030:
031: /**
032: * State for Physically managed objects. This class is abstract and generated classes of Physical State Class Loader
033: * extends this class So changes to this class needs to be done cautiously.
034: */
035: public abstract class PhysicalManagedObjectState extends
036: AbstractManagedObjectState implements Serializable,
037: PrettyPrintable {
038:
039: private static final TCLogger logger = TCLogging
040: .getLogger(PhysicalManagedObjectState.class);
041:
042: public PhysicalManagedObjectState() {
043: super ();
044: }
045:
046: /**
047: * This is only for testing, its highly inefficient
048: */
049: protected boolean basicEquals(AbstractManagedObjectState o) {
050: PhysicalManagedObjectState cmp = (PhysicalManagedObjectState) o;
051: boolean result = getParentID().equals(cmp.getParentID())
052: && getClassName().equals(cmp.getClassName())
053: && getLoaderDescription().equals(
054: cmp.getLoaderDescription());
055: if (!result)
056: return result;
057: Map mine = addValues(new HashMap());
058: Map his = cmp.addValues(new HashMap());
059: return mine.equals(his);
060: }
061:
062: public ObjectID getParentID() {
063: return ObjectID.NULL_ID;
064: }
065:
066: public void setParentID(ObjectID id) {
067: // This is over-riden when needed
068: }
069:
070: public int hashCode() {
071: throw new TCRuntimeException("Don't hash me!");
072: }
073:
074: public void apply(ObjectID objectID, DNACursor cursor,
075: BackReferences includeIDs) throws IOException {
076: ManagedObjectChangeListener listener = getListener();
077: while (cursor.next()) {
078: PhysicalAction a = cursor.getPhysicalAction();
079: Object value = a.getObject();
080: String fieldName = a.getFieldName();
081:
082: if (value == null) {
083: throw new AssertionError(
084: "attempt to apply null value to field "
085: + fieldName + " in " + objectID + ", "
086: + toString());
087: }
088:
089: Object old = set(fieldName, value);
090: ObjectID oldValue = old instanceof ObjectID ? (ObjectID) old
091: : ObjectID.NULL_ID;
092: ObjectID newValue = value instanceof ObjectID ? (ObjectID) value
093: : ObjectID.NULL_ID;
094: listener.changed(objectID, oldValue, newValue);
095: }
096: }
097:
098: /**
099: * @return old Value
100: */
101: public Object set(String fieldName, Object value) {
102: try {
103: return basicSet(fieldName, value);
104: } catch (ClassNotCompatableException cne) {
105: // This exception triggers a regeneration of the state class !
106: logger
107: .warn("Recoverable Incompatible Class Change Identified : "
108: + cne.getMessage());
109: throw cne;
110: } catch (ClassCastException cce) {
111: // This is due to a change in the type of the fields which is currently not supported.
112: // Not throwing the exception 'coz we dont want to crash the server because of an
113: // incompatable change
114: cce.printStackTrace();
115: logger.error(
116: "Unrecoverable Incompatible Class Change : fieldName = "
117: + fieldName + " value = " + value, cce);
118: return null;
119: } catch (Exception e) {
120: e.printStackTrace();
121: logger.error(
122: "Incompatible Change : Class Does not support it",
123: e);
124: return null;
125: }
126: }
127:
128: public void addObjectReferencesTo(ManagedObjectTraverser traverser) {
129: traverser.addReachableObjectIDs(getObjectReferences());
130: }
131:
132: /**
133: * This method is generated by PhysicalStateClassLoader. It adds all the values of the fields into the map. This is
134: * just a convinent methods for printing the values, creating facade and checking for equals, but this should not be
135: * used in any other case as there is an overhead involved.
136: */
137: public abstract Map addValues(Map m);
138:
139: public abstract Set getObjectReferences();
140:
141: /**
142: * This method is generated by PhysicalStateClassLoader.
143: */
144: protected abstract void basicDehydrate(DNAWriter writer);
145:
146: /**
147: * This method is generated by PhysicalStateClassLoader.
148: */
149: protected abstract int getClassId();
150:
151: /**
152: * This method is generated by PhysicalStateClassLoader.
153: *
154: * @return old Value
155: */
156: protected abstract Object basicSet(String fieldName, Object value);
157:
158: /**
159: * This method is generated by PhysicalStateClassLoader.
160: */
161: protected abstract void readObject(ObjectInput in)
162: throws IOException, ClassNotFoundException;
163:
164: /**
165: * This method is generated by PhysicalStateClassLoader.
166: *
167: * @return old Value
168: */
169: protected abstract void writeObject(ObjectOutput out)
170: throws IOException;
171:
172: public void dehydrate(ObjectID objectID, DNAWriter writer) {
173: basicDehydrate(writer);
174: writer.setParentObjectID(getParentID());
175: }
176:
177: public String toString() {
178: // XXX: Um... this is gross.
179: StringWriter writer = new StringWriter();
180: PrintWriter pWriter = new PrintWriter(writer);
181: new PrettyPrinter(pWriter).visit(this );
182: return writer.getBuffer().toString();
183: }
184:
185: public PrettyPrinter prettyPrint(PrettyPrinter out) {
186: PrettyPrinter rv = out;
187: out = out.print(getClass().getName()).duplicateAndIndent()
188: .println();
189: out.indent().print("parentID : " + getParentID());
190: out.indent().print("className : " + getClassName());
191: out.indent().print("loaderDesc: " + getLoaderDescription());
192: out.indent().print("references: " + addValues(new HashMap()))
193: .println();
194: out.indent().print("listener: " + getListener()).println();
195: return rv;
196: }
197:
198: public ManagedObjectFacade createFacade(ObjectID objectID,
199: String className, int limit) {
200: // NOTE: limit is ignored for physical object facades
201:
202: Map dataCopy = addValues(new HashMap());
203:
204: ObjectID parentID = getParentID();
205: boolean isInner = !parentID.isNull();
206:
207: return new PhysicalManagedObjectFacade(objectID, parentID,
208: className, dataCopy, isInner, DNA.NULL_ARRAY_SIZE,
209: false);
210: }
211:
212: public byte getType() {
213: return PHYSICAL_TYPE;
214: }
215:
216: public void writeTo(ObjectOutput out) throws IOException {
217: // write the class identifier
218: out.writeInt(this .getClassId());
219: ObjectID parentID = getParentID();
220: if (ObjectID.NULL_ID.equals(parentID)) {
221: out.writeBoolean(false);
222: } else {
223: out.writeBoolean(true);
224: out.writeLong(parentID.toLong());
225: }
226:
227: writeObject(out);
228: }
229:
230: static PhysicalManagedObjectState readFrom(ObjectInput in)
231: throws IOException, ClassNotFoundException {
232: // read the class identifier
233: int classId = in.readInt();
234: ObjectID pid = ObjectID.NULL_ID;
235: if (in.readBoolean()) {
236: pid = new ObjectID(in.readLong());
237: }
238:
239: PhysicalManagedObjectState pmos = ManagedObjectStateFactory
240: .getInstance().createPhysicalState(pid, classId);
241: pmos.readObject(in);
242: return pmos;
243: }
244:
245: }
|