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.objectserver.managedobject;
005:
006: import com.tc.exception.ImplementMe;
007: import com.tc.io.serializer.TCObjectInputStream;
008: import com.tc.io.serializer.TCObjectOutputStream;
009: import com.tc.object.ObjectID;
010: import com.tc.object.SerializationUtil;
011: import com.tc.object.dna.api.DNACursor;
012: import com.tc.object.dna.api.DNAWriter;
013: import com.tc.object.dna.api.DNAEncoding;
014: import com.tc.object.dna.api.LiteralAction;
015: import com.tc.object.dna.api.LogicalAction;
016: import com.tc.object.dna.api.PhysicalAction;
017: import com.tc.objectserver.core.api.ManagedObjectState;
018: import com.tc.objectserver.persistence.impl.InMemoryPersistor;
019: import com.tc.util.Assert;
020:
021: import java.io.ByteArrayInputStream;
022: import java.io.ByteArrayOutputStream;
023: import java.lang.reflect.Field;
024: import java.lang.reflect.InvocationHandler;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Modifier;
027: import java.lang.reflect.Proxy;
028: import java.util.ArrayList;
029: import java.util.Arrays;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.List;
033: import java.util.Map;
034:
035: import junit.framework.TestCase;
036:
037: public class ManagedObjectStateSerializationTest extends TestCase {
038: private static final String loaderDesc = "System.loader";
039:
040: private ObjectID objectID;
041: private ManagedObjectChangeListenerProvider listenerProvider;
042:
043: public void setUp() throws Exception {
044: super .setUp();
045: listenerProvider = new NullManagedObjectChangeListenerProvider();
046: ManagedObjectStateFactory.disableSingleton(true);
047: ManagedObjectStateFactory.createInstance(listenerProvider,
048: new InMemoryPersistor());
049: objectID = new ObjectID(2000);
050: }
051:
052: protected void tearDown() throws Exception {
053: super .tearDown();
054: ManagedObjectStateFactory.disableSingleton(false);
055: objectID = null;
056: listenerProvider = null;
057: }
058:
059: public void testCheckIfMissingAnyManagedObjectType()
060: throws Exception {
061: Field[] fields = ManagedObjectState.class.getDeclaredFields();
062:
063: for (int i = 0; i < fields.length; i++) {
064: Field field = fields[i];
065:
066: int fieldModifier = field.getModifiers();
067: if (Modifier.isStatic(fieldModifier)
068: && Modifier.isFinal(fieldModifier)) {
069: Byte type = (Byte) field.get(null);
070: switch (type.byteValue()) {
071: case ManagedObjectState.PHYSICAL_TYPE:
072: testPhysical();
073: break;
074: case ManagedObjectState.DATE_TYPE:
075: testDate();
076: break;
077: case ManagedObjectState.MAP_TYPE:
078: case ManagedObjectState.PARTIAL_MAP_TYPE:
079: // Map type is tested in another test.
080: break;
081: case ManagedObjectState.LINKED_HASHMAP_TYPE:
082: testLinkedHashMap();
083: break;
084: case ManagedObjectState.ARRAY_TYPE:
085: testArray();
086: break;
087: case ManagedObjectState.LITERAL_TYPE:
088: testLiteral();
089: break;
090: case ManagedObjectState.LIST_TYPE:
091: testList();
092: break;
093: case ManagedObjectState.SET_TYPE:
094: testSet();
095: break;
096: case ManagedObjectState.TREE_SET_TYPE:
097: testTreeSet();
098: break;
099: case ManagedObjectState.TREE_MAP_TYPE:
100: testTreeMap();
101: break;
102: case ManagedObjectState.QUEUE_TYPE:
103: testLinkedBlockingQueue();
104: break;
105: case ManagedObjectState.CONCURRENT_HASHMAP_TYPE:
106: testConcurrentHashMap();
107: break;
108: case ManagedObjectState.PROXY_TYPE:
109: testProxy();
110: break;
111: case ManagedObjectState.URL_TYPE:
112: testURL();
113: break;
114: default:
115: throw new AssertionError(
116: "Type "
117: + type
118: + " does not have a test case in ManagedObjectStateSerializationTest.");
119: }
120: }
121: }
122: }
123:
124: public void testProxy() throws Exception {
125: String CLASSLOADER_FIELD_NAME = "java.lang.reflect.Proxy.loader";
126: String INTERFACES_FIELD_NAME = "java.lang.reflect.Proxy.interfaces";
127: String INVOCATION_HANDLER_FIELD_NAME = "java.lang.reflect.Proxy.h";
128:
129: MyInvocationHandler handler = new MyInvocationHandler();
130: Proxy myProxy = (Proxy) Proxy.newProxyInstance(this .getClass()
131: .getClassLoader(), new Class[] { MyProxyInf1.class,
132: MyProxyInf2.class }, handler);
133: String className = myProxy.getClass().getName();
134:
135: TestDNACursor cursor = new TestDNACursor();
136:
137: cursor.addPhysicalAction(CLASSLOADER_FIELD_NAME, myProxy
138: .getClass().getClassLoader(), true);
139: cursor.addPhysicalAction(INTERFACES_FIELD_NAME, myProxy
140: .getClass().getInterfaces(), true);
141: cursor.addPhysicalAction(INVOCATION_HANDLER_FIELD_NAME,
142: new ObjectID(2002), true);
143:
144: ManagedObjectState state = applyValidation(className, cursor);
145:
146: serializationValidation(state, cursor,
147: ManagedObjectState.PHYSICAL_TYPE);
148: }
149:
150: public void testPhysical() throws Exception {
151: String className = "com.tc.objectserver.managedobject.ManagedObjectStateSerializationTest";
152: TestDNACursor cursor = new TestDNACursor();
153:
154: cursor.addPhysicalAction("field1", new ObjectID(2002), true);
155: cursor.addPhysicalAction("field2", new ObjectID(2003), true);
156: cursor.addPhysicalAction("field3", new Integer(33), false);
157:
158: ManagedObjectState state = applyValidation(className, cursor);
159:
160: serializationValidation(state, cursor,
161: ManagedObjectState.PHYSICAL_TYPE);
162: }
163:
164: public void testDate() throws Exception {
165: String className = "java.util.Date";
166:
167: TestDNACursor cursor = new TestDNACursor();
168:
169: cursor.addLogicalAction(SerializationUtil.SET_TIME,
170: new Long[] { new Long(System.currentTimeMillis()) });
171: cursor.addLogicalAction(SerializationUtil.SET_NANOS,
172: new Integer[] { new Integer(0) });
173:
174: ManagedObjectState state = applyValidation(className, cursor);
175:
176: serializationValidation(state, cursor,
177: ManagedObjectState.DATE_TYPE);
178: }
179:
180: public void testLinkedHashMap() throws Exception {
181: String className = "java.util.LinkedHashMap";
182: String ACCESS_ORDER_FIELDNAME = "java.util.LinkedHashMap.accessOrder";
183:
184: TestDNACursor cursor = new TestDNACursor();
185:
186: cursor.addPhysicalAction(ACCESS_ORDER_FIELDNAME, Boolean.FALSE,
187: false);
188:
189: cursor.addLogicalAction(SerializationUtil.PUT, new Object[] {
190: new ObjectID(2002), new ObjectID(2003) });
191: cursor.addLogicalAction(SerializationUtil.PUT, new Object[] {
192: new ObjectID(2004), new ObjectID(2005) });
193:
194: ManagedObjectState state = applyValidation(className, cursor);
195:
196: serializationValidation(state, cursor,
197: ManagedObjectState.LINKED_HASHMAP_TYPE);
198: }
199:
200: public void testArray() throws Exception {
201: String className = "[java.lang.Integer";
202: TestDNACursor cursor = new TestDNACursor();
203:
204: cursor.addArrayAction(new Integer[] { new Integer(27) });
205:
206: ManagedObjectState state = applyValidation(className, cursor);
207:
208: serializationValidation(state, cursor,
209: ManagedObjectState.ARRAY_TYPE);
210: }
211:
212: public void testLiteral() throws Exception {
213: String className = "java.lang.Integer";
214: TestDNACursor cursor = new TestDNACursor();
215:
216: cursor.addLiteralAction(new Integer(27));
217:
218: ManagedObjectState state = applyValidation(className, cursor);
219:
220: serializationValidation(state, cursor,
221: ManagedObjectState.LITERAL_TYPE);
222: }
223:
224: public void testList() throws Exception {
225: String className = "java.util.ArrayList";
226: TestDNACursor cursor = new TestDNACursor();
227:
228: cursor.addLogicalAction(SerializationUtil.ADD,
229: new Object[] { new ObjectID(2002) });
230: cursor.addLogicalAction(SerializationUtil.ADD,
231: new Object[] { new ObjectID(2003) });
232:
233: ManagedObjectState state = applyValidation(className, cursor);
234:
235: serializationValidation(state, cursor,
236: ManagedObjectState.LIST_TYPE);
237: }
238:
239: public void testSet() throws Exception {
240: String className = "java.util.HashSet";
241: TestDNACursor cursor = new TestDNACursor();
242:
243: cursor.addLogicalAction(SerializationUtil.ADD,
244: new Object[] { new ObjectID(2002) });
245: cursor.addLogicalAction(SerializationUtil.ADD,
246: new Object[] { new ObjectID(2003) });
247:
248: ManagedObjectState state = applyValidation(className, cursor);
249:
250: serializationValidation(state, cursor,
251: ManagedObjectState.SET_TYPE);
252: }
253:
254: public void testTreeSet() throws Exception {
255: String className = "java.util.TreeSet";
256: String COMPARATOR_FIELDNAME = "java.util.TreeMap.comparator";
257:
258: TestDNACursor cursor = new TestDNACursor();
259:
260: cursor.addPhysicalAction(COMPARATOR_FIELDNAME, new ObjectID(
261: 2001), true);
262:
263: cursor.addLogicalAction(SerializationUtil.ADD,
264: new Object[] { new ObjectID(2002) });
265: cursor.addLogicalAction(SerializationUtil.ADD,
266: new Object[] { new ObjectID(2003) });
267:
268: ManagedObjectState state = applyValidation(className, cursor);
269:
270: serializationValidation(state, cursor,
271: ManagedObjectState.TREE_SET_TYPE);
272: }
273:
274: public void testTreeMap() throws Exception {
275: String className = "java.util.TreeMap";
276: String COMPARATOR_FIELDNAME = "java.util.TreeMap.comparator";
277:
278: TestDNACursor cursor = new TestDNACursor();
279:
280: cursor.addPhysicalAction(COMPARATOR_FIELDNAME, new ObjectID(
281: 2001), true);
282:
283: cursor.addLogicalAction(SerializationUtil.PUT, new Object[] {
284: new ObjectID(2002), new ObjectID(2003) });
285: cursor.addLogicalAction(SerializationUtil.PUT, new Object[] {
286: new ObjectID(2004), new ObjectID(2005) });
287:
288: ManagedObjectState state = applyValidation(className, cursor);
289:
290: serializationValidation(state, cursor,
291: ManagedObjectState.TREE_MAP_TYPE);
292: }
293:
294: public void testLinkedBlockingQueue() throws Exception {
295: String className = "java.util.concurrent.LinkedBlockingQueue";
296: String TAKE_LOCK_FIELD_NAME = "java.util.concurrent.LinkedBlockingQueue.takeLock";
297: String PUT_LOCK_FIELD_NAME = "java.util.concurrent.LinkedBlockingQueue.putLock";
298: String CAPACITY_FIELD_NAME = "java.util.concurrent.LinkedBlockingQueue.capacity";
299:
300: TestDNACursor cursor = new TestDNACursor();
301:
302: cursor.addPhysicalAction(TAKE_LOCK_FIELD_NAME, new ObjectID(
303: 2001), true);
304: cursor.addPhysicalAction(PUT_LOCK_FIELD_NAME,
305: new ObjectID(2002), true);
306: cursor.addPhysicalAction(CAPACITY_FIELD_NAME, new Integer(100),
307: false);
308:
309: cursor.addLogicalAction(SerializationUtil.PUT,
310: new Object[] { new ObjectID(2003) });
311: cursor.addLogicalAction(SerializationUtil.PUT,
312: new Object[] { new ObjectID(2004) });
313:
314: ManagedObjectState state = applyValidation(className, cursor);
315:
316: serializationValidation(state, cursor,
317: ManagedObjectState.QUEUE_TYPE);
318: }
319:
320: public void testConcurrentHashMap() throws Exception {
321: String className = "java.util.concurrent.ConcurrentHashMap";
322: String SEGMENT_MASK_FIELD_NAME = className + ".segmentMask";
323: String SEGMENT_SHIFT_FIELD_NAME = className + ".segmentShift";
324: String SEGMENT_FIELD_NAME = className + ".segments";
325:
326: TestDNACursor cursor = new TestDNACursor();
327:
328: cursor.addPhysicalAction(SEGMENT_MASK_FIELD_NAME, new Integer(
329: 10), false);
330: cursor.addPhysicalAction(SEGMENT_SHIFT_FIELD_NAME, new Integer(
331: 20), false);
332: cursor.addLiteralAction(new Integer(2));
333: cursor.addPhysicalAction(SEGMENT_FIELD_NAME + 0, new ObjectID(
334: 2001), true);
335: cursor.addPhysicalAction(SEGMENT_FIELD_NAME + 1, new ObjectID(
336: 2002), true);
337:
338: cursor.addLogicalAction(SerializationUtil.PUT, new Object[] {
339: new ObjectID(2002), new ObjectID(2003) });
340: cursor.addLogicalAction(SerializationUtil.PUT, new Object[] {
341: new ObjectID(2004), new ObjectID(2005) });
342:
343: ManagedObjectState state = applyValidation(className, cursor);
344:
345: serializationValidation(state, cursor,
346: ManagedObjectState.CONCURRENT_HASHMAP_TYPE);
347: }
348:
349: public void testURL() throws Exception {
350: String className = "java.net.URL";
351:
352: TestDNACursor cursor = new TestDNACursor();
353:
354: cursor.addLogicalAction(SerializationUtil.URL_SET,
355: new Object[] { "http", "terracotta.org",
356: new Integer(8080), "auth", "user:pass",
357: "/test", "par1=val1", "ref" });
358:
359: ManagedObjectState state = applyValidation(className, cursor);
360:
361: serializationValidation(state, cursor,
362: ManagedObjectState.URL_TYPE);
363: }
364:
365: private ManagedObjectState applyValidation(String className,
366: DNACursor dnaCursor) throws Exception {
367: ManagedObjectState state = apply(className, dnaCursor);
368: TestDNAWriter dnaWriter = dehydrate(state);
369: validate(dnaCursor, dnaWriter);
370:
371: return state;
372: }
373:
374: private void serializationValidation(ManagedObjectState state,
375: DNACursor dnaCursor, byte type) throws Exception {
376: byte[] buffer = writeTo(state);
377: TestDNAWriter dnaWriter = readFrom(type, buffer);
378: validate(dnaCursor, dnaWriter);
379: }
380:
381: private byte[] writeTo(ManagedObjectState state) throws Exception {
382: ByteArrayOutputStream bout = new ByteArrayOutputStream();
383: TCObjectOutputStream out = new TCObjectOutputStream(bout);
384: state.writeTo(out);
385:
386: return bout.toByteArray();
387: }
388:
389: private TestDNAWriter readFrom(byte type, byte[] buffer)
390: throws Exception {
391: ByteArrayInputStream bin = new ByteArrayInputStream(buffer);
392: TCObjectInputStream in = new TCObjectInputStream(bin);
393:
394: ManagedObjectState state = ManagedObjectStateFactory
395: .getInstance().readManagedObjectStateFrom(in, type);
396: return dehydrate(state);
397: }
398:
399: private ManagedObjectState apply(String className,
400: DNACursor dnaCursor) throws Exception {
401: ManagedObjectState state = ManagedObjectStateFactory
402: .getInstance().createState(new ObjectID(1),
403: ObjectID.NULL_ID, className, loaderDesc,
404: dnaCursor);
405: state.apply(objectID, dnaCursor, new BackReferences());
406: return state;
407: }
408:
409: private TestDNAWriter dehydrate(ManagedObjectState state)
410: throws Exception {
411: TestDNAWriter dnaWriter = new TestDNAWriter();
412: state.dehydrate(objectID, dnaWriter);
413: return dnaWriter;
414: }
415:
416: private void validate(DNACursor dnaCursor, TestDNAWriter writer)
417: throws Exception {
418: Assert.assertEquals(dnaCursor.getActionCount(), writer
419: .getActionCount());
420: dnaCursor.reset();
421: while (dnaCursor.next()) {
422: Object action = dnaCursor.getAction();
423: Assert.assertTrue(writer.containsAction(action));
424: }
425: }
426:
427: public class TestDNAWriter implements DNAWriter {
428: private List physicalActions = new ArrayList();
429: private List logicalActions = new ArrayList();
430: private List literalActions = new ArrayList();
431:
432: public TestDNAWriter() {
433: //
434: }
435:
436: public void addLogicalAction(int method, Object[] parameters) {
437: logicalActions.add(new LogicalAction(method, parameters));
438: }
439:
440: public void addPhysicalAction(String field, Object value) {
441: addPhysicalAction(field, value, value instanceof ObjectID);
442: }
443:
444: public void finalizeDNA(boolean isDeltaDNA) {
445: //
446: }
447:
448: public void addArrayElementAction(int index, Object value) {
449: //
450: }
451:
452: public void addEntireArray(Object value) {
453: physicalActions.add(new PhysicalAction(value));
454: }
455:
456: public void addLiteralValue(Object value) {
457: literalActions.add(new LiteralAction(value));
458: }
459:
460: public void setParentObjectID(ObjectID id) {
461: //
462: }
463:
464: public void setArrayLength(int length) {
465: //
466: }
467:
468: public void addPhysicalAction(String fieldName, Object value,
469: boolean canBeReference) {
470: physicalActions.add(new PhysicalAction(fieldName, value,
471: canBeReference));
472: }
473:
474: public int getActionCount() {
475: return logicalActions.size() + physicalActions.size()
476: + literalActions.size();
477: }
478:
479: private boolean containsAction(Object targetAction) {
480: if (targetAction instanceof LogicalAction) {
481: return containsLogicalAction((LogicalAction) targetAction);
482: } else if (targetAction instanceof PhysicalAction) {
483: return containsPhysicalAction((PhysicalAction) targetAction);
484: } else if (targetAction instanceof LiteralAction) {
485: return containsLiteralAction((LiteralAction) targetAction);
486: }
487:
488: return false;
489: }
490:
491: private boolean containsLogicalAction(LogicalAction targetAction) {
492: for (Iterator i = logicalActions.iterator(); i.hasNext();) {
493: LogicalAction action = (LogicalAction) i.next();
494: if (identicalLogicalAction(targetAction, action)) {
495: return true;
496: }
497: }
498: return false;
499: }
500:
501: private boolean containsPhysicalAction(
502: PhysicalAction targetAction) {
503: for (Iterator i = physicalActions.iterator(); i.hasNext();) {
504: PhysicalAction action = (PhysicalAction) i.next();
505: if (identicalPhysicalAction(targetAction, action)) {
506: return true;
507: }
508: }
509: return false;
510: }
511:
512: private boolean containsLiteralAction(LiteralAction targetAction) {
513: for (Iterator i = literalActions.iterator(); i.hasNext();) {
514: LiteralAction action = (LiteralAction) i.next();
515: if (identicalLiteralAction(targetAction, action)) {
516: return true;
517: }
518: }
519: return false;
520: }
521:
522: private boolean identicalLiteralAction(LiteralAction a1,
523: LiteralAction a2) {
524: if (a1 == null || a2 == null) {
525: return false;
526: }
527: if (a1.getObject() == null || a2.getObject() == null) {
528: return false;
529: }
530:
531: return a1.getObject().equals(a2.getObject());
532: }
533:
534: private boolean identicalPhysicalAction(PhysicalAction a1,
535: PhysicalAction a2) {
536: if (a1 == null || a2 == null) {
537: return false;
538: }
539:
540: if (!a1.isEntireArray() && !a2.isEntireArray()) {
541: if (a1.getFieldName() == null
542: || a2.getFieldName() == null) {
543: return false;
544: }
545: }
546:
547: if (a1.isEntireArray() != a2.isEntireArray()) {
548: return false;
549: }
550:
551: if (a1.getObject() == null && a2.getObject() == null) {
552: return true;
553: }
554: if (a1.getObject() == null && a2.getObject() != null) {
555: return false;
556: }
557: if (a1.getObject() != null && a2.getObject() == null) {
558: return false;
559: }
560:
561: if (a1.isEntireArray()) {
562: return Arrays.equals((Object[]) a1.getObject(),
563: (Object[]) a2.getObject());
564: } else if (a1.getObject() instanceof Object[]
565: && a2.getObject() instanceof Object[]) {
566: return Arrays.equals((Object[]) a1.getObject(),
567: (Object[]) a2.getObject());
568: } else {
569: if (a1.getFieldName().equals(a2.getFieldName())) {
570: return (a1.getObject().equals(a2.getObject()));
571: }
572: }
573: return false;
574: }
575:
576: private boolean identicalLogicalAction(LogicalAction a1,
577: LogicalAction a2) {
578: if (a1 == null || a2 == null) {
579: return false;
580: }
581: if (a1.getParameters() == null
582: || a2.getParameters() == null) {
583: return false;
584: }
585:
586: if (a1.getMethod() == a2.getMethod()) {
587: if (a1.getParameters().length == a2.getParameters().length) {
588: for (int i = 0; i < a1.getParameters().length; i++) {
589: if (!a1.getParameters()[i].equals(a2
590: .getParameters()[i])) {
591: return false;
592: }
593: }
594: return true;
595: }
596: }
597: return false;
598: }
599:
600: public void addClassLoaderAction(String classLoaderFieldName,
601: Object value) {
602: //
603:
604: }
605:
606: public void addSubArrayAction(int start, Object array,
607: int length) {
608: //
609: }
610: }
611:
612: public class TestDNACursor implements DNACursor {
613: private List actions = new ArrayList();
614: private int current = -1;
615:
616: public void addPhysicalAction(String addFieldName,
617: Object addObj, boolean isref) {
618: actions
619: .add(new PhysicalAction(addFieldName, addObj, isref));
620: }
621:
622: public void addLogicalAction(int method, Object params[]) {
623: actions.add(new LogicalAction(method, params));
624: }
625:
626: public void addArrayAction(Object[] objects) {
627: actions.add(new PhysicalAction(objects));
628: }
629:
630: public void addLiteralAction(Object value) {
631: actions.add(new LiteralAction(value));
632: }
633:
634: public boolean next() {
635: return actions.size() > ++current;
636: }
637:
638: public LogicalAction getLogicalAction() {
639: return (LogicalAction) actions.get(current);
640: }
641:
642: public Object getAction() {
643: return actions.get(current);
644: }
645:
646: public PhysicalAction getPhysicalAction() {
647: return (PhysicalAction) actions.get(current);
648: }
649:
650: public boolean next(DNAEncoding encoding) {
651: throw new ImplementMe();
652: }
653:
654: public int getActionCount() {
655: return actions.size();
656: }
657:
658: public void reset() throws UnsupportedOperationException {
659: current = -1;
660: }
661: }
662:
663: public interface MyProxyInf1 {
664: public int getValue();
665:
666: public void setValue(int i);
667: }
668:
669: public interface MyProxyInf2 {
670: public String getStringValue();
671:
672: public void setStringValue(String str);
673: }
674:
675: public static class MyInvocationHandler implements
676: InvocationHandler {
677: private Map values = new HashMap();
678: private Map stringValues = new HashMap();
679:
680: public Object invoke(Object proxy, Method method, Object[] args)
681: throws Throwable {
682: if (method.getName().equals("getValue")) {
683: return values.get(proxy);
684: } else if (method.getName().equals("setValue")) {
685: values.put(proxy, args[0]);
686: return null;
687: } else if (method.getName().equals("setStringValue")) {
688: stringValues.put(proxy, args[0]);
689: return null;
690: } else if (method.getName().equals("getStringValue")) {
691: return stringValues.get(proxy);
692: } else if (method.getName().equals("hashCode")) {
693: return new Integer(System.identityHashCode(proxy));
694: }
695: return null;
696: }
697: }
698: }
|