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.common.CollectionDiff;
016: import com.versant.core.common.VersantFieldMetaData;
017:
018: import javax.jdo.spi.PersistenceCapable;
019: import java.util.*;
020:
021: import com.versant.core.common.BindingSupportImpl;
022: import com.versant.core.common.PersistenceContext;
023:
024: /**
025: * A SCO implementation of a Vector.
026: */
027: public final class SCOVector extends Vector implements
028: VersantManagedSCOCollection, VersantAdvancedSCO {
029:
030: private transient PersistenceCapable owner;
031: private final transient VersantFieldMetaData fmd;
032: private transient VersantStateManager stateManager;
033: private final transient boolean isMaster;
034: private final transient boolean isMany;
035: private final transient int inverseFieldNo;
036: private transient Object[] originalData;
037: private transient boolean beenReset;
038:
039: public SCOVector(PersistenceCapable owner,
040: VersantStateManager stateManager, VersantFieldMetaData fmd,
041: Object[] originalData) {
042: this .owner = owner;
043: this .fmd = fmd;
044: this .isMaster = fmd.isManaged() && fmd.isMaster();
045: this .isMany = fmd.isManaged() && fmd.isManyToMany();
046: this .stateManager = stateManager;
047: this .inverseFieldNo = fmd.getInverseFieldNo();
048: this .originalData = originalData;
049: int n = originalData == null ? 0 : originalData.length;
050: if (n > 0)
051: ensureCapacity(n);
052: if (!owner.jdoIsNew()) {
053: for (int i = 0; i < n; i++) {
054: Object o = originalData[i];
055: super .add(o);
056: }
057: } else if (isMaster) {
058: for (int i = 0; i < n; i++) {
059: Object o = originalData[i];
060: super .add(o);
061: SCOInverseUtil.addMasterOnDetail(o, owner,
062: inverseFieldNo);
063: }
064: } else if (isMany) {
065: for (int i = 0; i < n; i++) {
066: Object o = originalData[i];
067: super .add(o);
068: SCOInverseUtil.addToOtherSideOfManyToMany(o,
069: inverseFieldNo, owner);
070: }
071: } else {
072: for (int i = 0; i < n; i++) {
073: Object o = originalData[i];
074: super .add(o);
075: }
076: }
077: }
078:
079: public synchronized void setSize(int newSize) {
080: if (newSize > elementCount) {
081: throw BindingSupportImpl.getInstance().nullElement(
082: "setSize called with " + newSize + " > "
083: + elementCount + " and "
084: + "null elements are not allowed: "
085: + fmd.getQName());
086: }
087: if (isMaster) {
088: for (int i = newSize; i < elementCount; i++) {
089: SCOInverseUtil.removeMasterOnDetail(elementData[i],
090: owner, inverseFieldNo);
091: }
092: super .setSize(newSize);
093: makeDirty();
094: } else if (isMany) {
095: for (int i = newSize; i < elementCount; i++) {
096: SCOInverseUtil.removeFromOtherSideOfManyToMany(
097: elementData[i], inverseFieldNo, owner);
098: }
099: super .setSize(newSize);
100: makeDirty();
101: } else {
102: super .setSize(newSize);
103: makeDirty();
104: }
105:
106: }
107:
108: public synchronized void setElementAt(Object obj, int index) {
109: if (isMaster) {
110: if (index >= elementCount) {
111: throw BindingSupportImpl.getInstance()
112: .arrayIndexOutOfBounds(
113: index + " >= " + elementCount);
114: }
115: if (elementData[index] != null) {
116: SCOInverseUtil.removeMasterOnDetail(elementData[index],
117: owner, inverseFieldNo);
118: }
119: SCOInverseUtil
120: .addMasterOnDetail(obj, owner, inverseFieldNo);
121: super .setElementAt(obj, index);
122: makeDirty();
123: } else if (isMany) {
124: if (index >= elementCount) {
125: throw BindingSupportImpl.getInstance()
126: .arrayIndexOutOfBounds(
127: index + " >= " + elementCount);
128: }
129: if (elementData[index] != null) {
130: SCOInverseUtil.removeFromOtherSideOfManyToMany(
131: elementData[index], inverseFieldNo, owner);
132: }
133: SCOInverseUtil.addToOtherSideOfManyToMany(obj,
134: inverseFieldNo, owner);
135: super .setElementAt(obj, index);
136: makeDirty();
137: } else {
138: super .setElementAt(obj, index);
139: makeDirty();
140: }
141:
142: }
143:
144: public synchronized void removeElementAt(int index) {
145:
146: if (isMaster) {
147: if (index >= elementCount) {
148: throw BindingSupportImpl.getInstance()
149: .arrayIndexOutOfBounds(
150: index + " >= " + elementCount);
151: } else if (index < 0) {
152: throw BindingSupportImpl.getInstance()
153: .arrayIndexOutOfBounds(index);
154: }
155: SCOInverseUtil.removeMasterOnDetail(elementData[index],
156: owner, inverseFieldNo);
157: } else if (isMany) {
158: if (index >= elementCount) {
159: throw BindingSupportImpl.getInstance()
160: .arrayIndexOutOfBounds(
161: index + " >= " + elementCount);
162: } else if (index < 0) {
163: throw BindingSupportImpl.getInstance()
164: .arrayIndexOutOfBounds(index);
165: }
166: SCOInverseUtil.removeFromOtherSideOfManyToMany(
167: elementData[index], inverseFieldNo, owner);
168: }
169: super .removeElementAt(index);
170:
171: makeDirty();
172: }
173:
174: public synchronized void insertElementAt(Object obj, int index) {
175: if (isMaster) {
176: super .insertElementAt(obj, index);
177: SCOInverseUtil
178: .addMasterOnDetail(obj, owner, inverseFieldNo);
179: makeDirty();
180: } else if (isMany) {
181: super .insertElementAt(obj, index);
182: SCOInverseUtil.addToOtherSideOfManyToMany(obj,
183: inverseFieldNo, owner);
184: makeDirty();
185: } else {
186: makeDirty();
187: super .insertElementAt(obj, index);
188: }
189: }
190:
191: public synchronized void addElement(Object obj) {
192: if (isMaster) {
193: super .addElement(obj);
194: makeDirty();
195: SCOInverseUtil
196: .addMasterOnDetail(obj, owner, inverseFieldNo);
197: } else if (isMany) {
198: super .addElement(obj);
199: makeDirty();
200: SCOInverseUtil.addToOtherSideOfManyToMany(obj,
201: inverseFieldNo, owner);
202: } else {
203: super .addElement(obj);
204: makeDirty();
205: }
206: }
207:
208: public synchronized void removeAllElements() {
209:
210: modCount++;
211: // Let gc do its work
212: for (int i = 0; i < elementCount; i++) {
213: if (isMaster) {
214: SCOInverseUtil.removeMasterOnDetail(elementData[i],
215: owner, inverseFieldNo);
216: } else if (isMany) {
217: SCOInverseUtil.removeFromOtherSideOfManyToMany(
218: elementData[i], inverseFieldNo, owner);
219: }
220: elementData[i] = null;
221: }
222:
223: elementCount = 0;
224: makeDirty();
225: }
226:
227: public synchronized Object set(int index, Object element) {
228: if (isMaster) {
229: Object obj = super .set(index, element);
230: if (obj != null) {
231: SCOInverseUtil.removeMasterOnDetail(obj, owner,
232: inverseFieldNo);
233: }
234: SCOInverseUtil.addMasterOnDetail(element, owner,
235: inverseFieldNo);
236: makeDirty();
237: return obj;
238: } else if (isMany) {
239: Object obj = super .set(index, element);
240: if (obj != null) {
241: SCOInverseUtil.removeFromOtherSideOfManyToMany(obj,
242: inverseFieldNo, owner);
243: }
244: SCOInverseUtil.addToOtherSideOfManyToMany(element,
245: inverseFieldNo, owner);
246: makeDirty();
247: return obj;
248: } else {
249: Object obj = super .set(index, element);
250: makeDirty();
251: return obj;
252: }
253: }
254:
255: public synchronized boolean add(Object o) {
256: if (isMaster) {
257: super .add(o);
258: makeDirty();
259: SCOInverseUtil.addMasterOnDetail(o, owner, inverseFieldNo);
260: return true;
261: } else if (isMany) {
262: super .add(o);
263: makeDirty();
264: SCOInverseUtil.addToOtherSideOfManyToMany(o,
265: inverseFieldNo, owner);
266: return true;
267: } else {
268: super .add(o);
269: makeDirty();
270: return true;
271: }
272: }
273:
274: public synchronized Object remove(int index) {
275: Object obj = super .remove(index);
276: if (isMaster) {
277: SCOInverseUtil.removeMasterOnDetail(obj, owner,
278: inverseFieldNo);
279: } else if (isMany) {
280: SCOInverseUtil.removeFromOtherSideOfManyToMany(obj,
281: inverseFieldNo, owner);
282: }
283: makeDirty();
284: return obj;
285: }
286:
287: public synchronized boolean addAll(Collection c) {
288: if (isMaster) {
289: boolean added = false;
290: ensureCapacity(elementCount + c.size());
291: for (Iterator iter = c.iterator(); iter.hasNext();) {
292: Object o = iter.next();
293: if (o == null) {
294: } else {
295: added = super .add(o);
296: SCOInverseUtil.addMasterOnDetail(o, owner,
297: inverseFieldNo);
298: }
299: }
300: if (added) {
301: makeDirty();
302: }
303: return added;
304: } else if (isMany) {
305: boolean added = false;
306: ensureCapacity(elementCount + c.size());
307: for (Iterator iter = c.iterator(); iter.hasNext();) {
308: Object o = iter.next();
309: if (o == null) {
310: } else {
311: added = super .add(o);
312: SCOInverseUtil.addToOtherSideOfManyToMany(o,
313: inverseFieldNo, owner);
314: }
315: }
316: if (added) {
317: makeDirty();
318: }
319: return added;
320: } else if (super .addAll(c)) {
321: makeDirty();
322: return true;
323: }
324: return false;
325: }
326:
327: public synchronized boolean removeAll(Collection c) {
328: boolean modified = false;
329: Iterator e = super .iterator();
330: Object o = null;
331: while (e.hasNext()) {
332: o = e.next();
333: if (c.contains(o)) {
334: e.remove();
335: modified = true;
336: if (isMaster) {
337: SCOInverseUtil.removeMasterOnDetail(o, owner,
338: inverseFieldNo);
339: } else if (isMany) {
340: SCOInverseUtil.removeFromOtherSideOfManyToMany(o,
341: inverseFieldNo, owner);
342: }
343: }
344: }
345: if (modified)
346: makeDirty();
347: return modified;
348: }
349:
350: public synchronized boolean retainAll(Collection c) {
351: boolean modified = false;
352: Iterator e = super .iterator();
353: Object o = null;
354: while (e.hasNext()) {
355: o = e.next();
356: if (!c.contains(o)) {
357: e.remove();
358: modified = true;
359: if (isMaster) {
360: SCOInverseUtil.removeMasterOnDetail(o, owner,
361: inverseFieldNo);
362: } else if (isMany) {
363: SCOInverseUtil.removeFromOtherSideOfManyToMany(o,
364: inverseFieldNo, owner);
365: }
366: }
367: }
368:
369: if (modified) {
370: makeDirty();
371: }
372: return modified;
373: }
374:
375: public synchronized boolean addAll(int index, Collection c) {
376: if (isMaster) {
377: boolean added = false;
378: ensureCapacity(elementCount + c.size());
379: for (Iterator iter = c.iterator(); iter.hasNext();) {
380: Object o = iter.next();
381: if (o == null) {
382: } else {
383: super .insertElementAt(o, index++);
384: SCOInverseUtil.addMasterOnDetail(o, owner,
385: inverseFieldNo);
386: added = true;
387: }
388: }
389: if (added) {
390: makeDirty();
391: }
392: return added;
393: } else if (isMany) {
394: boolean added = false;
395: ensureCapacity(elementCount + c.size());
396: for (Iterator iter = c.iterator(); iter.hasNext();) {
397: Object o = iter.next();
398: if (o == null) {
399: } else {
400: super .insertElementAt(o, index++);
401: SCOInverseUtil.addToOtherSideOfManyToMany(o,
402: inverseFieldNo, owner);
403: added = true;
404: }
405: }
406: if (added) {
407: makeDirty();
408: }
409: return added;
410: } else if (super .addAll(index, c)) {
411: makeDirty();
412: return true;
413: }
414: return false;
415: }
416:
417: protected void removeRange(int fromIndex, int toIndex) {
418: if (isMaster) {
419: List removeList = super .subList(fromIndex, toIndex);
420: for (int i = 0; i < removeList.size(); i++) {
421: SCOInverseUtil.removeMasterOnDetail(get(i), owner,
422: inverseFieldNo);
423: }
424: } else if (isMany) {
425: List removeList = super .subList(fromIndex, toIndex);
426: for (int i = 0; i < removeList.size(); i++) {
427: SCOInverseUtil.removeFromOtherSideOfManyToMany(get(i),
428: inverseFieldNo, owner);
429: }
430: }
431:
432: super .removeRange(fromIndex, toIndex);
433: makeDirty();
434: }
435:
436: public ListIterator listIterator() {
437: return new SCOListIterator(super .listIterator(), stateManager,
438: owner, fmd.getManagedFieldNo());
439: }
440:
441: public ListIterator listIterator(int index) {
442: return new SCOListIterator(super .listIterator(index),
443: stateManager, owner, fmd.getManagedFieldNo());
444: }
445:
446: public Iterator iterator() {
447: return new SCOIterator(super .iterator(), stateManager, owner,
448: fmd.getManagedFieldNo());
449: }
450:
451: public CollectionDiff getCollectionDiff(PersistenceContext pm) {
452: Object[] data = toArray();
453: if (fmd.isOrdered()) {
454: return CollectionDiffUtil.getOrderedCollectionDiff(fmd, pm,
455: data, data.length,
456: (owner.jdoIsNew() && !beenReset) ? null
457: : originalData);
458: } else {
459: return CollectionDiffUtil.getUnorderedCollectionDiff(fmd,
460: pm, data, data.length,
461: (owner.jdoIsNew() && !beenReset) ? null
462: : originalData);
463: }
464: }
465:
466: public Object getOwner() {
467: return owner;
468: }
469:
470: public void makeTransient() {
471: owner = null;
472: stateManager = null;
473: }
474:
475: public void makeDirty() {
476: if (stateManager != null) {
477: stateManager.makeDirty(owner, fmd.getManagedFieldNo());
478: }
479: }
480:
481: public void reset() {
482: beenReset = true;
483: originalData = toArray();
484: }
485:
486: public void manyToManyAdd(Object o) {
487: super .add(o);
488: makeDirty();
489: }
490:
491: public void manyToManyRemove(Object o) {
492: if (super .removeElement(o)) {
493: makeDirty();
494: }
495: }
496:
497: /**
498: * Is the collection ordered.
499: */
500: public boolean isOrdered() {
501: return fmd.isOrdered();
502: }
503:
504: /**
505: * Put references to all the values into collectionData. If the
506: * values are PC instances then the instances themselves or their
507: * OIDs may be stored in collectionData.
508: */
509: public CollectionData fillCollectionData(
510: CollectionData collectionData) {
511: int size = size();
512: collectionData.valueCount = size;
513: Object[] newData;
514: Object[] values = collectionData.values;
515: if (values == null || values.length < size) {
516: newData = new Object[size];
517: } else {
518: newData = values;
519: }
520: for (int i = 0; i < size; i++) {
521: newData[i] = get(i);
522: }
523: collectionData.values = newData;
524: return collectionData;
525: }
526: }
|