KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > queryframework > ContainerPolicy


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.queryframework;
23
24 import java.security.AccessController JavaDoc;
25 import java.security.PrivilegedActionException JavaDoc;
26 import java.util.Vector JavaDoc;
27 import java.util.Hashtable JavaDoc;
28 import java.util.Enumeration JavaDoc;
29 import java.io.Serializable JavaDoc;
30 import java.lang.reflect.Constructor JavaDoc;
31
32 import java.util.IdentityHashMap JavaDoc;
33
34 import oracle.toplink.essentials.internal.helper.Helper;
35 import oracle.toplink.essentials.internal.helper.ClassConstants;
36 import oracle.toplink.essentials.internal.helper.IdentityHashtable;
37 import oracle.toplink.essentials.internal.sessions.CollectionChangeRecord;
38 import oracle.toplink.essentials.internal.sessions.MergeManager;
39 import oracle.toplink.essentials.internal.sessions.ObjectChangeSet;
40 import oracle.toplink.essentials.internal.sessions.UnitOfWorkChangeSet;
41 import oracle.toplink.essentials.internal.sessions.CollectionChangeRecord;
42 import oracle.toplink.essentials.queryframework.*;
43 import oracle.toplink.essentials.exceptions.*;
44 import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
45 import oracle.toplink.essentials.internal.security.PrivilegedNewInstanceFromClass;
46 import oracle.toplink.essentials.internal.security.PrivilegedInvokeConstructor;
47 import oracle.toplink.essentials.internal.security.PrivilegedGetConstructorFor;
48 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
49 import oracle.toplink.essentials.internal.sessions.AbstractSession;
50 import oracle.toplink.essentials.descriptors.ClassDescriptor;
51
52 /**
53  * <p><b>Purpose</b>:
54  * Used to support collections in read queries.
55  * <p>
56  * <p><b>Responsibilities</b>:
57  * Map the results into the appropriate collection instance.
58  * Generically support special collections like cursored stream and virtual collection.
59  *
60  * @author James Sutherland
61  * @since TOPLink/Java 1.2
62  */

63 public abstract class ContainerPolicy implements Cloneable JavaDoc, Serializable JavaDoc {
64     /** The descriptor is used to wrap and unwrap objects using the wrapper policy. **/
65     protected transient ClassDescriptor elementDescriptor;
66     protected transient Constructor JavaDoc constructor;
67
68     /**
69      * Default constructor.
70      */

71     public ContainerPolicy() {
72     }
73
74     /**
75      * INTERNAL:
76      * Add element to container however that needs to be done for the type of container.
77      * Valid for some subclasses only.
78      * Return whether the container changed.
79      */

80     protected boolean addInto(Object JavaDoc key, Object JavaDoc element, Object JavaDoc container) {
81         throw QueryException.cannotAddToContainer(element, container, this);
82     }
83
84     /**
85      * INTERNAL:
86      * Add element to container.
87      * This is used to add to a collection independent of JDK 1.1 and 1.2.
88      * The session may be required to wrap for the wrapper policy.
89      * Return whether the container changed
90      */

91     public boolean addInto(Object JavaDoc element, Object JavaDoc container, AbstractSession session) {
92         return addInto(null, element, container, session);
93     }
94
95     /**
96      * INTERNAL:
97      * Add element to container.
98      * This is used to add to a collection independent of JDK 1.1 and 1.2.
99      * The session may be required to wrap for the wrapper policy.
100      * Return whether the container changed
101      */

102     public boolean addInto(Object JavaDoc key, Object JavaDoc element, Object JavaDoc container, AbstractSession session) {
103         Object JavaDoc elementToAdd = element;
104         if (hasElementDescriptor()) {
105             elementToAdd = getElementDescriptor().getObjectBuilder().wrapObject(element, session);
106         }
107         return addInto(key, elementToAdd, container);
108     }
109
110     /**
111     * INTERNAL:
112     * It is illegal to send this message to this receiver. Try one of my subclasses.
113     * Throws an exception.
114     *
115     * @see #ListContainerPolicy
116     */

117     public void addIntoWithOrder(Integer JavaDoc index, Object JavaDoc element, Object JavaDoc container) {
118         throw QueryException.methodDoesNotExistInContainerClass("set", getContainerClass());
119     }
120
121     /**
122     * INTERNAL:
123     * It is illegal to send this message to this receiver. Try one of my subclasses.
124     * Throws an exception.
125     *
126     * @see #ListContainerPolicy
127     */

128     public void addIntoWithOrder(Integer JavaDoc index, Object JavaDoc element, Object JavaDoc container, AbstractSession session) {
129         Object JavaDoc elementToAdd = element;
130         if (hasElementDescriptor()) {
131             elementToAdd = getElementDescriptor().getObjectBuilder().wrapObject(element, session);
132         }
133         addIntoWithOrder(index, elementToAdd, container);
134     }
135
136     /**
137     * INTERNAL:
138     * It is illegal to send this message to this receiver. Try one of my subclasses.
139     * Throws an exception.
140     *
141     * @see #ListContainerPolicy
142     */

143     public void addIntoWithOrder(Vector JavaDoc indexes, Hashtable JavaDoc elements, Object JavaDoc container, AbstractSession session) {
144         throw QueryException.methodDoesNotExistInContainerClass("set", getContainerClass());
145     }
146     
147     /**
148      * INTERNAL:
149      * Return a container populated with the contents of the specified Vector.
150      */

151     public Object JavaDoc buildContainerFromVector(Vector JavaDoc vector, AbstractSession session) {
152         Object JavaDoc container = containerInstance(vector.size());
153
154         for (Enumeration JavaDoc e = vector.elements(); e.hasMoreElements();) {
155             addInto(e.nextElement(), container, session);
156         }
157         return container;
158     }
159
160     /**
161      * INTERNAL:
162      * Return the appropriate container policy for the specified
163      * concrete container class.
164      */

165     public static ContainerPolicy buildPolicyFor(Class JavaDoc concreteContainerClass) {
166         return buildPolicyFor(concreteContainerClass, false);
167     }
168     
169     /**
170      * INTERNAL:
171      * Return the appropriate container policy for the specified
172      * concrete container class.
173      */

174     public static ContainerPolicy buildPolicyFor(Class JavaDoc concreteContainerClass, boolean hasOrdering) {
175         if (Helper.classImplementsInterface(concreteContainerClass, ClassConstants.List_Class)) {
176             if (hasOrdering) {
177                 return new OrderedListContainerPolicy(concreteContainerClass);
178             } else {
179                 return new ListContainerPolicy(concreteContainerClass);
180             }
181         } else if (Helper.classImplementsInterface(concreteContainerClass, ClassConstants.SortedSet_Class)) {
182             return new SortedCollectionContainerPolicy(concreteContainerClass);
183         } else if (Helper.classImplementsInterface(concreteContainerClass, ClassConstants.Collection_Class)) {
184             return new CollectionContainerPolicy(concreteContainerClass);
185         } else if (Helper.classImplementsInterface(concreteContainerClass, ClassConstants.Map_Class)) {
186             return new MapContainerPolicy(concreteContainerClass);
187         }
188
189         throw ValidationException.illegalContainerClass(concreteContainerClass);
190     }
191
192     /**
193      * INTERNAL:
194      * Remove all the elements from the specified container.
195      * Valid only for certain subclasses.
196      */

197     public void clear(Object JavaDoc container) {
198         throw QueryException.methodNotValid(this, "clear(Object container)");
199     }
200
201     public Object JavaDoc clone() {
202         try {
203             return super.clone();
204         } catch (CloneNotSupportedException JavaDoc e) {
205             throw new InternalError JavaDoc();
206         }
207     }
208
209     public ContainerPolicy clone(ReadQuery query) {
210         return (ContainerPolicy)clone();
211     }
212
213     /**
214      * INTERNAL:
215      * Return a clone of the specified container. Can only be called for select subclasses.
216      */

217     public Object JavaDoc cloneFor(Object JavaDoc container) {
218         throw QueryException.cannotCreateClone(this, container);
219     }
220
221     /**
222      * INTERNAL:
223      * This method is used to calculate the differences between two collections.
224      */

225     public void compareCollectionsForChange(Object JavaDoc oldCollection, Object JavaDoc newCollection, CollectionChangeRecord changeRecord, AbstractSession session, ClassDescriptor referenceDescriptor) {
226         // 2612538 - the default size of IdentityHashtable (32) is appropriate
227
IdentityHashMap JavaDoc originalKeyValues = new IdentityHashMap JavaDoc();
228         IdentityHashMap JavaDoc cloneKeyValues = new IdentityHashMap JavaDoc();
229
230         // Collect the values from the oldCollection.
231
if (oldCollection != null) {
232             Object JavaDoc backUpIter = iteratorFor(oldCollection);
233             
234             while (hasNext(backUpIter)) {
235                 Object JavaDoc secondObject = next(backUpIter, session);
236     
237                 // CR2378 null check to prevent a null pointer exception - XC
238
if (secondObject != null) {
239                     originalKeyValues.put(secondObject, secondObject);
240                 }
241             }
242         }
243         
244         if (newCollection != null){
245             // Collect the objects from the new Collection.
246
Object JavaDoc cloneIter = iteratorFor(newCollection);
247             
248             while (hasNext(cloneIter)) {
249                 Object JavaDoc firstObject = next(cloneIter, session);
250     
251                 // CR2378 null check to prevent a null pointer exception - XC
252
// If value is null then nothing can be done with it.
253
if (firstObject != null) {
254                     if (originalKeyValues.containsKey(firstObject)) {
255                         // There is an original in the cache
256
if ((compareKeys(firstObject, session))) {
257                             // The keys have not changed
258
originalKeyValues.remove(firstObject);
259                         } else {
260                             // The keys have changed, create a changeSet
261
// (it will be resused later) and set the old key
262
// value to be used to remove.
263
Object JavaDoc backUpVersion = null;
264     
265                             // CR4172 compare the keys from the back up to the
266
// clone not from the original to the clone.
267
if (((UnitOfWorkImpl)session).isClassReadOnly(firstObject.getClass())) {
268                                 backUpVersion = ((UnitOfWorkImpl)session).getOriginalVersionOfObject(firstObject);
269                             } else {
270                                 backUpVersion = ((UnitOfWorkImpl)session).getBackupClone(firstObject);
271                             }
272                             
273                             ObjectChangeSet changeSet = referenceDescriptor.getObjectBuilder().createObjectChangeSet(firstObject, (UnitOfWorkChangeSet) changeRecord.getOwner().getUOWChangeSet(), session);
274                             changeSet.setOldKey(keyFrom(backUpVersion, session));
275                             changeSet.setNewKey(keyFrom(firstObject, session));
276                             cloneKeyValues.put(firstObject, firstObject);
277                         }
278                     } else {
279                         // Place it in the add collection
280
cloneKeyValues.put(firstObject, firstObject);
281                     }
282                 }
283             }
284         }
285
286         changeRecord.addAdditionChange(cloneKeyValues, (UnitOfWorkChangeSet) changeRecord.getOwner().getUOWChangeSet(), session);
287         changeRecord.addRemoveChange(originalKeyValues, (UnitOfWorkChangeSet) changeRecord.getOwner().getUOWChangeSet(), session);
288     }
289     
290     /**
291      * INTERNAL:
292      * Return true if keys are the same in the source as the backup. False otherwise
293      * in the case of readonly compare against the original
294      * For non map container policies return true always, because these policies have no concepts of Keys
295      */

296     public boolean compareKeys(Object JavaDoc sourceKey, AbstractSession session) {
297         return true;
298     }
299
300     /**
301      * INTERNAL:
302      * Build a new container, add the contents of each of the specified containers
303      * to it, and return it.
304      * Both of the containers must use the same container policy (namely, this one).
305      */

306     public Object JavaDoc concatenateContainers(Object JavaDoc firstContainer, Object JavaDoc secondContainer) {
307         Object JavaDoc container = containerInstance(sizeFor(firstContainer) + sizeFor(secondContainer));
308
309         for (Object JavaDoc firstIter = iteratorFor(firstContainer); hasNext(firstIter);) {
310             addInto(null, next(firstIter), container);
311         }
312
313         for (Object JavaDoc secondIter = iteratorFor(secondContainer); hasNext(secondIter);) {
314             addInto(null, next(secondIter), container);
315         }
316         return container;
317     }
318
319     /**
320      * INTERNAL:
321      * Return an instance of the container class.
322      * Null should never be returned.
323      * A ValidationException is thrown on error.
324      */

325     public Object JavaDoc containerInstance() {
326         try {
327             if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
328                 try {
329                     return AccessController.doPrivileged(new PrivilegedNewInstanceFromClass(getContainerClass()));
330                 } catch (PrivilegedActionException JavaDoc exception) {
331                     throw QueryException.couldNotInstantiateContainerClass(getContainerClass(), exception.getException());
332                 }
333             } else {
334                 return PrivilegedAccessHelper.newInstanceFromClass(getContainerClass());
335             }
336         } catch (Exception JavaDoc ex) {
337             throw QueryException.couldNotInstantiateContainerClass(getContainerClass(), ex);
338         }
339     }
340
341     /**
342      * INTERNAL:
343      * Return an instance of the container class with the specified initial capacity.
344      * Null should never be returned.
345      * A ValidationException is thrown on error.
346      */

347     public Object JavaDoc containerInstance(int initialCapacity) {
348         if (getConstructor() == null) {
349             return containerInstance();
350         }
351         try {
352             Object JavaDoc[] arguments = new Object JavaDoc[1];
353
354             //Code change for 3732. No longer need to add 1 as this was for JDK 1.1
355
arguments[0] = new Integer JavaDoc(initialCapacity);
356             if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
357                 try {
358                     return AccessController.doPrivileged(new PrivilegedInvokeConstructor(getConstructor(), arguments));
359                 } catch (PrivilegedActionException JavaDoc exception) {
360                     throw QueryException.couldNotInstantiateContainerClass(getContainerClass(), exception.getException());
361                 }
362             } else {
363                 return PrivilegedAccessHelper.invokeConstructor(getConstructor(), arguments);
364             }
365         } catch (Exception JavaDoc ex) {
366             throw QueryException.couldNotInstantiateContainerClass(getContainerClass(), ex);
367         }
368     }
369
370     /**
371      * INTERNAL:
372      * Return whether element exists in container.
373      */

374     protected boolean contains(Object JavaDoc element, Object JavaDoc container) {
375         throw QueryException.methodNotValid(this, "contains(Object element, Object container)");
376     }
377
378     /**
379      * INTERNAL:
380      * Check if the object is contained in the collection.
381      * This is used to check contains in a collection independent of JDK 1.1 and 1.2.
382      * The session may be required to unwrap for the wrapper policy.
383      */

384     public boolean contains(Object JavaDoc element, Object JavaDoc container, AbstractSession session) {
385         if (hasElementDescriptor() && getElementDescriptor().hasWrapperPolicy()) {
386             // The wrapper for the object must be removed.
387
Object JavaDoc iterator = iteratorFor(container);
388             while (hasNext(iterator)) {
389                 Object JavaDoc next = next(iterator);
390                 if (getElementDescriptor().getObjectBuilder().unwrapObject(next, session).equals(element)) {
391                     return true;
392                 }
393             }
394             return false;
395         } else {
396             return contains(element, container);
397         }
398     }
399
400     /**
401      * INTERNAL:
402      * Return whether element exists in container.
403      */

404     protected boolean containsKey(Object JavaDoc element, Object JavaDoc container) {
405         throw QueryException.methodNotValid(this, "containsKey(Object element, Object container)");
406     }
407
408     /**
409      * INTERNAL:
410      * Convert all the class-name-based settings in this ContainerPolicy to actual class-based
411      * settings
412      * This method is implemented by subclasses as necessary.
413      * @param classLoader
414      */

415     public void convertClassNamesToClasses(ClassLoader JavaDoc classLoader){};
416
417     /**
418      * INTERNAL:
419      * This can be used by collection such as cursored stream to gain control over execution.
420      */

421     public Object JavaDoc execute() {
422         throw QueryException.methodNotValid(this, "execute()");
423     }
424     
425     /**
426      * INTERNAL:
427      * Return the size constructor if available.
428      */

429     protected Constructor JavaDoc getConstructor() {
430         return constructor;
431     }
432
433     /**
434      * INTERNAL:
435      * Return the class used for the container.
436      */

437     public Class JavaDoc getContainerClass() {
438         throw QueryException.methodNotValid(this, "getContainerClass()");
439     }
440
441     /**
442      * INTERNAL:
443      * Used by the MW
444      */

445     public String JavaDoc getContainerClassName() {
446         throw QueryException.methodNotValid(this, "getContainerClassName()");
447     }
448
449     /**
450      * INTERNAL:
451      * Used for wrapping and unwrapping with the wrapper policy.
452      */

453     public ClassDescriptor getElementDescriptor() {
454         return elementDescriptor;
455     }
456     
457     /**
458      * INTERNAL:
459      * Used for wrapping and unwrapping with the wrapper policy.
460      */

461     public boolean hasElementDescriptor() {
462         return getElementDescriptor() != null;
463     }
464
465     /**
466      * INTERNAL:
467      * Return whether the iterator has more objects.
468      * The iterator is the one returned from #iteratorFor().
469      * Valid for some subclasses only.
470      *
471      * @see ContainerPolicy#iteratorFor(java.lang.Object)
472      */

473     public abstract boolean hasNext(Object JavaDoc iterator);
474
475     /**
476      * INTERNAL:
477      * Returns true if the collection has order
478      */

479     public boolean hasOrder() {
480         return false;
481     }
482
483     /**
484      * INTERNAL:
485      * Find the size constructor.
486      * Providing a size is important for performance.
487      */

488     public void initializeConstructor() {
489         try {
490             Constructor JavaDoc constructor = null;
491             if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
492                 try {
493                     constructor = (Constructor JavaDoc)AccessController.doPrivileged(new PrivilegedGetConstructorFor(getContainerClass(), new Class JavaDoc[] { ClassConstants.PINT }, false));
494                 } catch (PrivilegedActionException JavaDoc exception) {
495                     // If there is no constructor then the default will be used.
496
return;
497                 }
498             } else {
499                 constructor = PrivilegedAccessHelper.getConstructorFor(getContainerClass(), new Class JavaDoc[] { ClassConstants.PINT }, false);
500             }
501             setConstructor(constructor);
502         } catch (Exception JavaDoc exception) {
503             // If there is no constructor then the default will be used.
504
return;
505         }
506     }
507
508     public boolean isCollectionPolicy() {
509         return false;
510     }
511
512     /**
513      * Is this a Cursored stream?
514      *
515      */

516     public boolean isCursoredStreamPolicy() {
517         return false;
518     }
519
520     public boolean isCursorPolicy() {
521         return false;
522     }
523
524     public boolean isCursorStreamPolicy() {
525         return false;
526     }
527
528     public boolean isDirectMapPolicy() {
529         return false;
530     }
531
532     /**
533      * INTERNAL:
534      * Return whether the container is empty.
535      */

536     public boolean isEmpty(Object JavaDoc container) {
537         return sizeFor(container) == 0;
538     }
539
540     public boolean isListPolicy() {
541         return false;
542     }
543
544     public boolean isMapPolicy() {
545         return false;
546     }
547     
548     public boolean isScrollableCursorPolicy() {
549         return false;
550     }
551
552     /**
553      * INTERNAL:
554      * Return whether the specified object is of a valid container type.
555      *
556      * @see oracle.toplink.essentials.internal.queryframework.CollectionContainerPolicy#isValidContainer(Object)
557      * @see oracle.toplink.essentials.internal.queryframework.MapContainerPolicy#isValidContainer(Object)
558      */

559     public boolean isValidContainer(Object JavaDoc container) {
560         throw QueryException.methodNotValid(this, "isValidContainer(Object container)");
561     }
562
563     /**
564      * INTERNAL:
565      * Return whether the specified type is a valid container type.
566      */

567     public boolean isValidContainerType(Class JavaDoc containerType) {
568         throw QueryException.methodNotValid(this, "isValidContainerType(Class containerType)");
569     }
570
571     /**
572      * INTERNAL:
573      * Return an iterator for the given container.
574      * This iterator can then be used as a parameter to #hasNext()
575      * and #next().
576      *
577      * @see ContainerPolicy#hasNext(java.lang.Object)
578      * @see ContainerPolicy#next(java.lang.Object)
579      */

580     public abstract Object JavaDoc iteratorFor(Object JavaDoc container);
581
582     /**
583      * INTERNAL:
584      * Return the key for the specified element.
585      *
586      * @param element java.lang.Object
587      * @return java.lang.Object
588      */

589     public Object JavaDoc keyFrom(Object JavaDoc element, AbstractSession session) {
590         return null;
591     }
592     
593     /**
594      * INTERNAL:
595      * Merge changes from the source to the target object. Because this is a
596      * collection mapping, values are added to or removed from the collection
597      * based on the change set.
598      */

599     public Object JavaDoc mergeCascadeParts(ObjectChangeSet objectChanges, MergeManager mergeManager, AbstractSession parentSession) {
600         Object JavaDoc object = null;
601                 
602         if (mergeManager.shouldMergeChangesIntoDistributedCache()) {
603             // CR 2855 - Try to find the object first we may have merged it already.
604
object = objectChanges.getTargetVersionOfSourceObject(parentSession);
605                         
606             if ((object == null) && (objectChanges.isNew() || objectChanges.isAggregate()) && objectChanges.containsChangesFromSynchronization()) {
607                 if (!mergeManager.getObjectsAlreadyMerged().containsKey(objectChanges)) {
608                     // CR 2855 - If we haven't merged this object already then
609
// build a new object otherwise leave it as null which will
610
// stop the recursion.
611
// CR 3424 - Need to build the right instance based on
612
// class type instead of referenceDescriptor.
613
Class JavaDoc objectClass = objectChanges.getClassType(mergeManager.getSession());
614                     object = mergeManager.getSession().getDescriptor(objectClass).getObjectBuilder().buildNewInstance();
615                     // Store the change set to prevent us from creating this new object again.
616
mergeManager.getObjectsAlreadyMerged().put(objectChanges, object);
617                 } else {
618                     // CR 4012 - We have all ready created the object, must be
619
// in a cyclic merge on a new object so get it out of the
620
// already merged collection
621
object = mergeManager.getObjectsAlreadyMerged().get(objectChanges);
622                 }
623             } else {
624                 object = objectChanges.getTargetVersionOfSourceObject(parentSession, true);
625             }
626                         
627             if (objectChanges.containsChangesFromSynchronization()) {
628                 mergeManager.mergeChanges(object, objectChanges);
629             }
630         } else {
631             mergeManager.mergeChanges(objectChanges.getUnitOfWorkClone(), objectChanges);
632         }
633         
634         return object;
635     }
636     
637     /**
638      * INTERNAL:
639      * Merge changes from the source to the target object. Because this is a
640      * collection mapping, values are added to or removed from the collection
641      * based on the change set.
642      */

643     public void mergeChanges(CollectionChangeRecord changeRecord, Object JavaDoc valueOfTarget, boolean shouldMergeCascadeParts, MergeManager mergeManager, AbstractSession parentSession) {
644         ObjectChangeSet objectChanges;
645         
646         // Step 1 - iterate over the removed changes and remove them from the container.
647
Enumeration JavaDoc removeObjects = changeRecord.getRemoveObjectList().keys();
648             
649         while (removeObjects.hasMoreElements()) {
650             objectChanges = (ObjectChangeSet) removeObjects.nextElement();
651             
652             synchronized (valueOfTarget) {
653                 removeFrom(objectChanges.getOldKey(), objectChanges.getTargetVersionOfSourceObject(mergeManager.getSession()), valueOfTarget, parentSession);
654             }
655             
656             if (!mergeManager.shouldMergeChangesIntoDistributedCache()) {
657                 mergeManager.registerRemovedNewObjectIfRequired(objectChanges.getUnitOfWorkClone());
658             }
659         }
660             
661         // Step 2 - iterate over the added changes and add them to the container.
662
Enumeration JavaDoc addObjects = changeRecord.getAddObjectList().keys();
663             
664         while (addObjects.hasMoreElements()) {
665             objectChanges = (ObjectChangeSet) addObjects.nextElement();
666             Object JavaDoc object = null;
667                 
668             if (shouldMergeCascadeParts) {
669                 object = mergeCascadeParts(objectChanges, mergeManager, parentSession);
670             }
671                 
672             if (object == null) {
673                 // Retrieve the object to be added to the collection.
674
object = objectChanges.getTargetVersionOfSourceObject(mergeManager.getSession(), false);
675             }
676     
677             synchronized (valueOfTarget) {
678                 // I am assuming that at this point the above merge will have created a new object if required
679
if (mergeManager.shouldMergeChangesIntoDistributedCache()) {
680                     //bug#4458089 and 4454532- check if collection contains new item before adding during merge into distributed cache
681
if (!contains(object, valueOfTarget, mergeManager.getSession())) {
682                         addInto(objectChanges.getNewKey(), object, valueOfTarget, mergeManager.getSession());
683                     }
684                 } else {
685                     addInto(objectChanges.getNewKey(), object, valueOfTarget, mergeManager.getSession());
686                 }
687             }
688         }
689     }
690     
691     /**
692      * INTERNAL:
693      * Return the next object on the queue. The iterator is the one
694      * returned from #iteratorFor().
695      * Valid for some subclasses only.
696      *
697      * @see ContainerPolicy#iteratorFor(java.lang.Object)
698      */

699     protected abstract Object JavaDoc next(Object JavaDoc iterator);
700
701     /**
702      * INTERNAL:
703      * Return the next object from the iterator.
704      * This is used to stream over a collection independent of JDK 1.1 and 1.2.
705      * The session may be required to unwrap for the wrapper policy.
706      */

707     public Object JavaDoc next(Object JavaDoc iterator, AbstractSession session) {
708         Object JavaDoc next = next(iterator);
709         if (hasElementDescriptor()) {
710             next = getElementDescriptor().getObjectBuilder().unwrapObject(next, session);
711         }
712         return next;
713     }
714
715     /**
716      * This can be used by collection such as cursored stream to gain control over execution.
717      */

718     public boolean overridesRead() {
719         return false;
720     }
721
722     /**
723      * Prepare and validate.
724      * Allow subclasses to override.
725      */

726     public void prepare(DatabaseQuery query, AbstractSession session) throws QueryException {
727         if (query.isReadAllQuery() && (!query.isReportQuery()) && query.shouldUseWrapperPolicy()) {
728             setElementDescriptor(query.getDescriptor());
729             //make sure DataReadQuery points to this container policy
730
} else if (query.isDataReadQuery()) {
731             ((DataReadQuery)query).setContainerPolicy(this);
732         }
733     }
734
735     /**
736      * Prepare and validate.
737      * Allow subclasses to override.
738      */

739     public void prepareForExecution() throws QueryException {
740     }
741
742     /**
743      * This method is used to bridge the behaviour between Attribute Change Tracking and
744      * deferred change tracking with respect to adding the same instance multiple times.
745      * Each containerplicy type will implement specific behaviour for the collection
746      * type it is wrapping. These methods are only valid for collections containing object references
747      */

748     public void recordAddToCollectionInChangeRecord(ObjectChangeSet changeSetToAdd, CollectionChangeRecord collectionChangeRecord){
749         if (collectionChangeRecord.getRemoveObjectList().containsKey(changeSetToAdd)) {
750             collectionChangeRecord.getRemoveObjectList().remove(changeSetToAdd);
751         } else {
752             collectionChangeRecord.getAddObjectList().put(changeSetToAdd, changeSetToAdd);
753         }
754     }
755     
756     /**
757      * This method is used to bridge the behaviour between Attribute Change Tracking and
758      * deferred change tracking with respect to adding the same instance multiple times.
759      * Each containerplicy type will implement specific behaviour for the collection
760      * type it is wrapping. These methods are only valid for collections containing object references
761      */

762     public void recordRemoveFromCollectionInChangeRecord(ObjectChangeSet changeSetToRemove, CollectionChangeRecord collectionChangeRecord){
763         if(collectionChangeRecord.getAddObjectList().containsKey(changeSetToRemove)) {
764             collectionChangeRecord.getAddObjectList().remove(changeSetToRemove);
765         } else {
766             collectionChangeRecord.getRemoveObjectList().put(changeSetToRemove, changeSetToRemove);
767         }
768     }
769     
770     /**
771      * This can be used by collection such as cursored stream to gain control over execution.
772      */

773     public Object JavaDoc remoteExecute() {
774         return null;
775     }
776
777     /**
778      * INTERNAL:
779      * Remove all the elements from container.
780      * Valid only for certain subclasses.
781      */

782     public void removeAllElements(Object JavaDoc container) {
783         clear(container);
784     }
785
786     /**
787      * INTERNAL:
788      * Remove element from container.
789      * Valid for some subclasses only.
790      */

791     protected boolean removeFrom(Object JavaDoc key, Object JavaDoc element, Object JavaDoc container) {
792         throw QueryException.cannotRemoveFromContainer(element, container, this);
793     }
794
795     /**
796      * INTERNAL:
797      * Remove the object from the collection.
798      * This is used to remove from a collection independent of JDK 1.1 and 1.2.
799      * The session may be required to unwrap for the wrapper policy.
800      */

801     public boolean removeFrom(Object JavaDoc key, Object JavaDoc element, Object JavaDoc container, AbstractSession session) {
802         Object JavaDoc objectToRemove = element;
803         if (hasElementDescriptor() && getElementDescriptor().hasWrapperPolicy()) {
804             // The wrapper for the object must be removed.
805
Object JavaDoc iterator = iteratorFor(container);
806             while (hasNext(iterator)) {
807                 Object JavaDoc next = next(iterator);
808                 if (getElementDescriptor().getObjectBuilder().unwrapObject(next, session).equals(element)) {
809                     objectToRemove = next;
810                     break;
811                 }
812             }
813         }
814
815         return removeFrom(key, objectToRemove, container);
816     }
817
818     /**
819      * INTERNAL:
820      * Remove the object from the collection.
821      * This is used to remove from a collection independent of JDK 1.1 and 1.2.
822      * The session may be required to unwrap for the wrapper policy.
823      */

824     public boolean removeFrom(Object JavaDoc element, Object JavaDoc container, AbstractSession session) {
825         return removeFrom(null, element, container, session);
826     }
827
828     /**
829     * INTERNAL:
830     * It is illegal to send this message to this receiver. Try one of my subclasses.
831     * Throws an exception.
832     *
833     * @see #ListContainerPolicy
834     */

835     public void removeFromWithOrder(int beginIndex, Object JavaDoc container) {
836         throw QueryException.methodDoesNotExistInContainerClass("remove(index)", getContainerClass());
837     }
838
839     /**
840      * INTERNAL:
841      * Set the size constructor if available.
842      */

843     protected void setConstructor(Constructor JavaDoc constructor) {
844         this.constructor = constructor;
845     }
846
847     /**
848      * INTERNAL:
849      * Set the class used for the container.
850      */

851     public void setContainerClass(Class JavaDoc containerClass) {
852         throw QueryException.methodNotValid(this, "getContainerClass()");
853     }
854
855     /**
856      * INTERNAL:
857      * Used by the MW
858      */

859     public void setContainerClassName(String JavaDoc containerClassName) {
860         throw QueryException.methodNotValid(this, "getContainerClassName()");
861     }
862     
863     /**
864      * INTERNAL:
865      * Used for wrapping and unwrapping with the wrapper policy.
866      */

867     public void setElementDescriptor(ClassDescriptor elementDescriptor) {
868         this.elementDescriptor = elementDescriptor;
869     }
870
871     /**
872      * INTERNAL:
873      * It is illegal to send this message to this receiver. Try one of my
874      * subclasses. Throws an exception.
875      *
876      * @see #MapContainerPolicy
877      */

878     public void setKeyName(String JavaDoc instanceVariableName, String JavaDoc elementClassName) {
879         throw ValidationException.containerPolicyDoesNotUseKeys(this, instanceVariableName);
880     }
881
882     /**
883      * INTERNAL:
884      * Return the size of container.
885      */

886     public int sizeFor(Object JavaDoc container) {
887         throw QueryException.methodNotValid(this, "sizeFor(Object container)");
888     }
889
890     public String JavaDoc toString() {
891         return Helper.getShortClassName(this.getClass()) + "(" + toStringInfo() + ")";
892     }
893
894     protected Object JavaDoc toStringInfo() {
895         return "";
896     }
897
898     /**
899      * INTERNAL:
900      * over ride in MapPolicy subclass
901      */

902     public void validateElementAndRehashIfRequired(Object JavaDoc sourceValue, Object JavaDoc target, AbstractSession session, Object JavaDoc targetVersionOfSource) {
903         //do nothing
904
}
905
906     /**
907      * INTERNAL:
908      * Return a Vector populated with the contents of container.
909      * Added for bug 2766379, must implement a version of vectorFor that
910      * handles wrapped objects.
911      */

912     public Vector JavaDoc vectorFor(Object JavaDoc container, AbstractSession session) {
913         Vector JavaDoc result = new Vector JavaDoc(sizeFor(container));
914
915         for (Object JavaDoc iter = iteratorFor(container); hasNext(iter);) {
916             result.addElement(next(iter, session));
917         }
918         return result;
919     }
920 }
921
Popular Tags