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;
006:
007: import com.tc.exception.TCRuntimeException;
008: import com.tc.object.appevent.NonPortableEventContext;
009:
010: import java.util.ArrayList;
011: import java.util.IdentityHashMap;
012: import java.util.Iterator;
013: import java.util.List;
014: import java.util.Map;
015:
016: /**
017: * Generic Object traverser. Initial use for this is to add any unmanaged objects to the managed object tree
018: *
019: * @author steve
020: */
021: public class Traverser {
022: private static final TraverseTest NULL_TEST = new NullTraverseTest();
023: private final TraversalAction action;
024: private final PortableObjectProvider portableObjectProvider;
025: private NonPortableEventContext context;
026:
027: public Traverser(TraversalAction action,
028: PortableObjectProvider portableObjectProvider) {
029: this .action = action;
030: this .portableObjectProvider = portableObjectProvider;
031: }
032:
033: private void addReferencedObjects(Map toBeVisited, Object start,
034: Map visited, TraverseTest traverseTest) {
035: Class clazz = start.getClass();
036:
037: while (clazz != null) {
038: TraversedReferences portableObjects = new TraversedReferencesImpl();
039: portableObjects = portableObjectProvider
040: .getPortableObjects(clazz, start, portableObjects);
041:
042: for (Iterator i = portableObjects.iterator(); i.hasNext();) {
043: try {
044: TraversedReference currentReference = (TraversedReference) i
045: .next();
046: Object currentObject = currentReference.getValue();
047:
048: if (doNotTraverse(traverseTest, visited,
049: currentObject)) {
050: continue;
051: }
052:
053: traverseTest.checkPortability(currentReference,
054: start.getClass(), context);
055:
056: toBeVisited.put(currentObject, null);
057: } catch (IllegalArgumentException e) {
058: throw new TCRuntimeException(e);
059: }
060: }
061: clazz = clazz.getSuperclass();
062: }
063:
064: }
065:
066: private boolean doNotTraverse(TraverseTest traverseTest,
067: Map visited, Object current) {
068: if (current == null) {
069: return true;
070: }
071:
072: if (visited.containsKey(current)) {
073: return true;
074: }
075:
076: if (!traverseTest.shouldTraverse(current)) {
077: return true;
078: }
079:
080: return false;
081: }
082:
083: public void traverse(Object object) {
084: traverse(object, NULL_TEST, null);
085: }
086:
087: public void traverse(Object object, TraverseTest traverseTest,
088: NonPortableEventContext ctx) {
089: this .context = ctx;
090: Map visited = new IdentityHashMap();
091: List toAdd = new ArrayList();
092:
093: visited.put(object, null);
094:
095: IdentityHashMap toBeVisited = new IdentityHashMap();
096: addReferencedObjects(toBeVisited, object, visited, traverseTest);
097: toAdd.add(object);
098:
099: while (!toBeVisited.isEmpty()) {
100: for (Iterator i = new IdentityHashMap(toBeVisited).keySet()
101: .iterator(); i.hasNext();) {
102: Object obj = i.next();
103: visited.put(obj, null);
104: toBeVisited.remove(obj);
105: addReferencedObjects(toBeVisited, obj, visited,
106: traverseTest);
107: toAdd.add(obj); // action.visit() to be taken place after addReferencedObjects() so that
108: // the manager of the referenced objects will only be set after the referenced
109: // objects are obtained.
110: }
111: }
112: action.visit(toAdd);
113: }
114: }
|