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.object.applicator;
006:
007: import com.tc.object.ClientObjectManager;
008: import com.tc.object.ObjectID;
009: import com.tc.object.TCClass;
010: import com.tc.object.TCObject;
011: import com.tc.object.TraversedReferences;
012: import com.tc.object.bytecode.Manageable;
013: import com.tc.object.bytecode.TransparentAccess;
014: import com.tc.object.dna.api.DNA;
015: import com.tc.object.dna.api.DNACursor;
016: import com.tc.object.dna.api.DNAWriter;
017: import com.tc.object.dna.api.DNAEncoding;
018: import com.tc.object.dna.api.PhysicalAction;
019: import com.tc.object.field.TCField;
020: import com.tc.object.tx.optimistic.OptimisticTransactionManager;
021: import com.tc.object.tx.optimistic.TCObjectClone;
022: import com.tc.util.Assert;
023:
024: import java.io.IOException;
025: import java.util.HashMap;
026: import java.util.IdentityHashMap;
027: import java.util.Iterator;
028: import java.util.Map;
029:
030: public class PhysicalApplicator extends BaseApplicator {
031:
032: private final TCClass clazz;
033:
034: public PhysicalApplicator(TCClass clazz, DNAEncoding encoding) {
035: super (encoding);
036: this .clazz = clazz;
037: }
038:
039: /**
040: * return the key value pairs of field names to shared objects for this source. We already updated the literals and
041: * set the new TCObjectClone
042: */
043: public Map connectedCopy(Object source, Object dest, Map visited,
044: ClientObjectManager objectManager,
045: OptimisticTransactionManager txManager) {
046: Map map = new HashMap();
047: Map cloned = new IdentityHashMap();
048:
049: TransparentAccess da = (TransparentAccess) dest;
050:
051: Manageable sourceManageable = (Manageable) source;
052: Manageable destManaged = (Manageable) da;
053:
054: getAllFields(source, map);
055:
056: for (Iterator i = map.keySet().iterator(); i.hasNext();) {
057: String k = (String) i.next();
058: Object v = map.get(k);
059:
060: Object copyValue = createCopyIfNecessary(objectManager,
061: visited, cloned, v);
062: da.__tc_setfield(k, copyValue);
063: }
064:
065: destManaged.__tc_managed(new TCObjectClone(sourceManageable
066: .__tc_managed(), txManager));
067: return cloned;
068: }
069:
070: public TraversedReferences getPortableObjects(Object pojo,
071: TraversedReferences addTo) {
072: if (!(pojo instanceof TransparentAccess))
073: return addTo;
074:
075: Map map = new HashMap();
076: getAllFields(pojo, map);
077:
078: TCField[] fields = clazz.getPortableFields();
079: if (clazz.isNonStaticInner()) {
080: addTo.addNamedReference(clazz.getName(), clazz
081: .getParentFieldName(), map.get(clazz
082: .getParentFieldName()));
083: }
084: for (int i = 0; i < fields.length; i++) {
085: Object o = map.get(fields[i].getName());
086:
087: if (o != null && isPortableReference(o.getClass())) {
088: addTo.addNamedReference(fields[i].getName(), o);
089: }
090: }
091: return addTo;
092: }
093:
094: public void hydrate(ClientObjectManager objectManager,
095: TCObject tcObject, DNA dna, Object po) throws IOException,
096: ClassNotFoundException {
097: DNACursor cursor = dna.getCursor();
098: String fieldName;
099: Object fieldValue;
100:
101: while (cursor.next(encoding)) {
102: PhysicalAction a = cursor.getPhysicalAction();
103: Assert.eval(a.isTruePhysical());
104: fieldName = a.getFieldName();
105: fieldValue = a.getObject();
106: tcObject.setValue(fieldName, fieldValue);
107: }
108: }
109:
110: public void dehydrate(ClientObjectManager objectManager,
111: TCObject tcObject, DNAWriter writer, Object pojo) {
112: if (!objectManager.isPortableInstance(pojo)) {
113: return;
114: }
115:
116: TCClass tcc = clazz;
117: TCField[] fields;
118:
119: Map fieldValues = null;
120:
121: while (tcc != null) {
122: fields = tcc.getPortableFields();
123:
124: if (fields.length > 0 && fieldValues == null) {
125: fieldValues = new HashMap();
126: if (pojo instanceof TransparentAccess) {
127: // only need to do this once. The generated method takes care of walking up the class hierarchy
128: getAllFields(pojo, fieldValues);
129: } else {
130: throw new AssertionError("wrong type: "
131: + pojo.getClass());
132: }
133: }
134:
135: for (int i = 0; i < fields.length; i++) {
136: String fieldName = fields[i].getName();
137: Object fieldValue = fieldValues.get(fieldName);
138:
139: if (fieldValue == null) {
140: if (!fieldValues.containsKey(fieldName)) {
141: throw new AssertionError(
142: fieldName
143: + " does not exist in map returned from __tc_getallfields. Class is "
144: + tcc + ". field Values = "
145: + fieldValues);
146: }
147: }
148:
149: if (!objectManager.isPortableInstance(fieldValue)) {
150: continue;
151: }
152:
153: Object value = getDehydratableObject(fieldValue,
154: objectManager);
155: if (value == null) {
156: // instead of ignoring non-portable objects we send ObjectID.NULL_ID so that the state can
157: // be created at the server correctly if needed. Another reason is to null the reference across the cluster if
158: // such an attempt was made.
159: value = ObjectID.NULL_ID;
160: }
161: writer.addPhysicalAction(fieldName, value, fields[i]
162: .canBeReference());
163: }
164: tcc = tcc.getSuperclass();
165: }
166:
167: if (clazz.isNonStaticInner() && fieldValues != null) {
168: Object parentObject = fieldValues.get(clazz
169: .getParentFieldName());
170: Assert.assertNotNull("parentObject", parentObject);
171: Object parentObjectID = getDehydratableObject(parentObject,
172: objectManager);
173: if (parentObjectID != null) {
174: writer.setParentObjectID((ObjectID) parentObjectID);
175: }
176: }
177:
178: }
179:
180: public Object getNewInstance(ClientObjectManager objectManager,
181: DNA dna) {
182: throw new UnsupportedOperationException();
183: }
184:
185: private static void getAllFields(Object o, Map dest) {
186: // This is ugly, but doing the getStackTrace stuff inside of __tc_getallfields() seems
187: // to trip a hotspot bug (DEV-67)
188: if (o instanceof Throwable) {
189: // This has the side effect of getting the stack trace initilized in the target object
190: ((Throwable) o).getStackTrace();
191: }
192: ((TransparentAccess) o).__tc_getallfields(dest);
193: }
194:
195: }
|