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.exception.TCRuntimeException;
007: import com.tc.object.ClientObjectManager;
008: import com.tc.object.ObjectID;
009: import com.tc.object.TCObject;
010: import com.tc.object.TraversedReferences;
011: import com.tc.object.bytecode.ByteCodeUtil;
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.DNAEncoding;
016: import com.tc.object.dna.api.DNAWriter;
017: import com.tc.object.dna.api.LiteralAction;
018: import com.tc.object.dna.api.LogicalAction;
019: import com.tc.object.dna.api.PhysicalAction;
020: import com.tc.object.tx.optimistic.OptimisticTransactionManager;
021: import com.tc.object.tx.optimistic.TCObjectClone;
022: import com.tc.util.Assert;
023: import com.tc.util.FieldUtils;
024:
025: import java.io.IOException;
026: import java.lang.reflect.Array;
027: import java.lang.reflect.Field;
028: import java.lang.reflect.InvocationTargetException;
029: import java.lang.reflect.Method;
030: import java.util.IdentityHashMap;
031: import java.util.Iterator;
032: import java.util.Map;
033: import java.util.Map.Entry;
034: import java.util.concurrent.ConcurrentHashMap;
035:
036: /**
037: * Apply a logical action to an object
038: */
039: public class ConcurrentHashMapApplicator extends
040: PartialHashMapApplicator {
041: private static final String CONCURRENT_HASH_MAP_FIELD_NAME_PREFIX = ConcurrentHashMap.class
042: .getName()
043: + ".";
044: private static final String SEGMENT_MASK_FIELD_NAME = "segmentMask";
045: private static final String SEGMENT_SHIFT_FIELD_NAME = "segmentShift";
046: private static final String SEGMENT_FIELD_NAME = "segments";
047: private static final String TC_PUT_METHOD_NAME = ByteCodeUtil.TC_METHOD_PREFIX
048: + "put";
049:
050: private static final Field SEGMENT_MASK_FIELD;
051: private static final Field SEGMENT_SHIFT_FIELD;
052: private static final Field SEGMENT_FIELD;
053: private static final Method TC_PUT_METHOD;
054:
055: static {
056: try {
057: SEGMENT_MASK_FIELD = ConcurrentHashMap.class
058: .getDeclaredField(SEGMENT_MASK_FIELD_NAME);
059: SEGMENT_MASK_FIELD.setAccessible(true);
060:
061: SEGMENT_SHIFT_FIELD = ConcurrentHashMap.class
062: .getDeclaredField(SEGMENT_SHIFT_FIELD_NAME);
063: SEGMENT_SHIFT_FIELD.setAccessible(true);
064:
065: SEGMENT_FIELD = ConcurrentHashMap.class
066: .getDeclaredField(SEGMENT_FIELD_NAME);
067: SEGMENT_FIELD.setAccessible(true);
068:
069: TC_PUT_METHOD = ConcurrentHashMap.class.getDeclaredMethod(
070: TC_PUT_METHOD_NAME, new Class[] { Object.class,
071: Object.class });
072: TC_PUT_METHOD.setAccessible(true);
073: } catch (Exception e) {
074: throw new RuntimeException(e);
075: }
076: }
077:
078: public ConcurrentHashMapApplicator(DNAEncoding encoding) {
079: super (encoding);
080: }
081:
082: public TraversedReferences getPortableObjects(Object pojo,
083: TraversedReferences addTo) {
084: super .getPortableObjects(pojo, addTo);
085: getPhysicalPortableObjects(pojo, addTo);
086: return addTo;
087: }
088:
089: public void getPhysicalPortableObjects(Object pojo,
090: TraversedReferences addTo) {
091: try {
092: filterPortableObject(SEGMENT_MASK_FIELD.get(pojo), addTo);
093: filterPortableObject(SEGMENT_SHIFT_FIELD.get(pojo), addTo);
094: Object[] segments = (Object[]) SEGMENT_FIELD.get(pojo);
095: for (int i = 0; i < segments.length; i++) {
096: filterPortableObject(segments[i], addTo);
097: }
098: } catch (IllegalAccessException e) {
099: throw new TCRuntimeException(e);
100: }
101: }
102:
103: private void filterPortableObject(Object value,
104: TraversedReferences addTo) {
105: if (value != null && isPortableReference(value.getClass())) {
106: addTo.addAnonymousReference(value);
107: }
108: }
109:
110: public void hydrate(ClientObjectManager objectManager,
111: TCObject tcObject, DNA dna, Object po) throws IOException,
112: ClassNotFoundException {
113: int segmentLength = -1;
114: Object segment = null;
115: Object[] segments = null;
116: int segmentIndex = 0;
117: DNACursor cursor = dna.getCursor();
118:
119: while (cursor.next(encoding)) {
120: Object action = cursor.getAction();
121: if (action instanceof LogicalAction) {
122: if (segmentLength != -1) {
123: setSegmentField(segments, po, segmentLength,
124: segmentIndex);
125: segmentLength = -1;
126: }
127:
128: LogicalAction logicalAction = cursor.getLogicalAction();
129: int method = logicalAction.getMethod();
130: Object[] params = logicalAction.getParameters();
131: apply(objectManager, po, method, params);
132: } else if (action instanceof LiteralAction) {
133: LiteralAction literalAction = (LiteralAction) action;
134: segmentLength = ((Integer) literalAction.getObject())
135: .intValue();
136: } else if (action instanceof PhysicalAction) {
137: Assert.assertFalse(dna.isDelta()); // Physical fields are shared only when the DNA is not
138: // a delta.
139:
140: PhysicalAction physicalAction = cursor
141: .getPhysicalAction();
142:
143: Assert.eval(physicalAction.isTruePhysical());
144: String fieldName = physicalAction.getFieldName();
145: Object value = physicalAction.getObject();
146: try {
147: if (fieldName
148: .equals(CONCURRENT_HASH_MAP_FIELD_NAME_PREFIX
149: + SEGMENT_MASK_FIELD_NAME)) {
150: FieldUtils.tcSet(po, value, SEGMENT_MASK_FIELD);
151: } else if (fieldName
152: .equals(CONCURRENT_HASH_MAP_FIELD_NAME_PREFIX
153: + SEGMENT_SHIFT_FIELD_NAME)) {
154: FieldUtils
155: .tcSet(po, value, SEGMENT_SHIFT_FIELD);
156: } else if (fieldName
157: .equals(CONCURRENT_HASH_MAP_FIELD_NAME_PREFIX
158: + SEGMENT_FIELD_NAME + segmentIndex)) {
159: segment = objectManager
160: .lookupObject((ObjectID) value);
161: if (segments == null) {
162: segments = (Object[]) Array.newInstance(
163: segment.getClass(), segmentLength);
164: }
165: segments[segmentIndex] = segment;
166: segmentIndex++;
167: }
168: } catch (IllegalAccessException e) {
169: throw new TCRuntimeException(e);
170: }
171: }
172: }
173: setSegmentField(segments, po, segmentLength, segmentIndex);
174: }
175:
176: private void setSegmentField(Object[] segments, Object po,
177: int segmentLength, int segmentIndex) {
178: if (segmentLength != -1) {
179: Assert.assertEquals(segmentLength, segmentIndex);
180: try {
181: FieldUtils.tcSet(po, segments, SEGMENT_FIELD);
182: } catch (IllegalAccessException e) {
183: throw new TCRuntimeException(e);
184: }
185: }
186: }
187:
188: public void dehydrate(ClientObjectManager objectManager,
189: TCObject tcObject, DNAWriter writer, Object pojo) {
190: dehydrateFields(objectManager, tcObject, writer, pojo);
191: super .dehydrate(objectManager, tcObject, writer, pojo);
192: }
193:
194: private void dehydrateFields(ClientObjectManager objectManager,
195: TCObject tcObject, DNAWriter writer, Object pojo) {
196: try {
197: Object segmentMask = SEGMENT_MASK_FIELD.get(pojo);
198: segmentMask = getDehydratableObject(segmentMask,
199: objectManager);
200: writer.addPhysicalAction(
201: CONCURRENT_HASH_MAP_FIELD_NAME_PREFIX
202: + SEGMENT_MASK_FIELD_NAME, segmentMask);
203:
204: Object segmentShift = SEGMENT_SHIFT_FIELD.get(pojo);
205: segmentShift = getDehydratableObject(segmentShift,
206: objectManager);
207: writer.addPhysicalAction(
208: CONCURRENT_HASH_MAP_FIELD_NAME_PREFIX
209: + SEGMENT_SHIFT_FIELD_NAME, segmentShift);
210:
211: Object[] segments = (Object[]) SEGMENT_FIELD.get(pojo);
212: writer.addLiteralValue(new Integer(segments.length));
213: for (int i = 0; i < segments.length; i++) {
214: Object segment = segments[i];
215: segment = getDehydratableObject(segment, objectManager);
216: writer.addPhysicalAction(
217: CONCURRENT_HASH_MAP_FIELD_NAME_PREFIX
218: + SEGMENT_FIELD_NAME + i, segment);
219: }
220: } catch (IllegalAccessException e) {
221: throw new TCRuntimeException(e);
222: }
223: }
224:
225: public Map connectedCopy(Object source, Object dest, Map visited,
226: ClientObjectManager objectManager,
227: OptimisticTransactionManager txManager) {
228: Map cloned = new IdentityHashMap();
229:
230: Manageable sourceManageable = (Manageable) source;
231: Manageable destManaged = (Manageable) dest;
232:
233: Map sourceMap = (Map) source;
234: Map destMap = (Map) dest;
235:
236: for (Iterator i = sourceMap.entrySet().iterator(); i.hasNext();) {
237: Entry e = (Entry) i.next();
238:
239: Object copyKey = createCopyIfNecessary(objectManager,
240: visited, cloned, e.getKey());
241: Object copyValue = createCopyIfNecessary(objectManager,
242: visited, cloned, e.getValue());
243: try {
244: TC_PUT_METHOD.invoke(destMap, new Object[] { copyKey,
245: copyValue });
246: } catch (IllegalArgumentException e1) {
247: throw new TCRuntimeException(e1);
248: } catch (IllegalAccessException e1) {
249: throw new TCRuntimeException(e1);
250: } catch (InvocationTargetException e1) {
251: throw new TCRuntimeException(e1);
252: }
253: }
254:
255: destManaged.__tc_managed(new TCObjectClone(sourceManageable
256: .__tc_managed(), txManager));
257: return cloned;
258: }
259: }
|