001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdo.sco;
012:
013: import javax.jdo.spi.PersistenceCapable;
014: import java.util.*;
015:
016: import com.versant.core.common.OID;
017: import com.versant.core.common.*;
018:
019: /**
020: * This is a util used to extract a diff from to map's.
021: * <p/>
022: * This is not thread safe.
023: *
024: */
025: public final class MapDiffUtil {
026:
027: private VersantFieldMetaData fmd;
028: private boolean keyIsPC;
029: private boolean valueIsPC;
030: private List toDelete = new ArrayList();
031: private Map toInsert = new java.util.HashMap();
032: private static final Map EMPTY_BEFORE_MAP = new HashMap();
033:
034: public MapDiffUtil(VersantFieldMetaData fmd) {
035: this .fmd = fmd;
036: valueIsPC = fmd.isElementTypePC();
037: keyIsPC = fmd.isKeyTypePC();
038: }
039:
040: private void addForDelete(Object key) {
041: toDelete.add(key);
042: }
043:
044: private void addForInsert(Object key, Object value) {
045: toInsert.put(key, value);
046: }
047:
048: private void addForUpdate(Object key, Object value) {
049: toDelete.add(key);
050: toInsert.put(key, value);
051: }
052:
053: /**
054: * @param currentMap The dirty map
055: * @param beforeMap The map as before the changes. Null or Empty if first insert.
056: * @return
057: */
058: public MapDiff getDiff(Map currentMap, Map beforeMap,
059: PersistenceContext pm) {
060: //[BEGIN CHANGE: Pinaki]
061: // VDS Datastore requires the entire content of the map rather than the difference
062: // during flush. The corresponding flag is set in FieldMetaData during definition.
063:
064: if (fmd.isIncludeAllDataInDiff()) {
065: if (currentMap == null)
066: return null;
067: MapDiff mapDiff = new MapDiff(fmd);
068: int mapSize = currentMap.size();
069: mapDiff.insertedKeys = new Object[mapSize];
070: mapDiff.insertedValues = new Object[mapSize];
071: int i = 0;
072: for (Iterator keys = currentMap.keySet().iterator(); keys
073: .hasNext(); i++) {
074: Object key = keys.next();
075: Object value = currentMap.get(key);
076: mapDiff.insertedKeys[i] = (keyIsPC) ? pm
077: .getInternalOID((PersistenceCapable) key) : key;
078: mapDiff.insertedValues[i] = (valueIsPC) ? pm
079: .getInternalOID((PersistenceCapable) value)
080: : value;
081: }
082: return mapDiff;
083: }
084: //[END CHANGE: Pinaki]
085: if (beforeMap == null) {
086: beforeMap = EMPTY_BEFORE_MAP;
087: }
088: doAdded(currentMap, beforeMap);
089: doRemoved(currentMap, beforeMap);
090: doUpdates(currentMap, beforeMap);
091:
092: MapDiff mapDiff = new MapDiff(fmd);
093: doDeletes(mapDiff, pm);
094: if (!keyIsPC && !valueIsPC) {
095: mapDiff.insertedKeys = toInsert.keySet().toArray();
096: mapDiff.insertedValues = toInsert.values().toArray();
097: } else if (keyIsPC && valueIsPC) {
098: Object[] insKeys = new OID[toInsert.size()];
099: Object[] insVals = new OID[toInsert.size()];
100:
101: int c = 0;
102: Set insertedSet = toInsert.entrySet();
103: for (Iterator iterator = insertedSet.iterator(); iterator
104: .hasNext();) {
105: Map.Entry entry = (Map.Entry) iterator.next();
106: Object key = entry.getKey();
107: key = pm.getInternalOID((PersistenceCapable) key);
108: Object val = entry.getValue();
109: val = pm.getInternalOID((PersistenceCapable) val);
110: insKeys[c] = key;
111: insVals[c++] = val;
112: }
113: mapDiff.insertedKeys = insKeys;
114: mapDiff.insertedValues = insVals;
115: } else if (keyIsPC) {
116: Object[] insKeys = new OID[toInsert.size()];
117: Object[] insVals = toInsert.values().toArray();
118:
119: int c = 0;
120: Set insertedSet = toInsert.keySet();
121: for (Iterator iterator = insertedSet.iterator(); iterator
122: .hasNext();) {
123: Object key = iterator.next();
124: key = pm.getInternalOID((PersistenceCapable) key);
125: insKeys[c++] = key;
126: }
127: mapDiff.insertedKeys = insKeys;
128: mapDiff.insertedValues = insVals;
129:
130: } else if (valueIsPC) {
131: Object[] insKeys = toInsert.keySet().toArray();
132: Object[] insVals = new OID[toInsert.size()];
133: int c = 0;
134: Set insertedSet = toInsert.keySet();
135: for (Iterator iterator = insertedSet.iterator(); iterator
136: .hasNext();) {
137: Object value = toInsert.get(iterator.next());
138: value = pm.getInternalOID((PersistenceCapable) value);
139: insVals[c++] = value;
140: }
141: mapDiff.insertedKeys = insKeys;
142: mapDiff.insertedValues = insVals;
143:
144: }
145: toInsert.clear();
146: toDelete.clear();
147: return mapDiff;
148: }
149:
150: private void doDeletes(MapDiff mapDiff, PersistenceContext pm) {
151: Object[] delArray;
152: if (keyIsPC) {
153: delArray = new OID[toDelete.size()];
154: for (int i = 0; i < toDelete.size(); i++) {
155: delArray[i] = pm
156: .getInternalOID((PersistenceCapable) toDelete
157: .get(i));
158: }
159: } else {
160: delArray = toDelete.toArray();
161: }
162: mapDiff.deletedKeys = delArray;
163: }
164:
165: private void doAdded(Map currentMap, Map beforeMap) {
166: Set newKeys = new java.util.HashSet(currentMap.keySet());
167: newKeys.removeAll(beforeMap.keySet());
168: for (Iterator iterator = newKeys.iterator(); iterator.hasNext();) {
169: Object key = iterator.next();
170: Object val = currentMap.get(key);
171: addForInsert(key, val);
172: }
173: }
174:
175: private void doRemoved(Map currentMap, Map beforeMap) {
176: Set removedKeys = new java.util.HashSet(beforeMap.keySet());
177: removedKeys.removeAll(currentMap.keySet());
178: for (Iterator iterator = removedKeys.iterator(); iterator
179: .hasNext();) {
180: addForDelete(iterator.next());
181: }
182: }
183:
184: private void doUpdates(Map currentMap, Map beforeMap) {
185: Set keys = currentMap.keySet();
186: for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
187: Object key = iterator.next();
188: if (beforeMap.containsKey(key)) {
189: Object currentVal = currentMap.get(key);
190: Object beforeVal = beforeMap.get(key);
191: if (currentVal != null) {
192: if (!currentVal.equals(beforeVal)) {
193: addForUpdate(key, currentVal);
194: }
195: } else if (currentVal == null) {
196: if (beforeVal != null) {
197: addForUpdate(key, currentVal);
198: }
199: }
200: }
201: }
202: }
203: }
|