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.Comparator;
021: import java.util.Iterator;
022:
023: import org.jpox.StateManager;
024: import org.jpox.metadata.AbstractMemberMetaData;
025: import org.jpox.sco.SCOCollection;
026: import org.jpox.sco.SCOCollectionIterator;
027: import org.jpox.sco.SCOMtoN;
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 PriorityQueue 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 PriorityQueue extends java.util.PriorityQueue implements
042: SCOCollection, SCOMtoN, Cloneable, java.io.Serializable {
043: protected static final Localiser LOCALISER = Localiser.getInstance(
044: "org.jpox.Localisation", PriorityQueue.class
045: .getClassLoader());
046:
047: protected Object owner;
048: protected StateManager ownerSM;
049: protected String fieldName;
050: protected int fieldNumber;
051: protected boolean allowNulls;
052:
053: /** The internal "delegate". */
054: protected java.util.PriorityQueue delegate;
055:
056: /**
057: * Constructor.
058: * @param ownerSM The State Manager for this set.
059: * @param fieldName Name of the field
060: **/
061: public PriorityQueue(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: java.util.Collection c = (java.util.Collection) o;
084: if (c != null) {
085: initialiseDelegate();
086: delegate.addAll(c);
087: } else {
088: initialiseDelegate();
089: }
090: if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
091: JPOXLogger.PERSISTENCE.debug(LOCALISER.msg("023003",
092: StringUtils.toJVMIDString(ownerSM.getObject()),
093: fieldName, "" + size(), SCOUtils
094: .getSCOWrapperOptionsMessage(true, false,
095: allowNulls, false)));
096: }
097: }
098:
099: /**
100: * Method to initialise the SCO for use.
101: */
102: public void initialise() {
103: initialiseDelegate();
104: if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
105: JPOXLogger.PERSISTENCE.debug(LOCALISER.msg("023003",
106: StringUtils.toJVMIDString(ownerSM.getObject()),
107: fieldName, "" + size(), SCOUtils
108: .getSCOWrapperOptionsMessage(true, false,
109: allowNulls, false)));
110: }
111: }
112:
113: /**
114: * Convenience method to set up the delegate respecting any comparator specified in MetaData.
115: */
116: protected void initialiseDelegate() {
117: AbstractMemberMetaData fmd = ownerSM.getClassMetaData()
118: .getMetaDataForMember(fieldName);
119: Comparator comparator = SCOUtils.getComparator(fmd, ownerSM
120: .getObjectManager().getClassLoaderResolver());
121: if (comparator != null) {
122: this .delegate = new java.util.PriorityQueue(5, comparator);
123: } else {
124: this .delegate = new java.util.PriorityQueue();
125: }
126: }
127:
128: // ----------------------- Implementation of SCO methods -------------------
129:
130: /**
131: * Accessor for the unwrapped value that we are wrapping.
132: * @return The unwrapped value
133: */
134: public Object getValue() {
135: return delegate;
136: }
137:
138: /**
139: * Method to effect the load of the data in the SCO.
140: * Used when the SCO supports lazy-loading to tell it to load all now.
141: */
142: public void load() {
143: // Always loaded
144: }
145:
146: /**
147: * Method to flush the changes to the datastore when operating in queued mode.
148: * Does nothing in "direct" mode.
149: */
150: public void flush() {
151: // Never queued
152: }
153:
154: /**
155: * Method to update an embedded element in this collection.
156: * @param element The element
157: * @param fieldNumber Number of field in the element
158: * @param value New value for this field
159: */
160: public void updateEmbeddedElement(Object element, int fieldNumber,
161: Object value) {
162: // Embedded not supported so do nothing
163: }
164:
165: /**
166: * Accessor for the field name.
167: * @return The field name
168: */
169: public String getFieldName() {
170: return fieldName;
171: }
172:
173: /**
174: * Accessor for the owner object.
175: * @return The owner object
176: */
177: public Object getOwner() {
178: return owner;
179: }
180:
181: /**
182: * Method to unset the owner and field information.
183: */
184: public synchronized void unsetOwner() {
185: if (ownerSM != null) {
186: owner = null;
187: ownerSM = null;
188: fieldName = null;
189: }
190: }
191:
192: /**
193: * Utility to mark the object as dirty
194: **/
195: public void makeDirty() {
196: /*
197: * Although we are never really "dirty", the owning object must be
198: * marked dirty so that the proper state change occurs and its
199: * jdoPreStore() gets called properly.
200: */
201: if (ownerSM != null) {
202: ownerSM.makeDirty(fieldNumber);
203: }
204: }
205:
206: /**
207: * Method to return a detached copy of the container.
208: * Recurses through the elements so that they are likewise detached.
209: * @param state State for detachment process
210: * @return The detached container
211: */
212: public Object detachCopy(FetchPlanState state) {
213: java.util.Collection detached = new java.util.PriorityQueue();
214: SCOUtils.detachCopyForCollection(ownerSM, toArray(), state,
215: detached);
216: return detached;
217: }
218:
219: /**
220: * Method to return an attached copy of the passed (detached) value. The returned attached copy
221: * is a SCO wrapper. Goes through the existing elements in the store for this owner field and
222: * removes ones no longer present, and adds new elements. All elements in the (detached)
223: * value are attached.
224: * @param value The new (collection) value
225: */
226: public void attachCopy(Object value) {
227: java.util.Collection c = (java.util.Collection) value;
228:
229: // Attach all of the elements in the new collection
230: AbstractMemberMetaData fmd = ownerSM.getClassMetaData()
231: .getMetaDataForMember(fieldName);
232: boolean elementsWithoutIdentity = SCOUtils
233: .collectionHasElementsWithoutIdentity(fmd);
234:
235: java.util.Collection attachedElements = new java.util.HashSet(c
236: .size());
237: SCOUtils.attachCopyForCollection(ownerSM, c.toArray(),
238: attachedElements, elementsWithoutIdentity);
239:
240: // Update the attached collection with the detached elements
241: SCOUtils.updateCollectionWithCollectionElements(this ,
242: attachedElements);
243: }
244:
245: // ---------------- Implementation of Queue methods -------------------
246:
247: /**
248: * Creates and returns a copy of this object.
249: * <P>
250: * Mutable second-class Objects are required to provide a public
251: * clone method in order to allow for copying PersistenceCapable
252: * objects. In contrast to Object.clone(), this method must not throw a
253: * CloneNotSupportedException.
254: * @return A clone of the object
255: */
256: public Object clone() {
257: // return (delegate.clone();
258: // TODO Implement this since PqiorityQueue doesnt have clone method
259: return null;
260: }
261:
262: /**
263: * Accessor for the comparator.
264: * @return The comparator
265: */
266: public Comparator comparator() {
267: return delegate.comparator();
268: }
269:
270: /**
271: * Accessor for whether an element is contained in the Collection.
272: * @param element The element
273: * @return Whether the element is contained here
274: **/
275: public synchronized boolean contains(Object element) {
276: return delegate.contains(element);
277: }
278:
279: /**
280: * Accessor for whether a collection of elements are contained here.
281: * @param c The collection of elements.
282: * @return Whether they are contained.
283: **/
284: public synchronized boolean containsAll(java.util.Collection c) {
285: return delegate.containsAll(c);
286: }
287:
288: /**
289: * Equality operator.
290: * @param o The object to compare against.
291: * @return Whether this object is the same.
292: **/
293: public synchronized boolean equals(Object o) {
294: return delegate.equals(o);
295: }
296:
297: /**
298: * Hashcode operator.
299: * @return The Hash code.
300: **/
301: public synchronized int hashCode() {
302: return delegate.hashCode();
303: }
304:
305: /**
306: * Accessor for whether the Collection is empty.
307: * @return Whether it is empty.
308: **/
309: public synchronized boolean isEmpty() {
310: return delegate.isEmpty();
311: }
312:
313: /**
314: * Accessor for an iterator for the Collection.
315: * @return The iterator
316: **/
317: public synchronized Iterator iterator() {
318: return new SCOCollectionIterator(this , ownerSM, delegate, null,
319: true);
320: }
321:
322: /**
323: * Method to peek at the next element in the Queue.
324: * @return The element
325: **/
326: public synchronized Object peek() {
327: return delegate.peek();
328: }
329:
330: /**
331: * Accessor for the size of the Collection.
332: * @return The size
333: **/
334: public synchronized int size() {
335: return delegate.size();
336: }
337:
338: /**
339: * Method to return the Collection as an array.
340: * @return The array
341: **/
342: public synchronized Object[] toArray() {
343: return delegate.toArray();
344: }
345:
346: /**
347: * Method to return the Collection as an array.
348: * @param a The array to write the results to
349: * @return The array
350: **/
351: public synchronized Object[] toArray(Object a[]) {
352: return delegate.toArray(a);
353: }
354:
355: /**
356: * Method to return the Collection as a String.
357: * @return The string form
358: **/
359: public String toString() {
360: StringBuffer s = new StringBuffer("[");
361: int i = 0;
362: Iterator iter = iterator();
363: while (iter.hasNext()) {
364: if (i > 0) {
365: s.append(',');
366: }
367: s.append(iter.next());
368: i++;
369: }
370: s.append("]");
371:
372: return s.toString();
373: }
374:
375: // ----------------------------- Mutator methods ---------------------------
376:
377: /**
378: * Method to add an element to the Collection.
379: * @param element The element to add
380: * @return Whether it was added successfully.
381: **/
382: public synchronized boolean add(Object element) {
383: // Reject inappropriate elements
384: if (element == null && !allowNulls) {
385: throw new NullsNotAllowedException(ownerSM, fieldName);
386: }
387:
388: boolean success = delegate.add(element);
389: if (success) {
390: makeDirty();
391: }
392: return success;
393: }
394:
395: /**
396: * Method to add a collection of elements.
397: * @param elements The collection of elements to add.
398: * @return Whether they were added successfully.
399: **/
400: public synchronized boolean addAll(java.util.Collection elements) {
401: boolean success = delegate.addAll(elements);
402: if (success) {
403: makeDirty();
404: }
405: return success;
406: }
407:
408: /**
409: * Method to clear the Collection.
410: **/
411: public synchronized void clear() {
412: delegate.clear();
413: makeDirty();
414: }
415:
416: /**
417: * Method to offer an element to the Queue.
418: * @param element The element to offer
419: * @return Whether it was added successfully.
420: **/
421: public synchronized boolean offer(Object element) {
422: boolean success = delegate.offer(element);
423: if (success) {
424: makeDirty();
425: }
426: return success;
427: }
428:
429: /**
430: * Method to poll the next element in the Queue.
431: * @return The element (now removed)
432: **/
433: public synchronized Object poll() {
434: Object obj = delegate.poll();
435: makeDirty();
436: return obj;
437: }
438:
439: /**
440: * Method to remove an element from the List
441: * @param element The Element to remove
442: * @return Whether it was removed successfully.
443: **/
444: public synchronized boolean remove(Object element) {
445: return remove(element, true);
446: }
447:
448: /**
449: * Method to remove an element from the List
450: * @param element The Element to remove
451: * @return Whether it was removed successfully.
452: **/
453: public synchronized boolean remove(Object element,
454: boolean allowCascadeDelete) {
455: boolean success = delegate.remove(element);
456: if (success) {
457: makeDirty();
458: }
459: return success;
460: }
461:
462: /**
463: * Method to remove a Collection of elements.
464: * @param elements The collection to remove
465: * @return Whether they were removed successfully.
466: **/
467: public synchronized boolean removeAll(java.util.Collection elements) {
468: boolean success = delegate.removeAll(elements);
469: if (success) {
470: makeDirty();
471: }
472: return success;
473: }
474:
475: /**
476: * Method to retain a Collection of elements (and remove all others).
477: * @param c The collection to retain
478: * @return Whether they were retained successfully.
479: **/
480: public synchronized boolean retainAll(java.util.Collection c) {
481: boolean success = delegate.retainAll(c);
482: if (success) {
483: makeDirty();
484: }
485: return success;
486: }
487:
488: /**
489: * The writeReplace method is called when ObjectOutputStream is preparing
490: * to write the object to the stream. The ObjectOutputStream checks whether
491: * the class defines the writeReplace method. If the method is defined, the
492: * writeReplace method is called to allow the object to designate its
493: * replacement in the stream. The object returned should be either of the
494: * same type as the object passed in or an object that when read and
495: * resolved will result in an object of a type that is compatible with all
496: * references to the object.
497: * @return the replaced object
498: * @throws ObjectStreamException
499: */
500: protected Object writeReplace() throws ObjectStreamException {
501: return new java.util.PriorityQueue(delegate);
502: }
503: }
|