0001: /**********************************************************************
0002: Copyright (c) 2003 Andy Jefferson and others. All rights reserved.
0003: Licensed under the Apache License, Version 2.0 (the "License");
0004: you may not use this file except in compliance with the License.
0005: You may obtain a copy of the License at
0006:
0007: http://www.apache.org/licenses/LICENSE-2.0
0008:
0009: Unless required by applicable law or agreed to in writing, software
0010: distributed under the License is distributed on an "AS IS" BASIS,
0011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012: See the License for the specific language governing permissions and
0013: limitations under the License.
0014:
0015: Contributors:
0016: ...
0017: **********************************************************************/package org.jpox.sco;
0018:
0019: import java.io.ObjectStreamException;
0020: import java.util.Collection;
0021: import java.util.Iterator;
0022: import java.util.ListIterator;
0023:
0024: import org.jpox.ClassLoaderResolver;
0025: import org.jpox.ObjectManager;
0026: import org.jpox.StateManager;
0027: import org.jpox.exceptions.JPOXDataStoreException;
0028: import org.jpox.metadata.AbstractMemberMetaData;
0029: import org.jpox.metadata.FieldPersistenceModifier;
0030: import org.jpox.sco.exceptions.IncompatibleFieldTypeException;
0031: import org.jpox.sco.exceptions.NullsNotAllowedException;
0032: import org.jpox.sco.exceptions.QueryUnownedSCOException;
0033: import org.jpox.sco.queued.AddAtOperation;
0034: import org.jpox.sco.queued.AddOperation;
0035: import org.jpox.sco.queued.ClearOperation;
0036: import org.jpox.sco.queued.QueuedOperation;
0037: import org.jpox.sco.queued.RemoveAtOperation;
0038: import org.jpox.sco.queued.RemoveOperation;
0039: import org.jpox.sco.queued.SetOperation;
0040: import org.jpox.state.FetchPlanState;
0041: import org.jpox.state.StateManagerFactory;
0042: import org.jpox.store.DatastoreClass;
0043: import org.jpox.store.DatastoreIdentifier;
0044: import org.jpox.store.expression.QueryExpression;
0045: import org.jpox.store.mapping.CollectionMapping;
0046: import org.jpox.store.mapping.JavaTypeMapping;
0047: import org.jpox.store.query.Queryable;
0048: import org.jpox.store.query.ResultObjectFactory;
0049: import org.jpox.store.scostore.ListStore;
0050: import org.jpox.util.JPOXLogger;
0051: import org.jpox.util.Localiser;
0052: import org.jpox.util.StringUtils;
0053:
0054: /**
0055: * A mutable second-class Stack object.
0056: * This class extends Stack, using that class to contain the current objects, and the backing ListStore
0057: * to be the interface to the datastore. A "backing store" is not present for datastores that dont use
0058: * DatastoreClass, or if the container is serialised or non-persistent.
0059: *
0060: * <H3>Modes of Operation</H3>
0061: * The user can operate the list in 2 modes.
0062: * The <B>cached</B> mode will use an internal cache of the elements (in the "delegate") reading them at
0063: * the first opportunity and then using the cache thereafter.
0064: * The <B>non-cached</B> mode will just go direct to the "backing store" each call.
0065: *
0066: * <H3>Mutators</H3>
0067: * When the "backing store" is present any updates are passed direct to the datastore as well as to the "delegate".
0068: * If the "backing store" isn't present the changes are made to the "delegate" only.
0069: *
0070: * <H3>Accessors</H3>
0071: * When any accessor method is invoked, it typically checks whether the container has been loaded from its
0072: * "backing store" (where present) and does this as necessary. Some methods (<B>size()</B>) just check if
0073: * everything is loaded and use the delegate if possible, otherwise going direct to the datastore.
0074: * </P>
0075: *
0076: * @version $Revision: 1.93 $
0077: */
0078: public class Stack extends java.util.Stack implements SCOList,
0079: Cloneable, Queryable {
0080: protected static final Localiser LOCALISER = Localiser
0081: .getInstance("org.jpox.Localisation");
0082:
0083: private transient Object owner;
0084: private transient StateManager ownerSM;
0085: private transient String fieldName;
0086: private transient int fieldNumber;
0087: private transient ListStore backingStore;
0088: private transient Class elementType;
0089: private transient boolean allowNulls;
0090:
0091: /** The internal "delegate". */
0092: private java.util.Stack delegate;
0093:
0094: /** Whether to use "delegate" caching. */
0095: protected boolean useCache = true;
0096:
0097: /** Status flag whether the collection is loaded into the cache. */
0098: protected boolean isCacheLoaded = false;
0099:
0100: /** Whether the SCO is in "direct" or "queued" mode. */
0101: boolean queued = false;
0102:
0103: /** Queued operations when using "queued" mode. */
0104: private java.util.ArrayList queuedOperations = null;
0105:
0106: /**
0107: * Constructor, using the StateManager of the "owner" and the field name.
0108: * @param ownerSM The owner StateManager
0109: * @param fieldName The name of the field of the SCO.
0110: **/
0111: public Stack(StateManager ownerSM, String fieldName) {
0112: this .ownerSM = ownerSM;
0113: this .fieldName = fieldName;
0114: this .allowNulls = false;
0115:
0116: // Set up our delegate
0117: this .delegate = new java.util.Stack();
0118:
0119: if (ownerSM != null) {
0120: AbstractMemberMetaData fmd = ownerSM.getClassMetaData()
0121: .getMetaDataForMember(fieldName);
0122: owner = ownerSM.getObject();
0123: fieldNumber = fmd.getAbsoluteFieldNumber();
0124: allowNulls = SCOUtils
0125: .allowNullsInContainer(allowNulls, fmd);
0126: if (ownerSM.getStoreManager().usesDatastoreClass()) {
0127: queued = SCOUtils.useContainerQueueing(ownerSM);
0128: useCache = SCOUtils.useContainerCache(ownerSM,
0129: fieldName);
0130: }
0131:
0132: if (ownerSM.getStoreManager().usesDatastoreClass()
0133: && !SCOUtils.collectionHasSerialisedElements(fmd)
0134: && fmd.getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT) {
0135: ClassLoaderResolver clr = ownerSM.getObjectManager()
0136: .getClassLoaderResolver();
0137: DatastoreClass ownerTable = ownerSM.getStoreManager()
0138: .getDatastoreClass(owner.getClass().getName(),
0139: clr);
0140: JavaTypeMapping m = ownerTable.getFieldMapping(fmd);
0141: if (!(m instanceof CollectionMapping)) {
0142: throw new IncompatibleFieldTypeException(ownerSM,
0143: fieldName, java.util.Stack.class.getName(),
0144: fmd.getTypeName());
0145: }
0146:
0147: this .backingStore = (ListStore) ownerSM
0148: .getStoreManager().getStore(clr, fmd,
0149: java.util.Stack.class);
0150: this .elementType = clr.classForName(backingStore
0151: .getElementType());
0152: }
0153:
0154: if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
0155: JPOXLogger.PERSISTENCE.debug(SCOUtils
0156: .getContainerInfoMessage(ownerSM, fieldName,
0157: this , useCache, queued, allowNulls,
0158: SCOUtils.useCachedLazyLoading(ownerSM,
0159: fieldName)));
0160: }
0161: }
0162: }
0163:
0164: /**
0165: * Method to initialise the SCO from an existing value.
0166: * @param o The object to set from
0167: * @param forInsert Whether the object needs inserting in the datastore with this value
0168: * @param forUpdate Whether to update the datastore with this value
0169: */
0170: public void initialise(Object o, boolean forInsert,
0171: boolean forUpdate) {
0172: Collection c = (Collection) o;
0173: if (c != null) {
0174: // Check for the case of serialised PC elements, and assign StateManagers to the elements without
0175: AbstractMemberMetaData fmd = ownerSM.getClassMetaData()
0176: .getMetaDataForMember(fieldName);
0177: if (SCOUtils.collectionHasSerialisedElements(fmd)
0178: && fmd.getCollection().getElementClassMetaData() != null) {
0179: ObjectManager om = ownerSM.getObjectManager();
0180: Iterator iter = c.iterator();
0181: while (iter.hasNext()) {
0182: Object pc = iter.next();
0183: StateManager objSM = om.findStateManager(pc);
0184: if (objSM == null) {
0185: objSM = StateManagerFactory
0186: .newStateManagerForEmbedded(om, pc,
0187: false);
0188: objSM.addEmbeddedOwner(ownerSM, fieldNumber);
0189: }
0190: }
0191: }
0192:
0193: if (backingStore != null && useCache && !isCacheLoaded) {
0194: // Mark as loaded
0195: isCacheLoaded = true;
0196: }
0197:
0198: if (forInsert) {
0199: if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
0200: JPOXLogger.PERSISTENCE.debug(LOCALISER.msg(
0201: "023007", StringUtils.toJVMIDString(ownerSM
0202: .getObject()), fieldName, ""
0203: + c.size()));
0204: }
0205: addAll(c);
0206: } else if (forUpdate) {
0207: if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
0208: JPOXLogger.PERSISTENCE.debug(LOCALISER.msg(
0209: "023008", StringUtils.toJVMIDString(ownerSM
0210: .getObject()), fieldName, ""
0211: + c.size()));
0212: }
0213: clear();
0214: addAll(c);
0215: } else {
0216: if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
0217: JPOXLogger.PERSISTENCE.debug(LOCALISER.msg(
0218: "023007", StringUtils.toJVMIDString(ownerSM
0219: .getObject()), fieldName, ""
0220: + c.size()));
0221: }
0222: delegate.clear();
0223: delegate.addAll(c);
0224: }
0225: }
0226: }
0227:
0228: /**
0229: * Method to initialise the SCO for use.
0230: */
0231: public void initialise() {
0232: if (useCache
0233: && !SCOUtils.useCachedLazyLoading(ownerSM, fieldName)) {
0234: // Load up the container now if not using lazy loading
0235: loadFromStore();
0236: }
0237: }
0238:
0239: // ----------------------- Implementation of SCO methods -------------------
0240:
0241: /**
0242: * Accessor for the unwrapped value that we are wrapping.
0243: * @return The unwrapped value
0244: */
0245: public Object getValue() {
0246: // TODO Cater for delegate not being used
0247: return delegate;
0248: }
0249:
0250: /**
0251: * Accessor for the element type.
0252: * @return the element type contained in the collection
0253: */
0254: public Class getElementType() {
0255: return elementType;
0256: }
0257:
0258: /**
0259: * Method to effect the load of the data in the SCO.
0260: * Used when the SCO supports lazy-loading to tell it to load all now.
0261: */
0262: public void load() {
0263: if (useCache) {
0264: loadFromStore();
0265: }
0266: }
0267:
0268: /**
0269: * Method to load all elements from the "backing store" where appropriate.
0270: */
0271: protected void loadFromStore() {
0272: if (backingStore != null && !isCacheLoaded) {
0273: if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
0274: JPOXLogger.PERSISTENCE.debug(LOCALISER.msg("023006",
0275: StringUtils.toJVMIDString(ownerSM.getObject()),
0276: fieldName));
0277: }
0278: delegate.clear();
0279: Iterator iter = backingStore.iterator(ownerSM);
0280: while (iter.hasNext()) {
0281: delegate.add(iter.next());
0282: }
0283:
0284: isCacheLoaded = true;
0285: }
0286: }
0287:
0288: /**
0289: * Method to flush the changes to the datastore when operating in queued mode.
0290: * Does nothing in "direct" mode.
0291: */
0292: public void flush() {
0293: if (queued) {
0294: if (queuedOperations != null) {
0295: if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
0296: JPOXLogger.PERSISTENCE.debug(LOCALISER.msg(
0297: "023005", StringUtils.toJVMIDString(ownerSM
0298: .getObject()), fieldName));
0299: }
0300: Iterator iter = queuedOperations.iterator();
0301: while (iter.hasNext()) {
0302: QueuedOperation op = (QueuedOperation) iter.next();
0303: op.perform(backingStore, ownerSM);
0304: }
0305:
0306: queuedOperations.clear();
0307: queuedOperations = null;
0308: }
0309: }
0310: }
0311:
0312: /**
0313: * Convenience method to add a queued operation to the operations we perform at commit.
0314: * @param op The operation
0315: */
0316: protected void addQueuedOperation(QueuedOperation op) {
0317: if (queuedOperations == null) {
0318: queuedOperations = new java.util.ArrayList();
0319: }
0320: queuedOperations.add(op);
0321: }
0322:
0323: /**
0324: * Method to update an embedded element in this collection.
0325: * @param element The element
0326: * @param fieldNumber Number of field in the element
0327: * @param value New value for this field
0328: */
0329: public void updateEmbeddedElement(Object element, int fieldNumber,
0330: Object value) {
0331: if (backingStore != null) {
0332: backingStore.updateEmbeddedElement(ownerSM, element,
0333: fieldNumber, value);
0334: }
0335: }
0336:
0337: /**
0338: * Accessor for the field name.
0339: * @return The field name
0340: **/
0341: public String getFieldName() {
0342: return fieldName;
0343: }
0344:
0345: /**
0346: * Accessor for the owner object.
0347: * @return The owner object
0348: **/
0349: public Object getOwner() {
0350: return owner;
0351: }
0352:
0353: /**
0354: * Method to unset the owner and field information.
0355: **/
0356: public synchronized void unsetOwner() {
0357: if (ownerSM != null) {
0358: owner = null;
0359: ownerSM = null;
0360: fieldName = null;
0361: backingStore = null;
0362: }
0363: }
0364:
0365: /**
0366: * Utility to mark the object as dirty
0367: **/
0368: public void makeDirty() {
0369: // Although we are never really "dirty", the owning object must be
0370: // marked dirty so that the proper state change occurs and its
0371: // jdoPreStore() gets called properly.
0372: if (ownerSM != null) {
0373: ownerSM.getObjectManager().getApiAdapter().makeFieldDirty(
0374: owner, fieldName);
0375: }
0376: }
0377:
0378: /**
0379: * Method to return a detached copy of the container.
0380: * Recurse sthrough the elements so that they are likewise detached.
0381: * @param state State of detachment state
0382: * @return The detached container
0383: */
0384: public Object detachCopy(FetchPlanState state) {
0385: java.util.Collection detached = new java.util.Stack();
0386: SCOUtils.detachCopyForCollection(ownerSM, toArray(), state,
0387: detached);
0388: return detached;
0389: }
0390:
0391: /**
0392: * Method to return an attached copy of the passed (detached) value. The returned attached copy
0393: * is a SCO wrapper. Goes through the existing elements in the store for this owner field and
0394: * removes ones no longer present, and adds new elements. All elements in the (detached)
0395: * value are attached.
0396: * @param value The new (collection) value
0397: */
0398: public void attachCopy(Object value) {
0399: java.util.Collection c = (java.util.Collection) value;
0400:
0401: // Attach all of the elements in the new list
0402: AbstractMemberMetaData fmd = ownerSM.getClassMetaData()
0403: .getMetaDataForMember(fieldName);
0404: boolean elementsWithoutIdentity = SCOUtils
0405: .collectionHasElementsWithoutIdentity(fmd);
0406:
0407: java.util.List attachedElements = new java.util.ArrayList(c
0408: .size());
0409: SCOUtils.attachCopyForCollection(ownerSM, c.toArray(),
0410: attachedElements, elementsWithoutIdentity);
0411:
0412: // Update the attached list with the detached elements
0413: SCOUtils.updateListWithListElements(this , attachedElements);
0414: }
0415:
0416: // ------------------------ Query Statement methods ------------------------
0417:
0418: /**
0419: * Method to generate a QueryStatement for the SCO.
0420: * @return The QueryStatement
0421: */
0422: public synchronized QueryExpression newQueryStatement() {
0423: return newQueryStatement(elementType, null);
0424: }
0425:
0426: /**
0427: * Method to return a QueryStatement, using the specified candidate class.
0428: * @param candidateClass the candidate class
0429: * @param candidateAlias Alias for the candidate
0430: * @return The QueryStatement
0431: */
0432: public synchronized QueryExpression newQueryStatement(
0433: Class candidateClass, DatastoreIdentifier candidateAlias) {
0434: if (backingStore == null) {
0435: throw new QueryUnownedSCOException();
0436: }
0437:
0438: return backingStore.newQueryStatement(ownerSM, candidateClass
0439: .getName(), candidateAlias);
0440: }
0441:
0442: /**
0443: * Method to return a ResultObjectFactory for the SCO.
0444: * @param stmt The QueryStatement
0445: * @param ignoreCache Whether to ignore the cache
0446: * @param resultClass Whether to create objects of a particular class
0447: * @param useFetchPlan whether to use the fetch plan to retrieve fields in the same query
0448: * @return The ResultObjectFactory
0449: **/
0450: public synchronized ResultObjectFactory newResultObjectFactory(
0451: QueryExpression stmt, boolean ignoreCache,
0452: Class resultClass, boolean useFetchPlan) {
0453: if (backingStore == null) {
0454: throw new QueryUnownedSCOException();
0455: }
0456:
0457: return backingStore.newResultObjectFactory(ownerSM, stmt,
0458: ignoreCache, useFetchPlan);
0459: }
0460:
0461: // ------------------- Implementation of Stack methods ---------------------
0462:
0463: /**
0464: * Clone operator to return a copy of this object.
0465: * <p>
0466: * Mutable second-class Objects are required to provide a public
0467: * clone method in order to allow for copying PersistenceCapable
0468: * objects. In contrast to Object.clone(), this method must not throw a
0469: * CloneNotSupportedException.
0470: * </p>
0471: *
0472: * @return The cloned object
0473: */
0474: public Object clone() {
0475: if (useCache) {
0476: loadFromStore();
0477: }
0478:
0479: return delegate.clone();
0480: }
0481:
0482: /**
0483: * Method to return if the list contains this element.
0484: * @param element The element
0485: * @return Whether it is contained
0486: **/
0487: public boolean contains(Object element) {
0488: if (useCache && isCacheLoaded) {
0489: // If the "delegate" is already loaded, use it
0490: return delegate.contains(element);
0491: } else if (backingStore != null) {
0492: return backingStore.contains(ownerSM, element);
0493: }
0494:
0495: return delegate.contains(element);
0496: }
0497:
0498: /**
0499: * Accessor for whether the Stack is empty.
0500: * @return Whether it is empty.
0501: **/
0502: public boolean empty() {
0503: return isEmpty();
0504: }
0505:
0506: /**
0507: * Equality operator.
0508: * @param o The object to compare against.
0509: * @return Whether this object is the same.
0510: **/
0511: public synchronized boolean equals(Object o) {
0512: if (useCache) {
0513: loadFromStore();
0514: }
0515:
0516: if (o == this ) {
0517: return true;
0518: }
0519:
0520: if (!(o instanceof java.util.List)) {
0521: return false;
0522: }
0523: java.util.List l = (java.util.List) o;
0524: if (l.size() != size()) {
0525: return false;
0526: }
0527: Object[] elements = toArray();
0528: Object[] otherElements = l.toArray();
0529: for (int i = 0; i < elements.length; i++) {
0530: if (!elements[i].equals(otherElements[i])) {
0531: return false;
0532: }
0533: }
0534: return true;
0535: }
0536:
0537: /**
0538: * Method to retrieve an element no.
0539: * @param index The item to retrieve
0540: * @return The element at that position.
0541: **/
0542: public Object get(int index) {
0543: if (useCache) {
0544: loadFromStore();
0545: } else if (backingStore != null) {
0546: return backingStore.get(ownerSM, index);
0547: }
0548:
0549: return delegate.get(index);
0550: }
0551:
0552: /**
0553: * Method to the position of an element.
0554: * @param element The element.
0555: * @return The position.
0556: **/
0557: public int indexOf(Object element) {
0558: if (useCache) {
0559: loadFromStore();
0560: } else if (backingStore != null) {
0561: return backingStore.indexOf(ownerSM, element);
0562: }
0563:
0564: return delegate.indexOf(element);
0565: }
0566:
0567: /**
0568: * Accessor for whether the Stack is empty.
0569: * @return Whether it is empty.
0570: **/
0571: public boolean isEmpty() {
0572: return size() == 0;
0573: }
0574:
0575: /**
0576: * Method to retrieve an iterator for the list.
0577: * @return The iterator
0578: **/
0579: public Iterator iterator() {
0580: // Populate the cache if necessary
0581: if (useCache) {
0582: loadFromStore();
0583: }
0584:
0585: return new SCOListIterator(this , ownerSM, delegate,
0586: backingStore, useCache, -1);
0587: }
0588:
0589: /**
0590: * Method to retrieve a List iterator for the list.
0591: * @return The iterator
0592: **/
0593: public ListIterator listIterator() {
0594: // Populate the cache if necessary
0595: if (useCache) {
0596: loadFromStore();
0597: }
0598:
0599: return new SCOListIterator(this , ownerSM, delegate,
0600: backingStore, useCache, -1);
0601: }
0602:
0603: /**
0604: * Method to retrieve a List iterator for the list from the index.
0605: * @param index The start point
0606: * @return The iterator
0607: **/
0608: public ListIterator listIterator(int index) {
0609: // Populate the cache if necessary
0610: if (useCache) {
0611: loadFromStore();
0612: }
0613:
0614: return new SCOListIterator(this , ownerSM, delegate,
0615: backingStore, useCache, index);
0616: }
0617:
0618: /**
0619: * Method to retrieve the last position of the element.
0620: * @param element The element
0621: * @return The last position of this element in the List.
0622: **/
0623: public int lastIndexOf(Object element) {
0624: if (useCache) {
0625: loadFromStore();
0626: } else if (backingStore != null) {
0627: return backingStore.lastIndexOf(ownerSM, element);
0628: }
0629:
0630: return delegate.lastIndexOf(element);
0631: }
0632:
0633: /**
0634: * Method to retrieve the element at the top of the stack.
0635: *
0636: * @return The element at the top of the stack
0637: **/
0638: public Object peek() {
0639: return get(0);
0640: }
0641:
0642: /**
0643: * Accessor for the size of the Stack.
0644: * @return The size.
0645: **/
0646: public int size() {
0647: if (useCache && isCacheLoaded) {
0648: // If the "delegate" is already loaded, use it
0649: return delegate.size();
0650: } else if (backingStore != null) {
0651: return backingStore.size(ownerSM);
0652: }
0653:
0654: return delegate.size();
0655: }
0656:
0657: /**
0658: * Accessor for the subList of elements between from and to of the List
0659: * @param from Start index (inclusive)
0660: * @param to End index (exclusive)
0661: * @return The subList
0662: **/
0663: public synchronized java.util.List subList(int from, int to) {
0664: if (useCache) {
0665: loadFromStore();
0666: } else if (backingStore != null) {
0667: return backingStore.subList(ownerSM, from, to);
0668: }
0669:
0670: return delegate.subList(from, to);
0671: }
0672:
0673: /**
0674: * Method to return the list as an array.
0675: * @return The array
0676: **/
0677: public synchronized Object[] toArray() {
0678: if (useCache) {
0679: loadFromStore();
0680: } else if (backingStore != null) {
0681: return SCOUtils.toArray(backingStore, ownerSM);
0682: }
0683: return delegate.toArray();
0684: }
0685:
0686: /**
0687: * Method to return the list as an array.
0688: * @param a The runtime types of the array being defined by this param
0689: * @return The array
0690: **/
0691: public synchronized Object[] toArray(Object a[]) {
0692: if (useCache) {
0693: loadFromStore();
0694: } else if (backingStore != null) {
0695: return SCOUtils.toArray(backingStore, ownerSM, a);
0696: }
0697: return delegate.toArray(a);
0698: }
0699:
0700: // ------------------------------ Mutator methods --------------------------
0701:
0702: /**
0703: * Method to add an element to a position in the Stack
0704: *
0705: * @param index The position
0706: * @param element The new element
0707: **/
0708: public void add(int index, Object element) {
0709: // Reject inappropriate elements
0710: if (element == null && !allowNulls) {
0711: throw new NullsNotAllowedException(ownerSM, fieldName);
0712: }
0713:
0714: if (useCache) {
0715: loadFromStore();
0716: }
0717:
0718: if (backingStore != null) {
0719: if (queued && !ownerSM.getObjectManager().isFlushing()) {
0720: addQueuedOperation(new AddAtOperation(index, element));
0721: } else {
0722: try {
0723: backingStore.add(ownerSM, element, index,
0724: (useCache ? delegate.size() : -1));
0725: } catch (JPOXDataStoreException dse) {
0726: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("023013",
0727: "add", fieldName, dse));
0728: }
0729: }
0730: }
0731:
0732: // Only make it dirty after adding the element(s) to the datastore so we give it time
0733: // to be inserted - otherwise jdoPreStore on this object would have been called before completing the addition
0734: makeDirty();
0735:
0736: delegate.add(index, element);
0737: }
0738:
0739: /**
0740: * Method to add an element to the Stack
0741: *
0742: * @param element The new element
0743: * @return Whether it was added ok.
0744: **/
0745: public boolean add(Object element) {
0746: // Reject inappropriate elements
0747: if (element == null && !allowNulls) {
0748: throw new NullsNotAllowedException(ownerSM, fieldName);
0749: }
0750:
0751: if (useCache) {
0752: loadFromStore();
0753: }
0754:
0755: boolean backingSuccess = true;
0756: if (backingStore != null) {
0757: if (queued && !ownerSM.getObjectManager().isFlushing()) {
0758: addQueuedOperation(new AddOperation(element));
0759: } else {
0760: try {
0761: backingStore.add(ownerSM, element,
0762: (useCache ? delegate.size() : -1));
0763: } catch (JPOXDataStoreException dse) {
0764: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("023013",
0765: "add", fieldName, dse));
0766: backingSuccess = false;
0767: }
0768: }
0769: }
0770:
0771: // Only make it dirty after adding the element(s) to the datastore so we give it time
0772: // to be inserted - otherwise jdoPreStore on this object would have been called before completing the addition
0773: makeDirty();
0774:
0775: boolean delegateSuccess = delegate.add(element);
0776: return (backingStore != null ? backingSuccess : delegateSuccess);
0777: }
0778:
0779: /**
0780: * Method to add an element to the Stack
0781: *
0782: * @param element The new element
0783: **/
0784: public void addElement(Object element) {
0785: // This is a historical wrapper to the Collection method
0786: add(element);
0787: }
0788:
0789: /**
0790: * Method to add a Collection to the Stack
0791: * @param elements The collection
0792: * @return Whether it was added ok.
0793: **/
0794: public boolean addAll(Collection elements) {
0795: if (useCache) {
0796: loadFromStore();
0797: }
0798:
0799: boolean backingSuccess = true;
0800: if (backingStore != null) {
0801: if (queued && !ownerSM.getObjectManager().isFlushing()) {
0802: Iterator iter = elements.iterator();
0803: while (iter.hasNext()) {
0804: addQueuedOperation(new AddOperation(iter.next()));
0805: }
0806: } else {
0807: try {
0808: backingSuccess = backingStore
0809: .addAll(ownerSM, elements,
0810: (useCache ? delegate.size() : -1));
0811: } catch (JPOXDataStoreException dse) {
0812: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("023013",
0813: "addAll", fieldName, dse));
0814: backingSuccess = false;
0815: }
0816: }
0817: }
0818:
0819: // Only make it dirty after adding the element(s) to the datastore so we give it time
0820: // to be inserted - otherwise jdoPreStore on this object would have been called before completing the addition
0821: makeDirty();
0822:
0823: boolean delegateSuccess = delegate.addAll(elements);
0824: return (backingStore != null ? backingSuccess : delegateSuccess);
0825: }
0826:
0827: /**
0828: * Method to add a Collection to a position in the Stack
0829: * @param index Position to insert the collection.
0830: * @param elements The collection
0831: * @return Whether it was added ok.
0832: **/
0833: public boolean addAll(int index, Collection elements) {
0834: if (useCache) {
0835: loadFromStore();
0836: }
0837:
0838: boolean backingSuccess = true;
0839: if (backingStore != null) {
0840: if (queued && !ownerSM.getObjectManager().isFlushing()) {
0841: Iterator iter = elements.iterator();
0842: while (iter.hasNext()) {
0843: addQueuedOperation(new AddOperation(iter.next()));
0844: }
0845: } else {
0846: try {
0847: backingSuccess = backingStore.addAll(ownerSM,
0848: elements, index, (useCache ? delegate
0849: .size() : -1));
0850: } catch (JPOXDataStoreException dse) {
0851: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("023013",
0852: "addAll", fieldName, dse));
0853: backingSuccess = false;
0854: }
0855: }
0856: }
0857:
0858: // Only make it dirty after adding the element(s) to the datastore so we give it time
0859: // to be inserted - otherwise jdoPreStore on this object would have been called before completing the addition
0860: makeDirty();
0861:
0862: boolean delegateSuccess = delegate.addAll(index, elements);
0863: return (backingStore != null ? backingSuccess : delegateSuccess);
0864: }
0865:
0866: /**
0867: * Method to clear the Stack
0868: **/
0869: public synchronized void clear() {
0870: makeDirty();
0871:
0872: if (backingStore != null) {
0873: if (queued && !ownerSM.getObjectManager().isFlushing()) {
0874: addQueuedOperation(new ClearOperation());
0875: } else {
0876: backingStore.clear(ownerSM);
0877: }
0878: }
0879: delegate.clear();
0880: }
0881:
0882: /**
0883: * Method to remove the top element in the stack and return it.
0884: * @return The top element that was in the Stack (now removed).
0885: **/
0886: public Object pop() {
0887: makeDirty();
0888:
0889: if (useCache) {
0890: loadFromStore();
0891: }
0892:
0893: if (backingStore != null) {
0894: if (queued && !ownerSM.getObjectManager().isFlushing()) {
0895: addQueuedOperation(new RemoveAtOperation(0));
0896: } else {
0897: backingStore.remove(ownerSM, 0, (useCache ? delegate
0898: .size() : -1));
0899: }
0900: }
0901: return delegate.remove(0);
0902: }
0903:
0904: /**
0905: * Method to push an element onto the stack and return it.
0906: *
0907: * @param element The element to push onto the stack.
0908: * @return The element that was pushed onto the Stack
0909: **/
0910: public Object push(Object element) {
0911: // Reject inappropriate elements
0912: if (element == null && !allowNulls) {
0913: throw new NullsNotAllowedException(ownerSM, fieldName);
0914: }
0915:
0916: if (useCache) {
0917: loadFromStore();
0918: }
0919:
0920: if (backingStore != null) {
0921: if (queued && !ownerSM.getObjectManager().isFlushing()) {
0922: addQueuedOperation(new AddAtOperation(0, element));
0923: } else {
0924: backingStore.add(ownerSM, element, 0,
0925: (useCache ? delegate.size() : -1));
0926: }
0927: }
0928:
0929: // Only make it dirty after adding the element(s) to the datastore so we give it time
0930: // to be inserted - otherwise jdoPreStore on this object would have been called before completing the addition
0931: makeDirty();
0932:
0933: delegate.add(0, element);
0934: return element;
0935: }
0936:
0937: /**
0938: * Method to remove an element from the Stack
0939: * @param element The element
0940: * @return Whether the element was removed
0941: */
0942: public boolean remove(Object element) {
0943: return remove(element, true);
0944: }
0945:
0946: /**
0947: * Method to remove an element from the collection, and observe the flag for whether to allow cascade delete.
0948: * @param element The element
0949: * @param allowCascadeDelete Whether to allow cascade delete
0950: */
0951: public boolean remove(Object element, boolean allowCascadeDelete) {
0952: makeDirty();
0953:
0954: if (useCache) {
0955: loadFromStore();
0956: }
0957:
0958: int size = (useCache ? delegate.size() : -1);
0959: boolean delegateSuccess = delegate.remove(element);
0960:
0961: boolean backingSuccess = true;
0962: if (backingStore != null) {
0963: if (queued && !ownerSM.getObjectManager().isFlushing()) {
0964: backingSuccess = contains(element);
0965: if (backingSuccess) {
0966: addQueuedOperation(new RemoveOperation(element,
0967: allowCascadeDelete));
0968: }
0969: } else {
0970: try {
0971: backingSuccess = backingStore.remove(ownerSM,
0972: element, size, allowCascadeDelete);
0973: } catch (JPOXDataStoreException dse) {
0974: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("023013",
0975: "remove", fieldName, dse));
0976: backingSuccess = false;
0977: }
0978: }
0979: }
0980:
0981: return (backingStore != null ? backingSuccess : delegateSuccess);
0982: }
0983:
0984: /**
0985: * Method to remove a Collection of objects from the Stack
0986: * @param elements The Collection
0987: * @return Whether the collection of elements were removed
0988: **/
0989: public boolean removeAll(Collection elements) {
0990: makeDirty();
0991:
0992: if (useCache) {
0993: loadFromStore();
0994: }
0995:
0996: int size = (useCache ? delegate.size() : -1);
0997: boolean delegateSuccess = delegate.removeAll(elements);
0998:
0999: boolean backingSuccess = true;
1000: if (backingStore != null) {
1001: if (queued && !ownerSM.getObjectManager().isFlushing()) {
1002: backingSuccess = false;
1003: Iterator iter = elements.iterator();
1004: while (iter.hasNext()) {
1005: Object element = iter.next();
1006: boolean contained = contains(element);
1007: if (contained) {
1008: backingSuccess = true;
1009: addQueuedOperation(new RemoveOperation(iter
1010: .next()));
1011: }
1012: }
1013: } else {
1014: try {
1015: backingSuccess = backingStore.removeAll(ownerSM,
1016: elements, size);
1017: } catch (JPOXDataStoreException dse) {
1018: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("023013",
1019: "removeAll", fieldName, dse));
1020: backingSuccess = false;
1021: }
1022: }
1023: }
1024:
1025: return (backingStore != null ? backingSuccess : delegateSuccess);
1026: }
1027:
1028: /**
1029: * Method to remove an element from the Stack
1030: * @param element The element
1031: * @return Whether the element was removed
1032: **/
1033: public boolean removeElement(Object element) {
1034: // This is a historical wrapper to the Collection method
1035: return remove(element);
1036: }
1037:
1038: /**
1039: * Method to remove an element from the Stack
1040: * @param index The element position.
1041: * @return The object that was removed
1042: **/
1043: public Object remove(int index) {
1044: makeDirty();
1045:
1046: if (useCache) {
1047: loadFromStore();
1048: }
1049:
1050: int size = (useCache ? delegate.size() : -1);
1051: Object delegateObject = delegate.remove(index);
1052:
1053: Object backingObject = null;
1054: if (backingStore != null) {
1055: if (queued && !ownerSM.getObjectManager().isFlushing()) {
1056: addQueuedOperation(new RemoveAtOperation(index));
1057: } else {
1058: try {
1059: backingObject = backingStore.remove(ownerSM, index,
1060: size);
1061: } catch (JPOXDataStoreException dse) {
1062: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("023013",
1063: "remove", fieldName, dse));
1064: backingObject = null;
1065: }
1066: }
1067: }
1068:
1069: return (backingStore != null ? backingObject : delegateObject);
1070: }
1071:
1072: /**
1073: * Method to remove an element from the Stack
1074: * @param index The element position.
1075: **/
1076: public void removeElementAt(int index) {
1077: // This is a historical wrapper to the Collection method
1078: remove(index);
1079: }
1080:
1081: /**
1082: * Method to remove all elements from the Stack.
1083: * Same as clear().
1084: **/
1085: public void removeAllElements() {
1086: clear();
1087: }
1088:
1089: /**
1090: * Method to retain a Collection of elements (and remove all others).
1091: * @param c The collection to retain
1092: * @return Whether they were retained successfully.
1093: **/
1094: public synchronized boolean retainAll(java.util.Collection c) {
1095: makeDirty();
1096:
1097: if (useCache) {
1098: loadFromStore();
1099: }
1100:
1101: boolean modified = false;
1102: Iterator iter = iterator();
1103: while (iter.hasNext()) {
1104: Object element = iter.next();
1105: if (!c.contains(element)) {
1106: iter.remove();
1107: modified = true;
1108: }
1109: }
1110: return modified;
1111: }
1112:
1113: /**
1114: * JPOX wrapper addition that allows turning off of the dependent-field checks
1115: * when doing the position setting. This means that we can prevent the deletion of
1116: * the object that was previously in that position. This particular feature is used
1117: * when attaching a list field and where some elements have changed positions.
1118: * @param index The position
1119: * @param element The new element
1120: * @return The element previously at that position
1121: */
1122: public Object set(int index, Object element,
1123: boolean allowDependentField) {
1124: // Reject inappropriate elements
1125: if (element == null && !allowNulls) {
1126: throw new NullsNotAllowedException(ownerSM, fieldName);
1127: }
1128:
1129: makeDirty();
1130:
1131: if (useCache) {
1132: loadFromStore();
1133: }
1134:
1135: if (backingStore != null) {
1136: if (queued && !ownerSM.getObjectManager().isFlushing()) {
1137: addQueuedOperation(new SetOperation(index, element,
1138: allowDependentField));
1139: } else {
1140: backingStore.set(ownerSM, index, element,
1141: allowDependentField);
1142: }
1143: }
1144: return delegate.set(index, element);
1145: }
1146:
1147: /**
1148: * Method to set the element at a position in the Stack
1149: *
1150: * @param index The position
1151: * @param element The new element
1152: * @return The element previously at that position
1153: **/
1154: public Object set(int index, Object element) {
1155: return set(index, element, true);
1156: }
1157:
1158: /**
1159: * Method to set the element at a position in the Stack
1160: *
1161: * @param element The new element
1162: * @param index The position
1163: **/
1164: public void setElementAt(Object element, int index) {
1165: // This is a historical wrapper to the Collection method
1166: set(index, element);
1167: }
1168:
1169: /**
1170: * The writeReplace method is called when ObjectOutputStream is preparing
1171: * to write the object to the stream. The ObjectOutputStream checks whether
1172: * the class defines the writeReplace method. If the method is defined, the
1173: * writeReplace method is called to allow the object to designate its
1174: * replacement in the stream. The object returned should be either of the
1175: * same type as the object passed in or an object that when read and
1176: * resolved will result in an object of a type that is compatible with all
1177: * references to the object.
1178: *
1179: * @return the replaced object
1180: * @throws ObjectStreamException
1181: */
1182: protected Object writeReplace() throws ObjectStreamException {
1183: if (useCache) {
1184: loadFromStore();
1185: java.util.Stack stack = new java.util.Stack();
1186: stack.addAll(delegate);
1187: return stack;
1188: } else {
1189: // TODO Cater for non-cached collection, load elements in a DB call.
1190: java.util.Stack stack = new java.util.Stack();
1191: stack.addAll(delegate);
1192: return stack;
1193: }
1194: }
1195: }
|