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 com.versant.core.jdo.VersantPersistenceManagerImp;
014: import com.versant.core.jdo.VersantStateManager;
015: import com.versant.core.jdo.VersantStateManager;
016: import com.versant.core.common.CollectionDiff;
017: import com.versant.core.common.VersantFieldMetaData;
018:
019: import javax.jdo.spi.PersistenceCapable;
020: import java.util.Collection;
021: import java.util.Iterator;
022: import java.util.TreeSet;
023:
024: import com.versant.core.common.BindingSupportImpl;
025: import com.versant.core.common.PersistenceContext;
026:
027: /**
028: * TreeSet SCO.
029: */
030: public class SCOTreeSet extends TreeSet implements
031: VersantManagedSCOCollection, VersantAdvancedSCO {
032:
033: private transient PersistenceCapable owner;
034: private transient VersantStateManager stateManager;
035: private final transient VersantFieldMetaData fmd;
036: private final transient boolean isMaster;
037: private final transient boolean isMany;
038: private final transient int inverseFieldNo;
039: private transient Object[] originalData;
040: private boolean beenReset;
041:
042: public SCOTreeSet(PersistenceCapable owner,
043: VersantStateManager stateManager, VersantFieldMetaData fmd,
044: Object[] originalData) {
045: super (fmd.getComparator());
046: this .isMaster = fmd.isManaged() && fmd.isMaster();
047: this .inverseFieldNo = fmd.getInverseFieldNo();
048: this .owner = owner;
049: this .stateManager = stateManager;
050: this .fmd = fmd;
051: this .isMany = fmd.isManaged() && fmd.isManyToMany();
052: this .originalData = originalData;
053: int n = originalData == null ? 0 : originalData.length;
054: if (!owner.jdoIsNew()) {
055: for (int i = 0; i < n; i++) {
056: Object o = originalData[i];
057: if (o == null)
058: break;
059: super .add(o);
060: }
061: } else if (isMaster) {
062: for (int i = 0; i < n; i++) {
063: Object o = originalData[i];
064: if (o == null)
065: throw createNPE();
066: super .add(o);
067: SCOInverseUtil.addMasterOnDetail(o, owner,
068: inverseFieldNo);
069: }
070: } else if (isMany) {
071: for (int i = 0; i < n; i++) {
072: Object o = originalData[i];
073: if (o == null)
074: throw createNPE();
075: super .add(o);
076: SCOInverseUtil.addToOtherSideOfManyToMany(o,
077: inverseFieldNo, owner);
078: }
079: } else {
080: for (int i = 0; i < n; i++) {
081: Object o = originalData[i];
082: if (o == null)
083: throw createNPE();
084: super .add(o);
085: }
086: }
087: }
088:
089: private RuntimeException createNPE() {
090: return BindingSupportImpl.getInstance().nullElement(
091: "Null element not allowed: " + fmd.getQName());
092: }
093:
094: public boolean add(Object o) {
095: if (o == null)
096: throw createNPE();
097: if (isMaster) {
098: boolean result = super .add(o);
099: if (result) {
100: makeDirty();
101: SCOInverseUtil.addMasterOnDetail(o, owner,
102: inverseFieldNo);
103: }
104: return result;
105: } else if (isMany) {
106: boolean result = super .add(o);
107: if (result) {
108: makeDirty();
109: SCOInverseUtil.addToOtherSideOfManyToMany(o,
110: inverseFieldNo, owner);
111: }
112: return result;
113: } else {
114: boolean result = super .add(o);
115: if (result)
116: makeDirty();
117: return result;
118: }
119: }
120:
121: public boolean remove(Object o) {
122: boolean result = super .remove(o);
123: if (result) {
124: makeDirty();
125: if (isMaster) {
126: SCOInverseUtil.removeMasterOnDetail(o, owner,
127: inverseFieldNo);
128: } else if (isMany) {
129: SCOInverseUtil.removeFromOtherSideOfManyToMany(o,
130: inverseFieldNo, owner);
131: }
132: }
133: return result;
134: }
135:
136: public void clear() {
137: if (isMaster) {
138: for (Iterator iter = super .iterator(); iter.hasNext();) {
139: SCOInverseUtil.removeMasterOnDetail(iter.next(), owner,
140: inverseFieldNo);
141: }
142: } else if (isMany) {
143: for (Iterator iter = super .iterator(); iter.hasNext();) {
144: SCOInverseUtil.removeFromOtherSideOfManyToMany(iter
145: .next(), inverseFieldNo, owner);
146: }
147: }
148: super .clear();
149: makeDirty();
150: }
151:
152: public boolean retainAll(Collection c) {
153: if (isMaster) {
154: boolean modified = false;
155: Iterator e = super .iterator();
156: while (e.hasNext()) {
157: Object o = e.next();
158: if (!c.contains(o)) {
159: e.remove();
160: SCOInverseUtil.removeMasterOnDetail(o, owner,
161: inverseFieldNo);
162: modified = true;
163: }
164: }
165: if (modified)
166: makeDirty();
167: return modified;
168: } else if (isMany) {
169: boolean modified = false;
170: Iterator e = super .iterator();
171: while (e.hasNext()) {
172: Object o = e.next();
173: if (!c.contains(o)) {
174: e.remove();
175: SCOInverseUtil.removeFromOtherSideOfManyToMany(o,
176: inverseFieldNo, owner);
177: modified = true;
178: }
179: }
180: if (modified)
181: makeDirty();
182: return modified;
183: } else if (super .retainAll(c)) {
184: makeDirty();
185: return true;
186: }
187: return false;
188: }
189:
190: public boolean removeAll(Collection c) {
191: if (isMaster) {
192: boolean modified = false;
193: Object o = null;
194: if (size() > c.size()) {
195: for (Iterator i = c.iterator(); i.hasNext();) {
196: o = i.next();
197: if (o != null) {
198: modified |= super .remove(o);
199: SCOInverseUtil.removeMasterOnDetail(o, owner,
200: inverseFieldNo);
201: }
202: }
203: } else {
204: for (Iterator i = super .iterator(); i.hasNext();) {
205: o = i.next();
206: if (c.contains(o)) {
207: i.remove();
208: modified = true;
209: SCOInverseUtil.removeMasterOnDetail(o, owner,
210: inverseFieldNo);
211: }
212: }
213: }
214: if (modified)
215: makeDirty();
216: return modified;
217: } else if (isMany) {
218: boolean modified = false;
219: Object o = null;
220: if (size() > c.size()) {
221: for (Iterator i = c.iterator(); i.hasNext();) {
222: o = i.next();
223: if (o != null) {
224: boolean ans = super .remove(o);
225: if (ans) {
226: modified = true;
227: SCOInverseUtil
228: .removeFromOtherSideOfManyToMany(o,
229: inverseFieldNo, owner);
230: }
231: }
232: }
233: } else {
234: for (Iterator i = super .iterator(); i.hasNext();) {
235: o = i.next();
236: if (c.contains(o)) {
237: i.remove();
238: modified = true;
239: SCOInverseUtil.removeFromOtherSideOfManyToMany(
240: o, inverseFieldNo, owner);
241: }
242: }
243: }
244: if (modified)
245: makeDirty();
246: return modified;
247: } else if (super .removeAll(c)) {
248: makeDirty();
249: return true;
250: }
251: return false;
252: }
253:
254: public boolean addAll(Collection c) {
255: if (isMaster) {
256: boolean modified = false;
257: Object o = null;
258: Iterator e = c.iterator();
259: while (e.hasNext()) {
260: o = e.next();
261: if (o == null) {
262: throw createNPE();
263: } else if (super .add(o)) {
264: modified = true;
265: SCOInverseUtil.addMasterOnDetail(o, owner,
266: inverseFieldNo);
267: }
268: }
269: if (modified)
270: makeDirty();
271: return modified;
272: } else if (isMany) {
273: boolean modified = false;
274: Object o = null;
275: Iterator e = c.iterator();
276: while (e.hasNext()) {
277: o = e.next();
278: if (o == null) {
279: throw createNPE();
280: } else if (super .add(o)) {
281: modified = true;
282: SCOInverseUtil.addToOtherSideOfManyToMany(o,
283: inverseFieldNo, owner);
284: }
285: }
286: if (modified)
287: makeDirty();
288: return modified;
289: } else if (super .addAll(c)) {
290: makeDirty();
291: return true;
292: }
293: return false;
294:
295: }
296:
297: public Iterator iterator() {
298: return new SCOIterator(super .iterator(), stateManager, owner,
299: fmd.getManagedFieldNo());
300: }
301:
302: public Object getOwner() {
303: return owner;
304: }
305:
306: public void makeTransient() {
307: owner = null;
308: stateManager = null;
309: }
310:
311: public void makeDirty() {
312: if (stateManager != null) {
313: stateManager.makeDirty(owner, fmd.getManagedFieldNo());
314: }
315: }
316:
317: public void reset() {
318: beenReset = true;
319: originalData = toArray();
320: }
321:
322: public CollectionDiff getCollectionDiff(PersistenceContext pm) {
323: Object[] data = toArray();
324: return CollectionDiffUtil.getUnorderedCollectionDiff(fmd, pm,
325: data, data.length,
326: (owner.jdoIsNew() && !beenReset) ? null : originalData);
327: }
328:
329: public void manyToManyAdd(Object o) {
330: if (super .add(o))
331: makeDirty();
332: }
333:
334: public void manyToManyRemove(Object o) {
335: if (super .remove(o))
336: makeDirty();
337: }
338:
339: /**
340: * Is the collection ordered.
341: */
342: public boolean isOrdered() {
343: return fmd.isOrdered();
344: }
345:
346: /**
347: * Put references to all the values into collectionData. If the
348: * values are PC instances then the instances themselves or their
349: * OIDs may be stored in collectionData.
350: */
351: public CollectionData fillCollectionData(
352: CollectionData collectionData) {
353: int size = size();
354: collectionData.valueCount = size;
355: Object[] newData;
356: Object[] values = collectionData.values;
357: if (values == null || values.length < size) {
358: newData = new Object[size];
359: } else {
360: newData = values;
361: }
362: int i = 0;
363: for (Iterator it = this.iterator(); it.hasNext();) {
364: newData[i++] = it.next();
365: }
366: collectionData.values = newData;
367: return collectionData;
368: }
369: }
|