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 java.beans.DefaultPersistenceDelegate;
014: import java.beans.Encoder;
015: import java.beans.Expression;
016: import java.beans.Statement;
017: import java.util.*;
018:
019: /**
020: * This is a util class to assist with java.beans persistence for JDO Genie
021: * SCOs. Call register with an Encoder to instal persistence delegates to
022: * handle all the JDO Genie SCO classes.
023: *
024: * @see #register(java.beans.Encoder)
025: * @see java.beans.Encoder
026: * @see java.beans.XMLEncoder
027: */
028: public class PersistenceDelegateManager {
029:
030: /**
031: * Set persistence delegates on provided encoder for JDO Genie SCO instances.
032: */
033: public static void register(Encoder encoder) {
034: encoder.setPersistenceDelegate(
035: com.versant.core.jdo.sco.Date.class,
036: new SCOPersistenceDelegate(java.util.Date.class));
037:
038: encoder.setPersistenceDelegate(SCOList.class, new SCOListPD(
039: ArrayList.class));
040: encoder.setPersistenceDelegate(SCOArrayList.class,
041: new SCOListPD(ArrayList.class));
042: encoder.setPersistenceDelegate(SCOVector.class, new SCOListPD(
043: Vector.class));
044:
045: encoder.setPersistenceDelegate(SCOHashMap.class, new SCOMapPD(
046: HashMap.class));
047: encoder.setPersistenceDelegate(SCOHashtable.class,
048: new SCOMapPD(Hashtable.class));
049: encoder.setPersistenceDelegate(SCOTreeMap.class, new SCOMapPD(
050: TreeMap.class));
051: encoder.setPersistenceDelegate(SCOTreeSet.class, new SCOMapPD(
052: TreeSet.class));
053:
054: encoder.setPersistenceDelegate(SCOHashSet.class,
055: new SCOCollectionPD(HashSet.class));
056: encoder.setPersistenceDelegate(SCOLinkedList.class,
057: new SCOCollectionPD(LinkedList.class));
058: }
059:
060: private static void invokeStatement(Object instance,
061: String methodName, Object[] args, Encoder out) {
062: out.writeStatement(new Statement(instance, methodName, args));
063: }
064:
065: private static boolean equals(Object o1, Object o2) {
066: return (o1 == null) ? (o2 == null) : o1.equals(o2);
067: }
068:
069: public static class SCOPersistenceDelegate extends
070: DefaultPersistenceDelegate {
071:
072: Class javaType;
073:
074: public SCOPersistenceDelegate(Class javaType) {
075: this .javaType = javaType;
076: }
077:
078: protected Expression instantiate(Object oldInstance, Encoder out) {
079:
080: return new Expression(oldInstance, javaType, "new",
081: new Object[] {});
082: }
083:
084: protected boolean mutatesTo(Object oldInstance,
085: Object newInstance) {
086: if (oldInstance != null && newInstance != null) {
087: return true;
088: }
089: return super .mutatesTo(oldInstance, newInstance);
090: }
091: }
092:
093: public static class SCOCollectionPD extends SCOPersistenceDelegate {
094:
095: public SCOCollectionPD(Class javaType) {
096: super (javaType);
097: }
098:
099: protected void initialize(Class type, Object oldInstance,
100: Object newInstance, Encoder out) {
101: java.util.Collection oldO = (java.util.Collection) oldInstance;
102: java.util.Collection newO = (java.util.Collection) newInstance;
103:
104: if (newO.size() != 0) {
105: PersistenceDelegateManager.invokeStatement(oldInstance,
106: "clear", new Object[] {}, out);
107: }
108: for (Iterator i = oldO.iterator(); i.hasNext();) {
109: PersistenceDelegateManager.invokeStatement(oldInstance,
110: "add", new Object[] { i.next() }, out);
111: }
112: }
113: }
114:
115: public static class SCOListPD extends SCOPersistenceDelegate {
116:
117: public SCOListPD(Class javaType) {
118: super (javaType);
119: }
120:
121: protected void initialize(Class type, Object oldInstance,
122: Object newInstance, Encoder out) {
123:
124: java.util.List oldO = (java.util.List) oldInstance;
125: java.util.List newO = (java.util.List) newInstance;
126: int oldSize = oldO.size();
127: int newSize = (newO == null) ? 0 : newO.size();
128: if (oldSize < newSize) {
129: PersistenceDelegateManager.invokeStatement(oldInstance,
130: "clear", new Object[] {}, out);
131: newSize = 0;
132: }
133: for (int i = 0; i < newSize; i++) {
134: Object index = new Integer(i);
135:
136: Expression oldGetExp = new Expression(oldInstance,
137: "get", new Object[] { index });
138: Expression newGetExp = new Expression(newInstance,
139: "get", new Object[] { index });
140: try {
141: Object oldValue = oldGetExp.getValue();
142: Object newValue = newGetExp.getValue();
143: out.writeExpression(oldGetExp);
144: if (!PersistenceDelegateManager.equals(newValue,
145: out.get(oldValue))) {
146: PersistenceDelegateManager.invokeStatement(
147: oldInstance, "set", new Object[] {
148: index, oldValue }, out);
149: }
150: } catch (Exception e) {
151: out.getExceptionListener().exceptionThrown(e);
152: }
153: }
154: for (int i = newSize; i < oldSize; i++) {
155: PersistenceDelegateManager.invokeStatement(oldInstance,
156: "add", new Object[] { oldO.get(i) }, out);
157: }
158: }
159:
160: }
161:
162: public static class SCOMapPD extends SCOPersistenceDelegate {
163:
164: public SCOMapPD(Class javaType) {
165: super (javaType);
166: }
167:
168: protected void initialize(Class type, Object oldInstance,
169: Object newInstance, Encoder out) {
170: java.util.Map oldMap = (java.util.Map) oldInstance;
171: java.util.Map newMap = (java.util.Map) newInstance;
172: // Remove the new elements.
173: // Do this first otherwise we undo the adding work.
174: if (newMap != null) {
175: java.util.Iterator newKeys = newMap.keySet().iterator();
176: while (newKeys.hasNext()) {
177: Object newKey = newKeys.next();
178: // PENDING: This "key" is not in the right environment.
179: if (!oldMap.containsKey(newKey)) {
180: PersistenceDelegateManager.invokeStatement(
181: oldInstance, "remove",
182: new Object[] { newKey }, out);
183: }
184: }
185: }
186: // Add the new elements.
187: java.util.Iterator oldKeys = oldMap.keySet().iterator();
188: while (oldKeys.hasNext()) {
189: Object oldKey = oldKeys.next();
190:
191: Expression oldGetExp = new Expression(oldInstance,
192: "get", new Object[] { oldKey });
193: // Pending: should use newKey.
194: Expression newGetExp = new Expression(newInstance,
195: "get", new Object[] { oldKey });
196: try {
197: Object oldValue = oldGetExp.getValue();
198: Object newValue = newGetExp.getValue();
199: out.writeExpression(oldGetExp);
200: if (!PersistenceDelegateManager.equals(newValue,
201: out.get(oldValue))) {
202: PersistenceDelegateManager.invokeStatement(
203: oldInstance, "put", new Object[] {
204: oldKey, oldValue }, out);
205: }
206: } catch (Exception e) {
207: out.getExceptionListener().exceptionThrown(e);
208: }
209: }
210: }
211: }
212: }
|