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.Iterator;
022: import java.util.ListIterator;
023:
024: import org.jpox.StateManager;
025: import org.jpox.metadata.AbstractMemberMetaData;
026: import org.jpox.sco.SCOList;
027: import org.jpox.sco.SCOListIterator;
028: import org.jpox.sco.SCOUtils;
029: import org.jpox.sco.exceptions.NullsNotAllowedException;
030: import org.jpox.state.FetchPlanState;
031: import org.jpox.util.JPOXLogger;
032: import org.jpox.util.Localiser;
033: import org.jpox.util.StringUtils;
034:
035: /**
036: * A mutable second-class Stack object.
037: * This is the simplified form that intercepts mutators and marks the field as dirty.
038: *
039: * @version $Revision: 1.3 $
040: */
041: public class Stack extends java.util.Stack implements SCOList,
042: Cloneable {
043: protected static final Localiser LOCALISER = Localiser
044: .getInstance("org.jpox.Localisation");
045:
046: protected transient Object owner;
047: protected transient StateManager ownerSM;
048: protected transient String fieldName;
049: protected transient int fieldNumber;
050: protected transient boolean allowNulls;
051:
052: /** The internal "delegate". */
053: protected java.util.Stack delegate;
054:
055: /**
056: * Constructor, using the StateManager of the "owner" and the field name.
057: * @param ownerSM The owner StateManager
058: * @param fieldName The name of the field of the SCO.
059: **/
060: public Stack(StateManager ownerSM, String fieldName) {
061: this .ownerSM = ownerSM;
062: this .fieldName = fieldName;
063: this .allowNulls = false;
064: if (ownerSM != null) {
065: AbstractMemberMetaData fmd = ownerSM.getClassMetaData()
066: .getMetaDataForMember(fieldName);
067: owner = ownerSM.getObject();
068: fieldNumber = fmd.getAbsoluteFieldNumber();
069: allowNulls = SCOUtils
070: .allowNullsInContainer(allowNulls, fmd);
071: }
072: }
073:
074: /**
075: * Method to initialise the SCO from an existing value.
076: * @param o The object to set from
077: * @param forInsert Whether the object needs inserting in the datastore with this value
078: * @param forUpdate Whether to update the datastore with this value
079: */
080: public void initialise(Object o, boolean forInsert,
081: boolean forUpdate) {
082: Collection c = (Collection) o;
083: if (c != null) {
084: delegate = new java.util.Stack(); // Make copy of container rather than using same memory
085: delegate.addAll(c);
086: } else {
087: delegate = new java.util.Stack();
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.Stack();
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 of detachment state
192: * @return The detached container
193: */
194: public Object detachCopy(FetchPlanState state) {
195: java.util.Collection detached = new java.util.Stack();
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 Stack 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: *
237: * @return The cloned object
238: */
239: public Object clone() {
240: return delegate.clone();
241: }
242:
243: /**
244: * Method to return if the list contains this element.
245: * @param element The element
246: * @return Whether it is contained
247: **/
248: public boolean contains(Object element) {
249: return delegate.contains(element);
250: }
251:
252: /**
253: * Accessor for whether the Stack is empty.
254: * @return Whether it is empty.
255: **/
256: public boolean empty() {
257: return delegate.empty();
258: }
259:
260: /**
261: * Equality operator.
262: * @param o The object to compare against.
263: * @return Whether this object is the same.
264: **/
265: public synchronized boolean equals(Object o) {
266: return delegate.equals(o);
267: }
268:
269: /**
270: * Method to retrieve an element no.
271: * @param index The item to retrieve
272: * @return The element at that position.
273: **/
274: public Object get(int index) {
275: return delegate.get(index);
276: }
277:
278: /**
279: * Method to the position of an element.
280: * @param element The element.
281: * @return The position.
282: **/
283: public int indexOf(Object element) {
284: return delegate.indexOf(element);
285: }
286:
287: /**
288: * Accessor for whether the Stack is empty.
289: * @return Whether it is empty.
290: **/
291: public boolean isEmpty() {
292: return delegate.isEmpty();
293: }
294:
295: /**
296: * Method to retrieve an iterator for the list.
297: * @return The iterator
298: **/
299: public Iterator iterator() {
300: return new SCOListIterator(this , ownerSM, delegate, null, true,
301: -1);
302: }
303:
304: /**
305: * Method to retrieve a List iterator for the list.
306: * @return The iterator
307: **/
308: public ListIterator listIterator() {
309: return new SCOListIterator(this , ownerSM, delegate, null, true,
310: -1);
311: }
312:
313: /**
314: * Method to retrieve a List iterator for the list from the index.
315: * @param index The start point
316: * @return The iterator
317: **/
318: public ListIterator listIterator(int index) {
319: return new SCOListIterator(this , ownerSM, delegate, null, true,
320: index);
321: }
322:
323: /**
324: * Method to retrieve the last position of the element.
325: * @param element The element
326: * @return The last position of this element in the List.
327: **/
328: public int lastIndexOf(Object element) {
329: return delegate.lastIndexOf(element);
330: }
331:
332: /**
333: * Method to retrieve the element at the top of the stack.
334: * @return The element at the top of the stack
335: **/
336: public Object peek() {
337: return delegate.peek();
338: }
339:
340: /**
341: * Accessor for the size of the Stack.
342: * @return The size.
343: **/
344: public int size() {
345: return delegate.size();
346: }
347:
348: /**
349: * Accessor for the subList of elements between from and to of the List
350: * @param from Start index (inclusive)
351: * @param to End index (exclusive)
352: * @return The subList
353: **/
354: public synchronized java.util.List subList(int from, int to) {
355: return delegate.subList(from, to);
356: }
357:
358: /**
359: * Method to return the list as an array.
360: * @return The array
361: **/
362: public synchronized Object[] toArray() {
363: return delegate.toArray();
364: }
365:
366: /**
367: * Method to return the list as an array.
368: * @param a The runtime types of the array being defined by this param
369: * @return The array
370: **/
371: public synchronized Object[] toArray(Object a[]) {
372: return delegate.toArray(a);
373: }
374:
375: /**
376: * Method to add an element to a position in the Stack
377: *
378: * @param index The position
379: * @param element The new element
380: **/
381: public void add(int index, Object element) {
382: // Reject inappropriate elements
383: if (element == null && !allowNulls) {
384: throw new NullsNotAllowedException(ownerSM, fieldName);
385: }
386:
387: delegate.add(index, element);
388: makeDirty();
389: }
390:
391: /**
392: * Method to add an element to the Stack
393: *
394: * @param element The new element
395: * @return Whether it was added ok.
396: **/
397: public boolean add(Object element) {
398: // Reject inappropriate elements
399: if (element == null && !allowNulls) {
400: throw new NullsNotAllowedException(ownerSM, fieldName);
401: }
402:
403: boolean success = delegate.add(element);
404: if (success) {
405: makeDirty();
406: }
407: return success;
408: }
409:
410: /**
411: * Method to add an element to the Stack
412: *
413: * @param element The new element
414: **/
415: public void addElement(Object element) {
416: // Reject inappropriate elements
417: if (element == null && !allowNulls) {
418: throw new NullsNotAllowedException(ownerSM, fieldName);
419: }
420:
421: delegate.add(element);
422: makeDirty();
423: }
424:
425: /**
426: * Method to add a Collection to the Stack
427: * @param elements The collection
428: * @return Whether it was added ok.
429: **/
430: public boolean addAll(Collection elements) {
431: boolean success = delegate.addAll(elements);
432: if (success) {
433: makeDirty();
434: }
435: return success;
436: }
437:
438: /**
439: * Method to add a Collection to a position in the Stack
440: * @param index Position to insert the collection.
441: * @param elements The collection
442: * @return Whether it was added ok.
443: **/
444: public boolean addAll(int index, Collection elements) {
445: boolean success = delegate.addAll(index, elements);
446: if (success) {
447: makeDirty();
448: }
449: return success;
450: }
451:
452: /**
453: * Method to clear the Stack
454: **/
455: public synchronized void clear() {
456: delegate.clear();
457: makeDirty();
458: }
459:
460: /**
461: * Method to remove the top element in the stack and return it.
462: * @return The top element that was in the Stack (now removed).
463: **/
464: public Object pop() {
465: Object obj = delegate.pop();
466: makeDirty();
467: return obj;
468: }
469:
470: /**
471: * Method to push an element onto the stack and return it.
472: *
473: * @param element The element to push onto the stack.
474: * @return The element that was pushed onto the Stack
475: **/
476: public Object push(Object element) {
477: // Reject inappropriate elements
478: if (element == null && !allowNulls) {
479: throw new NullsNotAllowedException(ownerSM, fieldName);
480: }
481:
482: Object obj = delegate.push(element);
483: makeDirty();
484: return obj;
485: }
486:
487: /**
488: * Method to remove an element from the List
489: * @param element The Element to remove
490: * @return Whether it was removed successfully.
491: **/
492: public synchronized boolean remove(Object element) {
493: return remove(element, true);
494: }
495:
496: /**
497: * Method to remove an element from the List
498: * @param element The Element to remove
499: * @return Whether it was removed successfully.
500: **/
501: public synchronized boolean remove(Object element,
502: boolean allowCascadeDelete) {
503: boolean success = delegate.remove(element);
504: if (success) {
505: makeDirty();
506: }
507: return success;
508: }
509:
510: /**
511: * Method to remove a Collection of objects from the Stack
512: * @param elements The Collection
513: * @return Whether the collection of elements were removed
514: **/
515: public boolean removeAll(Collection elements) {
516: boolean success = delegate.removeAll(elements);
517: if (success) {
518: makeDirty();
519: }
520: return success;
521: }
522:
523: /**
524: * Method to remove an element from the Stack
525: * @param element The element
526: * @return Whether the element was removed
527: **/
528: public boolean removeElement(Object element) {
529: boolean success = delegate.removeElement(element);
530: if (success) {
531: makeDirty();
532: }
533: return success;
534: }
535:
536: /**
537: * Method to remove an element from the Stack
538: * @param index The element position.
539: * @return The object that was removed
540: **/
541: public Object remove(int index) {
542: Object obj = delegate.remove(index);
543: makeDirty();
544: return obj;
545: }
546:
547: /**
548: * Method to remove an element from the Stack
549: * @param index The element position.
550: **/
551: public void removeElementAt(int index) {
552: delegate.removeElementAt(index);
553: makeDirty();
554: }
555:
556: /**
557: * Method to remove all elements from the Stack.
558: * Same as clear().
559: **/
560: public void removeAllElements() {
561: clear();
562: makeDirty();
563: }
564:
565: /**
566: * Method to retain a Collection of elements (and remove all others).
567: * @param c The collection to retain
568: * @return Whether they were retained successfully.
569: **/
570: public synchronized boolean retainAll(java.util.Collection c) {
571: boolean success = delegate.retainAll(c);
572: if (success) {
573: makeDirty();
574: }
575: return success;
576: }
577:
578: /**
579: * JPOX wrapper addition that allows turning off of the dependent-field checks
580: * when doing the position setting. This means that we can prevent the deletion of
581: * the object that was previously in that position. This particular feature is used
582: * when attaching a list field and where some elements have changed positions.
583: * @param index The position
584: * @param element The new element
585: * @return The element previously at that position
586: */
587: public Object set(int index, Object element,
588: boolean allowDependentField) {
589: // Reject inappropriate elements
590: if (element == null && !allowNulls) {
591: throw new NullsNotAllowedException(ownerSM, fieldName);
592: }
593:
594: Object obj = delegate.set(index, element);
595: makeDirty();
596: return obj;
597: }
598:
599: /**
600: * Method to set the element at a position in the Stack
601: *
602: * @param index The position
603: * @param element The new element
604: * @return The element previously at that position
605: **/
606: public Object set(int index, Object element) {
607: return set(index, element, true);
608: }
609:
610: /**
611: * Method to set the element at a position in the Stack
612: *
613: * @param element The new element
614: * @param index The position
615: **/
616: public void setElementAt(Object element, int index) {
617: delegate.setElementAt(element, index);
618: makeDirty();
619: }
620:
621: /**
622: * The writeReplace method is called when ObjectOutputStream is preparing
623: * to write the object to the stream. The ObjectOutputStream checks whether
624: * the class defines the writeReplace method. If the method is defined, the
625: * writeReplace method is called to allow the object to designate its
626: * replacement in the stream. The object returned should be either of the
627: * same type as the object passed in or an object that when read and
628: * resolved will result in an object of a type that is compatible with all
629: * references to the object.
630: *
631: * @return the replaced object
632: * @throws ObjectStreamException
633: */
634: protected Object writeReplace() throws ObjectStreamException {
635: java.util.Stack stack = new java.util.Stack();
636: stack.addAll(delegate);
637: return stack;
638: }
639: }
|