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.logging.TCLogger;
007: import com.tc.logging.TCLogging;
008: import com.tc.object.ClientObjectManager;
009: import com.tc.object.LiteralValues;
010: import com.tc.object.ObjectID;
011: import com.tc.object.TCObject;
012: import com.tc.object.dna.api.DNAEncoding;
013: import com.tc.util.Assert;
014:
015: import java.util.Map;
016:
017: /**
018: * This class provides facilities for use in implementing applicators.
019: */
020: public abstract class BaseApplicator implements ChangeApplicator {
021:
022: private static final TCLogger logger = TCLogging
023: .getLogger(BaseApplicator.class);
024: private static final LiteralValues literals = createLiteralValuesInstance();
025:
026: /**
027: * The encoding to use when reading/writing DNA
028: */
029: protected final DNAEncoding encoding;
030:
031: private static final LiteralValues createLiteralValuesInstance() {
032: try {
033: Class klazz = Class.forName("com.tc.object.LiteralValues");
034: return (LiteralValues) klazz.newInstance();
035: } catch (ClassNotFoundException e) {
036: throw new Error(e);
037: } catch (InstantiationException e) {
038: throw new Error(e);
039: } catch (IllegalAccessException e) {
040: throw new Error(e);
041: }
042: }
043:
044: /**
045: * Construct a BaseApplicator with an encoding to use when reading/writing DNA
046: * @param encoding DNA encoding to use
047: */
048: protected BaseApplicator(DNAEncoding encoding) {
049: this .encoding = encoding;
050: }
051:
052: /**
053: * Get an ObjectID or literal value for the given pojo
054: * @param pojo Object instance
055: * @param objectManager Client-side object manager
056: * @return ObjectID representing pojo, or the pojo itself if its a literal, or null if it's a non-portable object
057: */
058: protected final Object getDehydratableObject(Object pojo,
059: ClientObjectManager objectManager) {
060: if (pojo == null) {
061: return ObjectID.NULL_ID;
062: } else if (literals.isLiteralInstance(pojo)) {
063: return pojo;
064: } else {
065: TCObject tcObject = objectManager
066: .lookupExistingOrNull(pojo);
067: if (tcObject == null) {
068: // When we dehydrate complex objects, traverser bails out on the first non portable
069: // object. We dont want to dehydrate things that are not added in the ClientObjectManager.
070: logger.warn("Not dehydrating object of type "
071: + pojo.getClass().getName() + "@"
072: + System.identityHashCode(pojo));
073: return null;
074: }
075: return tcObject.getObjectID();
076: }
077: }
078:
079: /**
080: * Determine whether the pojo is a literal instance
081: * @param pojo Object to examine
082: * @return True if literal
083: */
084: protected final boolean isLiteralInstance(Object pojo) {
085: return literals.isLiteralInstance(pojo);
086: }
087:
088: /**
089: * Determine whether this class is portable
090: * @param c The class
091: * @return True if portable
092: */
093: protected boolean isPortableReference(Class c) {
094: return !literals.isLiteral(c.getName());
095: }
096:
097: /**
098: * For an inner object, create or find the containing parent instance.
099: * @param visited Map of those objects that have been visited so far
100: * @param objectManager Client-side object manager
101: * @param cloned Map of those objects that have been cloned already (key=obj, value=clone)
102: * @param v The object
103: * @return The new or existing parent object clone
104: */
105: protected Object createParentIfNecessary(Map visited,
106: ClientObjectManager objectManager, Map cloned, Object v) {
107: return objectManager.createParentCopyInstanceIfNecessary(
108: visited, cloned, v);
109: }
110:
111: /**
112: * Create or use existing copy of originalValue
113: * @param objectManager Client-side object manager
114: * @param visited Already visited objects and their clones (key=obj, value=clone)
115: * @param originalValue The original value
116: * @return The clone, may be new or may be copy
117: */
118: protected Object createCopyIfNecessary(
119: ClientObjectManager objectManager, Map visited, Map cloned,
120: Object originalValue) {
121: Object copyKey;
122: if (originalValue == null || isLiteralInstance(originalValue)) {
123: copyKey = originalValue;
124: } else if (visited.containsKey(originalValue)) {
125: Assert.eval(visited.get(originalValue) != null);
126: copyKey = visited.get(originalValue);
127: } else {
128: Assert.eval(!isLiteralInstance(originalValue));
129: copyKey = objectManager.createNewCopyInstance(
130: originalValue, createParentIfNecessary(visited,
131: objectManager, cloned, originalValue));
132:
133: visited.put(originalValue, copyKey);
134: cloned.put(originalValue, copyKey);
135: }
136: return copyKey;
137: }
138:
139: }
|