001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.object.applicator;
005:
006: import com.tc.object.ClientObjectManager;
007: import com.tc.object.ObjectID;
008: import com.tc.object.SerializationUtil;
009: import com.tc.object.TCObject;
010: import com.tc.object.TraversedReferences;
011: import com.tc.object.bytecode.Manageable;
012: import com.tc.object.bytecode.TCMap;
013: import com.tc.object.dna.api.DNA;
014: import com.tc.object.dna.api.DNACursor;
015: import com.tc.object.dna.api.DNAEncoding;
016: import com.tc.object.dna.api.DNAWriter;
017: import com.tc.object.dna.api.LogicalAction;
018: import com.tc.object.tx.optimistic.OptimisticTransactionManager;
019: import com.tc.object.tx.optimistic.TCObjectClone;
020:
021: import java.io.IOException;
022: import java.util.Collection;
023: import java.util.IdentityHashMap;
024: import java.util.Iterator;
025: import java.util.Map;
026: import java.util.Map.Entry;
027:
028: /**
029: * Apply a logical action to an object
030: */
031: public class HashMapApplicator extends BaseApplicator {
032:
033: public HashMapApplicator(DNAEncoding encoding) {
034: super (encoding);
035: }
036:
037: public TraversedReferences getPortableObjects(Object pojo,
038: TraversedReferences addTo) {
039: Map m = (Map) pojo;
040: filterPortableObjects(m.keySet(), addTo);
041: filterPortableObjects(m.values(), addTo);
042: return addTo;
043: }
044:
045: private void filterPortableObjects(Collection objects,
046: TraversedReferences addTo) {
047: for (Iterator i = objects.iterator(); i.hasNext();) {
048: Object o = i.next();
049: if (o != null && isPortableReference(o.getClass())) {
050: addTo.addAnonymousReference(o);
051: }
052: }
053: }
054:
055: /**
056: * return the key value pairs of field names to shared objects for this source. We already updated the literals and
057: * set the new TCObjectClone
058: */
059: public Map connectedCopy(Object source, Object dest, Map visited,
060: ClientObjectManager objectManager,
061: OptimisticTransactionManager txManager) {
062: Map cloned = new IdentityHashMap();
063:
064: Manageable sourceManageable = (Manageable) source;
065: Manageable destManaged = (Manageable) dest;
066:
067: Map sourceMap = (Map) source;
068: Map destMap = (Map) dest;
069:
070: for (Iterator i = sourceMap.entrySet().iterator(); i.hasNext();) {
071: Entry e = (Entry) i.next();
072:
073: Object copyKey = createCopyIfNecessary(objectManager,
074: visited, cloned, e.getKey());
075: Object copyValue = createCopyIfNecessary(objectManager,
076: visited, cloned, e.getValue());
077: destMap.put(copyKey, copyValue);
078: }
079:
080: destManaged.__tc_managed(new TCObjectClone(sourceManageable
081: .__tc_managed(), txManager));
082: return cloned;
083: }
084:
085: public void hydrate(ClientObjectManager objectManager,
086: TCObject tcObject, DNA dna, Object po) throws IOException,
087: ClassNotFoundException {
088: DNACursor cursor = dna.getCursor();
089:
090: while (cursor.next(encoding)) {
091: LogicalAction action = cursor.getLogicalAction();
092: int method = action.getMethod();
093: Object[] params = action.getParameters();
094: apply(objectManager, po, method, params);
095: }
096: }
097:
098: protected void apply(ClientObjectManager objectManager, Object po,
099: int method, Object[] params) throws ClassNotFoundException {
100: Map m = (Map) po;
101: switch (method) {
102: case SerializationUtil.PUT:
103: Object k = getKey(params);
104: Object v = getValue(params);
105: Object pkey = getObjectForKey(objectManager, k);
106:
107: Object value = getObjectForValue(objectManager, v);
108:
109: if (m instanceof TCMap) {
110: ((TCMap) m).__tc_applicator_put(pkey, value);
111: } else {
112: m.put(pkey, value);
113: }
114:
115: break;
116: case SerializationUtil.REMOVE:
117: Object rkey = params[0] instanceof ObjectID ? objectManager
118: .lookupObject((ObjectID) params[0]) : params[0];
119: if (m instanceof TCMap) {
120: ((TCMap) m).__tc_applicator_remove(rkey);
121: } else {
122: m.remove(rkey);
123: }
124:
125: break;
126: case SerializationUtil.CLEAR:
127: m.clear();
128: break;
129: default:
130: throw new AssertionError("invalid action:" + method);
131: }
132: }
133:
134: // This can be overridden by subclass if you want different behavior.
135: protected Object getObjectForValue(
136: ClientObjectManager objectManager, Object v)
137: throws ClassNotFoundException {
138: return (v instanceof ObjectID ? objectManager
139: .lookupObject((ObjectID) v) : v);
140: }
141:
142: // This can be overridden by subclass if you want different behavior.
143: protected Object getObjectForKey(ClientObjectManager objectManager,
144: Object k) throws ClassNotFoundException {
145: return (k instanceof ObjectID ? objectManager
146: .lookupObject((ObjectID) k) : k);
147: }
148:
149: private Object getValue(Object[] params) {
150: // Hack hack big hack for trove maps which replace the key on set as opposed to HashMaps which do not.
151: return params.length == 3 ? params[2] : params[1];
152: }
153:
154: private Object getKey(Object[] params) {
155: return params.length == 3 ? params[1] : params[0];
156: }
157:
158: public void dehydrate(ClientObjectManager objectManager,
159: TCObject tcObject, DNAWriter writer, Object pojo) {
160:
161: Map map = (Map) pojo;
162: for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
163: Entry entry = (Entry) i.next();
164: Object key = entry.getKey();
165: Object value = entry.getValue();
166:
167: if (!objectManager.isPortableInstance(key)) {
168: continue;
169: }
170: if (!objectManager.isPortableInstance(value)) {
171: continue;
172: }
173:
174: final Object addKey = getDehydratableObject(key,
175: objectManager);
176: final Object addValue = getDehydratableObject(value,
177: objectManager);
178:
179: if (addKey == null || addValue == null) {
180: continue;
181: }
182:
183: writer.addLogicalAction(SerializationUtil.PUT,
184: new Object[] { addKey, addValue });
185: }
186: }
187:
188: public Object getNewInstance(ClientObjectManager objectManager,
189: DNA dna) throws IOException, ClassNotFoundException {
190: if (false) {
191: throw new IOException();
192: } // silence compiler warning
193: if (false) {
194: throw new ClassNotFoundException();
195: } // silence compiler warning
196: throw new UnsupportedOperationException();
197: }
198: }
|