001: /**********************************************************************
002: Copyright (c) 2007 Andy Jefferson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015: Contributors:
016: ...
017: **********************************************************************/package org.jpox.sco.simple;
018:
019: import java.io.ObjectStreamException;
020: import java.util.Collection;
021: import java.util.Enumeration;
022: import java.util.Iterator;
023: import java.util.ListIterator;
024:
025: import org.jpox.StateManager;
026: import org.jpox.metadata.AbstractMemberMetaData;
027: import org.jpox.sco.SCOList;
028: import org.jpox.sco.SCOListIterator;
029: import org.jpox.sco.SCOUtils;
030: import org.jpox.sco.exceptions.NullsNotAllowedException;
031: import org.jpox.state.FetchPlanState;
032: import org.jpox.util.JPOXLogger;
033: import org.jpox.util.Localiser;
034: import org.jpox.util.StringUtils;
035:
036: /**
037: * A mutable second-class Vector object.
038: * This is the simplified form that intercepts mutators and marks the field as dirty.
039: *
040: * @version $Revision: 1.3 $
041: */
042: public class Vector extends java.util.Vector implements SCOList,
043: Cloneable {
044: protected static final Localiser LOCALISER = Localiser
045: .getInstance("org.jpox.Localisation");
046:
047: protected transient Object owner;
048: protected transient StateManager ownerSM;
049: protected transient String fieldName;
050: protected transient int fieldNumber;
051: protected transient boolean allowNulls;
052:
053: /** The internal "delegate". */
054: protected java.util.Vector delegate;
055:
056: /**
057: * Constructor, using the StateManager of the "owner" and the field name.
058: * @param ownerSM The owner StateManager
059: * @param fieldName The name of the field of the SCO.
060: **/
061: public Vector(StateManager ownerSM, String fieldName) {
062: this .ownerSM = ownerSM;
063: this .fieldName = fieldName;
064: this .allowNulls = false;
065: if (ownerSM != null) {
066: AbstractMemberMetaData fmd = ownerSM.getClassMetaData()
067: .getMetaDataForMember(fieldName);
068: owner = ownerSM.getObject();
069: fieldNumber = fmd.getAbsoluteFieldNumber();
070: allowNulls = SCOUtils
071: .allowNullsInContainer(allowNulls, fmd);
072: }
073: }
074:
075: /**
076: * Method to initialise the SCO from an existing value.
077: * @param o The object to set from
078: * @param forInsert Whether the object needs inserting in the datastore with this value
079: * @param forUpdate Whether to update the datastore with this value
080: */
081: public void initialise(Object o, boolean forInsert,
082: boolean forUpdate) {
083: Collection c = (Collection) o;
084: if (c != null) {
085: delegate = new java.util.Vector(c); // Make copy of container rather than using same memory
086: } else {
087: delegate = new java.util.Vector();
088: }
089: if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
090: JPOXLogger.PERSISTENCE.debug(LOCALISER.msg("023003",
091: StringUtils.toJVMIDString(ownerSM.getObject()),
092: fieldName, "" + size(), SCOUtils
093: .getSCOWrapperOptionsMessage(true, false,
094: allowNulls, false)));
095: }
096: }
097:
098: /**
099: * Method to initialise the SCO for use.
100: */
101: public void initialise() {
102: delegate = new java.util.Vector();
103: if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
104: JPOXLogger.PERSISTENCE.debug(LOCALISER.msg("023003",
105: StringUtils.toJVMIDString(ownerSM.getObject()),
106: fieldName, "" + size(), SCOUtils
107: .getSCOWrapperOptionsMessage(true, false,
108: allowNulls, false)));
109: }
110: }
111:
112: // ----------------------- Implementation of SCO methods -------------------
113:
114: /**
115: * Accessor for the unwrapped value that we are wrapping.
116: * @return The unwrapped value
117: */
118: public Object getValue() {
119: return delegate;
120: }
121:
122: /**
123: * Method to effect the load of the data in the SCO.
124: * Used when the SCO supports lazy-loading to tell it to load all now.
125: */
126: public void load() {
127: // Always loaded
128: }
129:
130: /**
131: * Method to flush the changes to the datastore when operating in queued mode.
132: * Does nothing in "direct" mode.
133: */
134: public void flush() {
135: // Never queued
136: }
137:
138: /**
139: * Method to update an embedded element in this collection.
140: * @param element The element
141: * @param fieldNumber Number of field in the element
142: * @param value New value for this field
143: */
144: public void updateEmbeddedElement(Object element, int fieldNumber,
145: Object value) {
146: // Embedded not supported so do nothing
147: }
148:
149: /**
150: * Accessor for the field name.
151: * @return The field name
152: **/
153: public String getFieldName() {
154: return fieldName;
155: }
156:
157: /**
158: * Accessor for the owner object.
159: * @return The owner object
160: **/
161: public Object getOwner() {
162: return owner;
163: }
164:
165: /**
166: * Method to unset the owner and field information.
167: **/
168: public synchronized void unsetOwner() {
169: if (ownerSM != null) {
170: owner = null;
171: ownerSM = null;
172: fieldName = null;
173: }
174: }
175:
176: /**
177: * Utility to mark the object as dirty
178: **/
179: public void makeDirty() {
180: // Although we are never really "dirty", the owning object must be
181: // marked dirty so that the proper state change occurs and its
182: // jdoPreStore() gets called properly.
183: if (ownerSM != null) {
184: ownerSM.makeDirty(fieldNumber);
185: }
186: }
187:
188: /**
189: * Method to return a detached copy of the container.
190: * Recurse sthrough the elements so that they are likewise detached.
191: * @param state State for detachment process
192: * @return The detached container
193: */
194: public Object detachCopy(FetchPlanState state) {
195: java.util.Collection detached = new java.util.Vector();
196: SCOUtils.detachCopyForCollection(ownerSM, toArray(), state,
197: detached);
198: return detached;
199: }
200:
201: /**
202: * Method to return an attached copy of the passed (detached) value. The returned attached copy
203: * is a SCO wrapper. Goes through the existing elements in the store for this owner field and
204: * removes ones no longer present, and adds new elements. All elements in the (detached)
205: * value are attached.
206: * @param value The new (collection) value
207: */
208: public void attachCopy(Object value) {
209: java.util.Collection c = (java.util.Collection) value;
210:
211: // Attach all of the elements in the new list
212: AbstractMemberMetaData fmd = ownerSM.getClassMetaData()
213: .getMetaDataForMember(fieldName);
214: boolean elementsWithoutIdentity = SCOUtils
215: .collectionHasElementsWithoutIdentity(fmd);
216:
217: java.util.List attachedElements = new java.util.ArrayList(c
218: .size());
219: SCOUtils.attachCopyForCollection(ownerSM, c.toArray(),
220: attachedElements, elementsWithoutIdentity);
221:
222: // Update the attached list with the detached elements
223: SCOUtils.updateListWithListElements(this , attachedElements);
224: }
225:
226: // ------------------ Implementation of Vector methods ---------------------
227:
228: /**
229: * Clone operator to return a copy of this object.
230: * <p>
231: * Mutable second-class Objects are required to provide a public
232: * clone method in order to allow for copying PersistenceCapable
233: * objects. In contrast to Object.clone(), this method must not throw a
234: * CloneNotSupportedException.
235: * </p>
236: * @return The cloned object
237: */
238: public Object clone() {
239: return delegate.clone();
240: }
241:
242: /**
243: * Method to return if the list contains this element.
244: * @param element The element
245: * @return Whether it is contained
246: **/
247: public boolean contains(Object element) {
248: return delegate.contains(element);
249: }
250:
251: /**
252: * Accessor for whether a collection of elements are contained here.
253: * @param c The collection of elements.
254: * @return Whether they are contained.
255: **/
256: public synchronized boolean containsAll(java.util.Collection c) {
257: return delegate.containsAll(c);
258: }
259:
260: /**
261: * Method to retrieve an element no.
262: * @param index The item to retrieve
263: * @return The element at that position.
264: **/
265: public Object elementAt(int index) {
266: return delegate.elementAt(index);
267: }
268:
269: /**
270: * Equality operator.
271: * @param o The object to compare against.
272: * @return Whether this object is the same.
273: **/
274: public synchronized boolean equals(Object o) {
275: return delegate.equals(o);
276: }
277:
278: /**
279: * Method to return the elements of the List as an Enumeration.
280: * @return The elements
281: */
282: public Enumeration elements() {
283: return delegate.elements();
284: }
285:
286: /**
287: * Method to return the first element in the Vector.
288: * @return The first element
289: */
290: public Object firstElement() {
291: return delegate.firstElement();
292: }
293:
294: /**
295: * Method to retrieve an element no.
296: * @param index The item to retrieve
297: * @return The element at that position.
298: **/
299: public Object get(int index) {
300: return delegate.get(index);
301: }
302:
303: /**
304: * Hashcode operator.
305: * @return The Hash code.
306: **/
307: public synchronized int hashCode() {
308: return delegate.hashCode();
309: }
310:
311: /**
312: * Method to the position of an element.
313: * @param element The element.
314: * @return The position.
315: **/
316: public int indexOf(Object element) {
317: return delegate.indexOf(element);
318: }
319:
320: /**
321: * Method to the position of an element.
322: * @param element The element.
323: * @param startIndex The start position
324: * @return The position.
325: **/
326: public int indexOf(Object element, int startIndex) {
327: return delegate.indexOf(element, startIndex);
328: }
329:
330: /**
331: * Accessor for whether the Vector is empty.
332: * @return Whether it is empty.
333: **/
334: public boolean isEmpty() {
335: return delegate.isEmpty();
336: }
337:
338: /**
339: * Method to retrieve an iterator for the list.
340: * @return The iterator
341: **/
342: public Iterator iterator() {
343: return new SCOListIterator(this , ownerSM, delegate, null, true,
344: -1);
345: }
346:
347: /**
348: * Method to return the last element in the Vector.
349: * @return The last element
350: */
351: public Object lastElement() {
352: return delegate.lastElement();
353: }
354:
355: /**
356: * Method to retrieve the last position of the element.
357: * @param element The element
358: * @return The last position of this element in the List.
359: **/
360: public int lastIndexOf(Object element) {
361: return delegate.lastIndexOf(element);
362: }
363:
364: /**
365: * Method to retrieve the last position of the element.
366: * @param element The element
367: * @param startIndex The start position
368: * @return The last position of this element in the List.
369: **/
370: public int lastIndexOf(Object element, int startIndex) {
371: return delegate.lastIndexOf(element, startIndex);
372: }
373:
374: /**
375: * Method to retrieve a List iterator for the list.
376: * @return The iterator
377: **/
378: public ListIterator listIterator() {
379: return new SCOListIterator(this , ownerSM, delegate, null, true,
380: -1);
381: }
382:
383: /**
384: * Method to retrieve a List iterator for the list from the index.
385: * @param index The start point
386: * @return The iterator
387: **/
388: public ListIterator listIterator(int index) {
389: return new SCOListIterator(this , ownerSM, delegate, null, true,
390: index);
391: }
392:
393: /**
394: * Accessor for the size of the Vector.
395: * @return The size.
396: **/
397: public int size() {
398: return delegate.size();
399: }
400:
401: /**
402: * Accessor for the subList of elements between from and to of the List
403: * @param from Start index (inclusive)
404: * @param to End index (exclusive)
405: * @return The subList
406: **/
407: public synchronized java.util.List subList(int from, int to) {
408: return delegate.subList(from, to);
409: }
410:
411: /**
412: * Method to return the list as an array.
413: * @return The array
414: **/
415: public synchronized Object[] toArray() {
416: return delegate.toArray();
417: }
418:
419: /**
420: * Method to return the list as an array.
421: * @param a The runtime types of the array being defined by this param
422: * @return The array
423: **/
424: public synchronized Object[] toArray(Object a[]) {
425: return delegate.toArray(a);
426: }
427:
428: /**
429: * Method to add an element to a position in the Vector.
430: * @param index The position
431: * @param element The new element
432: **/
433: public void add(int index, Object element) {
434: // Reject inappropriate elements
435: if (element == null && !allowNulls) {
436: throw new NullsNotAllowedException(ownerSM, fieldName);
437: }
438:
439: delegate.add(index, element);
440: makeDirty();
441: }
442:
443: /**
444: * Method to add an element to the Vector.
445: * @param element The new element
446: * @return Whether it was added ok.
447: **/
448: public boolean add(Object element) {
449: // Reject inappropriate elements
450: if (element == null && !allowNulls) {
451: throw new NullsNotAllowedException(ownerSM, fieldName);
452: }
453:
454: boolean success = delegate.add(element);
455: if (success) {
456: makeDirty();
457: }
458: return success;
459: }
460:
461: /**
462: * Method to add a Collection to the Vector.
463: * @param elements The collection
464: * @return Whether it was added ok.
465: **/
466: public boolean addAll(Collection elements) {
467: boolean success = delegate.addAll(elements);
468: if (success) {
469: makeDirty();
470: }
471: return success;
472: }
473:
474: /**
475: * Method to add a Collection to a position in the Vector.
476: * @param index Position to insert the collection.
477: * @param elements The collection
478: * @return Whether it was added ok.
479: **/
480: public boolean addAll(int index, Collection elements) {
481: boolean success = delegate.addAll(index, elements);
482: if (success) {
483: makeDirty();
484: }
485: return success;
486: }
487:
488: /**
489: * Method to add an element to the Vector.
490: * @param element The new element
491: **/
492: public void addElement(Object element) {
493: delegate.addElement(element);
494: makeDirty();
495: }
496:
497: /**
498: * Method to clear the Vector.
499: **/
500: public synchronized void clear() {
501: delegate.clear();
502: makeDirty();
503: }
504:
505: /**
506: * Method to remove an element from the List
507: * @param element The Element to remove
508: * @return Whether it was removed successfully.
509: **/
510: public synchronized boolean remove(Object element) {
511: return remove(element, true);
512: }
513:
514: /**
515: * Method to remove an element from the List
516: * @param element The Element to remove
517: * @return Whether it was removed successfully.
518: **/
519: public synchronized boolean remove(Object element,
520: boolean allowCascadeDelete) {
521: boolean success = delegate.remove(element);
522: if (success) {
523: makeDirty();
524: }
525: return success;
526: }
527:
528: /**
529: * Method to remove an element from the Vector.
530: * @param index The element position.
531: * @return The object that was removed
532: **/
533: public Object remove(int index) {
534: Object obj = delegate.remove(index);
535: makeDirty();
536: return obj;
537: }
538:
539: /**
540: * Method to remove a Collection of elements from the Vector.
541: * @param elements The collection
542: * @return Whether it was removed ok.
543: */
544: public boolean removeAll(Collection elements) {
545: boolean success = delegate.removeAll(elements);
546: if (success) {
547: makeDirty();
548: }
549: return success;
550: }
551:
552: /**
553: * Method to remove an element from the Vector.
554: * @param element The element
555: * @return Whether the element was removed
556: **/
557: public boolean removeElement(Object element) {
558: boolean success = delegate.removeElement(element);
559: if (success) {
560: makeDirty();
561: }
562: return success;
563: }
564:
565: /**
566: * Method to remove an element from the Vector.
567: * @param index The element position.
568: **/
569: public void removeElementAt(int index) {
570: delegate.removeElementAt(index);
571: makeDirty();
572: }
573:
574: /**
575: * Method to remove all elements from the Vector.
576: **/
577: public void removeAllElements() {
578: clear();
579: }
580:
581: /**
582: * Method to retain a Collection of elements (and remove all others).
583: * @param c The collection to retain
584: * @return Whether they were retained successfully.
585: **/
586: public synchronized boolean retainAll(java.util.Collection c) {
587: boolean success = delegate.retainAll(c);
588: if (success) {
589: makeDirty();
590: }
591: return success;
592: }
593:
594: /**
595: * JPOX wrapper addition that allows turning off of the dependent-field checks
596: * when doing the position setting. This means that we can prevent the deletion of
597: * the object that was previously in that position. This particular feature is used
598: * when attaching a list field and where some elements have changed positions.
599: * @param index The position
600: * @param element The new element
601: * @return The element previously at that position
602: */
603: public Object set(int index, Object element,
604: boolean allowDependentField) {
605: // Reject inappropriate elements
606: if (element == null && !allowNulls) {
607: throw new NullsNotAllowedException(ownerSM, fieldName);
608: }
609:
610: Object obj = delegate.set(index, element);
611: makeDirty();
612: return obj;
613: }
614:
615: /**
616: * Method to set the element at a position in the Vector.
617: * @param index The position
618: * @param element The new element
619: * @return The element previously at that position
620: **/
621: public Object set(int index, Object element) {
622: return set(index, element, true);
623: }
624:
625: /**
626: * Method to set the element at a position in the Vector.
627: * @param element The new element
628: * @param index The position
629: **/
630: public void setElementAt(Object element, int index) {
631: // This is a historical wrapper to the Collection method
632: set(index, element);
633: }
634:
635: /**
636: * The writeReplace method is called when ObjectOutputStream is preparing
637: * to write the object to the stream. The ObjectOutputStream checks whether
638: * the class defines the writeReplace method. If the method is defined, the
639: * writeReplace method is called to allow the object to designate its
640: * replacement in the stream. The object returned should be either of the
641: * same type as the object passed in or an object that when read and
642: * resolved will result in an object of a type that is compatible with
643: * all references to the object.
644: *
645: * @return the replaced object
646: * @throws ObjectStreamException
647: */
648: protected Object writeReplace() throws ObjectStreamException {
649: return new java.util.Vector(delegate);
650: }
651: }
|