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