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.SerializationUtil;
010: import com.tc.object.TCObject;
011: import com.tc.object.TraversedReferences;
012: import com.tc.object.bytecode.Manageable;
013: import com.tc.object.dna.api.DNA;
014: import com.tc.object.dna.api.DNACursor;
015: import com.tc.object.dna.api.DNAWriter;
016: import com.tc.object.dna.api.DNAEncoding;
017: import com.tc.object.dna.api.LogicalAction;
018: import com.tc.object.dna.api.PhysicalAction;
019: import com.tc.object.tx.optimistic.OptimisticTransactionManager;
020: import com.tc.object.tx.optimistic.TCObjectClone;
021: import com.tc.util.Assert;
022: import com.tc.util.FieldUtils;
023:
024: import java.io.IOException;
025: import java.lang.reflect.Field;
026: import java.util.Collection;
027: import java.util.Comparator;
028: import java.util.IdentityHashMap;
029: import java.util.Iterator;
030: import java.util.Map;
031: import java.util.TreeMap;
032: import java.util.Map.Entry;
033:
034: public class TreeMapApplicator extends BaseApplicator {
035:
036: static final String COMPARATOR_FIELDNAME = "java.util.TreeMap.comparator";
037: private static final Field COMPARATOR_FIELD;
038:
039: static {
040: try {
041: Field field = TreeMap.class.getDeclaredField("comparator");
042: field.setAccessible(true);
043: COMPARATOR_FIELD = field;
044: } catch (Exception e) {
045: throw new RuntimeException(e);
046: }
047: }
048:
049: public TreeMapApplicator(DNAEncoding encoding) {
050: super (encoding);
051: }
052:
053: /**
054: * return the key value pairs of field names to shared objects for this source. We already updated the literals and
055: * set the new TCObjectClone
056: */
057: public Map connectedCopy(Object source, Object dest, Map visited,
058: ClientObjectManager objectManager,
059: OptimisticTransactionManager txManager) {
060: Map cloned = new IdentityHashMap();
061:
062: Manageable sourceManageable = (Manageable) source;
063: Manageable destManaged = (Manageable) dest;
064:
065: TreeMap sourceMap = (TreeMap) source;
066: TreeMap destMap = (TreeMap) dest;
067:
068: for (Iterator i = sourceMap.entrySet().iterator(); i.hasNext();) {
069: Entry e = (Entry) i.next();
070:
071: Object k = e.getKey();
072: Object v = e.getValue();
073:
074: Object copyKey = createCopyIfNecessary(objectManager,
075: visited, cloned, k);
076: Object copyValue = createCopyIfNecessary(objectManager,
077: visited, cloned, v);
078:
079: destMap.put(copyKey, copyValue);
080: }
081:
082: // deal with comparator
083: Comparator comparatorOrig = sourceMap.comparator();
084: Comparator copyValue = (Comparator) createCopyIfNecessary(
085: objectManager, visited, cloned, comparatorOrig);
086: // FIXME::TODO:: check if this is OK.
087: setComparator(destMap, copyValue);
088:
089: destManaged.__tc_managed(new TCObjectClone(sourceManageable
090: .__tc_managed(), txManager));
091:
092: return cloned;
093: }
094:
095: public TraversedReferences getPortableObjects(Object pojo,
096: TraversedReferences addTo) {
097: TreeMap treemap = (TreeMap) pojo;
098: filterPortableObjects(treemap.keySet(), addTo);
099: filterPortableObjects(treemap.values(), addTo);
100: filterPortableObject(treemap.comparator(), addTo);
101: return addTo;
102: }
103:
104: private void filterPortableObjects(Collection objects,
105: TraversedReferences addTo) {
106: for (Iterator i = objects.iterator(); i.hasNext();) {
107: Object value = i.next();
108: filterPortableObject(value, addTo);
109: }
110: }
111:
112: private void filterPortableObject(Object value,
113: TraversedReferences addTo) {
114: if (value != null && isPortableReference(value.getClass())) {
115: addTo.addAnonymousReference(value);
116: }
117: }
118:
119: public void hydrate(ClientObjectManager objectManager,
120: TCObject tcObject, DNA dna, Object po) throws IOException,
121: ClassNotFoundException {
122: Map m = (Map) po;
123: DNACursor cursor = dna.getCursor();
124:
125: while (cursor.next(encoding)) {
126: Object action = cursor.getAction();
127: if (action instanceof PhysicalAction) {
128: // This is done so that subclass of TreeMaps can work
129: PhysicalAction pa = (PhysicalAction) action;
130: Assert.assertEquals(COMPARATOR_FIELDNAME, pa
131: .getFieldName());
132: Comparator c = (Comparator) objectManager
133: .lookupObject((ObjectID) pa.getObject());
134: setComparator(po, c);
135: } else {
136: LogicalAction la = (LogicalAction) action;
137: int method = la.getMethod();
138: Object[] params = la.getParameters();
139: switch (method) {
140: case SerializationUtil.PUT:
141: Object k = params[0];
142: Object v = params[1];
143: Object pkey = k instanceof ObjectID ? objectManager
144: .lookupObject((ObjectID) k) : k;
145: Object value = v instanceof ObjectID ? objectManager
146: .lookupObject((ObjectID) v)
147: : v;
148: m.put(pkey, value);
149: break;
150: case SerializationUtil.REMOVE:
151: Object rkey = params[0] instanceof ObjectID ? objectManager
152: .lookupObject((ObjectID) params[0])
153: : params[0];
154: m.remove(rkey);
155: break;
156: case SerializationUtil.CLEAR:
157: m.clear();
158: break;
159: default:
160: throw new AssertionError("invalid action:" + method);
161: }
162: }
163: }
164: }
165:
166: private void setComparator(Object target, Object value) {
167: try {
168: FieldUtils.tcSet(target, value, COMPARATOR_FIELD);
169: } catch (Exception e) {
170: throw new RuntimeException(e);
171: }
172: }
173:
174: public void dehydrate(ClientObjectManager objectManager,
175: TCObject tcObject, DNAWriter writer, Object pojo) {
176: TreeMap map = (TreeMap) pojo;
177:
178: Comparator cmp = map.comparator();
179: final Object cmpObj = getDehydratableObject(cmp, objectManager);
180: if (cmpObj != null) {
181: writer.addPhysicalAction(COMPARATOR_FIELDNAME, cmpObj);
182: }
183:
184: for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
185: Entry entry = (Entry) i.next();
186: Object key = entry.getKey();
187: Object value = entry.getValue();
188:
189: if (!objectManager.isPortableInstance(key)) {
190: continue;
191: }
192: if (!objectManager.isPortableInstance(value)) {
193: continue;
194: }
195:
196: final Object addKey = getDehydratableObject(key,
197: objectManager);
198: final Object addValue = getDehydratableObject(value,
199: objectManager);
200:
201: if (addKey == null || addValue == null) {
202: continue;
203: }
204:
205: writer.addLogicalAction(SerializationUtil.PUT,
206: new Object[] { addKey, addValue });
207: }
208:
209: }
210:
211: public Object getNewInstance(ClientObjectManager objectManager,
212: DNA dna) throws IOException, ClassNotFoundException {
213: DNACursor cursor = dna.getCursor();
214: if (!cursor.next(encoding)) {
215: throw new AssertionError(
216: "Cursor is empty in TreeMap.getNewInstance()");
217: }
218: PhysicalAction physicalAction = cursor.getPhysicalAction();
219: Assert.assertEquals(COMPARATOR_FIELDNAME, physicalAction
220: .getFieldName());
221: Comparator c = (Comparator) objectManager
222: .lookupObject((ObjectID) physicalAction.getObject());
223: return (c == null ? new TreeMap() : new TreeMap(c));
224: }
225: }
|