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