Source code: org/hibernate/collection/PersistentBag.java
1 //$Id: PersistentBag.java,v 1.14 2005/04/03 02:53:05 oneovthafew Exp $
2 package org.hibernate.collection;
3
4 import java.io.Serializable;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.ListIterator;
12
13 import org.hibernate.EntityMode;
14 import org.hibernate.HibernateException;
15 import org.hibernate.engine.SessionImplementor;
16 import org.hibernate.persister.collection.CollectionPersister;
17 import org.hibernate.type.Type;
18
19 /**
20 * An unordered, unkeyed collection that can contain the same element
21 * multiple times. The Java collections API, curiously, has no <tt>Bag</tt>.
22 * Most developers seem to use <tt>List</tt>s to represent bag semantics,
23 * so Hibernate follows this practice.
24 *
25 * @author Gavin King
26 */
27 public class PersistentBag extends AbstractPersistentCollection implements java.util.List {
28
29 private java.util.List bag;
30
31 public PersistentBag(SessionImplementor session) {
32 super(session);
33 }
34
35 public PersistentBag(SessionImplementor session, java.util.Collection coll) {
36 super(session);
37 if (coll instanceof java.util.List) {
38 bag = (java.util.List) coll;
39 }
40 else {
41 bag = new ArrayList();
42 Iterator iter = coll.iterator();
43 while ( iter.hasNext() ) {
44 bag.add( iter.next() );
45 }
46 }
47 setInitialized();
48 setDirectlyAccessible(true);
49 }
50
51 public PersistentBag() {} //needed for SOAP libraries, etc
52
53 public boolean isWrapper(Object collection) {
54 return bag==collection;
55 }
56 public boolean empty() {
57 return bag.isEmpty();
58 }
59
60 public Iterator entries(CollectionPersister persister) {
61 return bag.iterator();
62 }
63
64 public Object readFrom(ResultSet rs, CollectionPersister persister, Object owner)
65 throws HibernateException, SQLException {
66 // note that if we load this collection from a cartesian product
67 // the multiplicity would be broken ... so use an idbag instead
68 Object element = persister.readElement( rs, owner, getSession() ) ;
69 if (element!=null) bag.add(element);
70 return element;
71 }
72
73 public void beforeInitialize(CollectionPersister persister) {
74 this.bag = new ArrayList();
75 }
76
77 public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
78 Type elementType = persister.getElementType();
79 EntityMode entityMode = getSession().getEntityMode();
80 java.util.List sn = (java.util.List) getSnapshot();
81 if ( sn.size()!=bag.size() ) return false;
82 Iterator iter = bag.iterator();
83 while ( iter.hasNext() ) {
84 Object elt = iter.next();
85 final boolean unequal = countOccurrences(elt, bag, elementType, entityMode) !=
86 countOccurrences(elt, sn, elementType, entityMode);
87 if ( unequal ) return false;
88 }
89 return true;
90 }
91
92 private int countOccurrences(Object element, java.util.List list, Type elementType, EntityMode entityMode)
93 throws HibernateException {
94 Iterator iter = list.iterator();
95 int result=0;
96 while ( iter.hasNext() ) {
97 if ( elementType.isSame( element, iter.next(), entityMode ) ) result++;
98 }
99 return result;
100 }
101
102 protected Serializable snapshot(CollectionPersister persister)
103 throws HibernateException {
104 EntityMode entityMode = getSession().getEntityMode();
105 ArrayList clonedList = new ArrayList( bag.size() );
106 Iterator iter = bag.iterator();
107 while ( iter.hasNext() ) {
108 clonedList.add( persister.getElementType().deepCopy( iter.next(), entityMode, persister.getFactory() ) );
109 }
110 return clonedList;
111 }
112
113 public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
114 java.util.List sn = (java.util.List) snapshot;
115 return getOrphans( sn, bag, entityName, getSession() );
116 }
117
118
119 public Serializable disassemble(CollectionPersister persister)
120 throws HibernateException {
121
122 int length = bag.size();
123 Serializable[] result = new Serializable[length];
124 for ( int i=0; i<length; i++ ) {
125 result[i] = persister.getElementType().disassemble( bag.get(i), getSession(), null );
126 }
127 return result;
128 }
129
130 public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
131 throws HibernateException {
132 beforeInitialize(persister);
133 Serializable[] array = (Serializable[]) disassembled;
134 for ( int i=0; i<array.length; i++ ) {
135 Object element = persister.getElementType().assemble( array[i], getSession(), owner );
136 if ( element!=null ) bag.add( element );
137 }
138 setInitialized();
139 }
140
141 public boolean needsRecreate(CollectionPersister persister) {
142 return !persister.isOneToMany();
143 }
144
145
146 // For a one-to-many, a <bag> is not really a bag;
147 // it is *really* a set, since it can't contain the
148 // same element twice. It could be considered a bug
149 // in the mapping dtd that <bag> allows <one-to-many>.
150
151 // Anyway, here we implement <set> semantics for a
152 // <one-to-many> <bag>!
153
154 public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
155 //if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
156 Type elementType = persister.getElementType();
157 EntityMode entityMode = getSession().getEntityMode();
158 ArrayList deletes = new ArrayList();
159 java.util.List sn = (java.util.List) getSnapshot();
160 Iterator olditer = sn.iterator();
161 int i=0;
162 while ( olditer.hasNext() ) {
163 Object old = olditer.next();
164 Iterator newiter = bag.iterator();
165 boolean found = false;
166 if ( bag.size()>i && elementType.isSame( old, bag.get(i++), entityMode ) ) {
167 //a shortcut if its location didn't change!
168 found = true;
169 }
170 else {
171 //search for it
172 //note that this code is incorrect for other than one-to-many
173 while ( newiter.hasNext() ) {
174 if ( elementType.isSame( old, newiter.next(), entityMode ) ) {
175 found = true;
176 break;
177 }
178 }
179 }
180 if (!found) deletes.add(old);
181 }
182 return deletes.iterator();
183 }
184
185 public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
186 //if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
187 java.util.List sn = (java.util.List) getSnapshot();
188 final EntityMode entityMode = getSession().getEntityMode();
189 if ( sn.size()>i && elemType.isSame( sn.get(i), entry, entityMode ) ) {
190 //a shortcut if its location didn't change!
191 return false;
192 }
193 else {
194 //search for it
195 //note that this code is incorrect for other than one-to-many
196 Iterator olditer = sn.iterator();
197 while ( olditer.hasNext() ) {
198 Object old = olditer.next();
199 if ( elemType.isSame( old, entry, entityMode ) ) return false;
200 }
201 return true;
202 }
203 }
204
205 public boolean isRowUpdatePossible() {
206 return false;
207 }
208
209 public boolean needsUpdating(Object entry, int i, Type elemType) {
210 //if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
211 return false;
212 }
213
214 /**
215 * @see java.util.Collection#size()
216 */
217 public int size() {
218 read();
219 return bag.size();
220 }
221
222 /**
223 * @see java.util.Collection#isEmpty()
224 */
225 public boolean isEmpty() {
226 read();
227 return bag.isEmpty();
228 }
229
230 /**
231 * @see java.util.Collection#contains(Object)
232 */
233 public boolean contains(Object o) {
234 read();
235 return bag.contains(o);
236 }
237
238 /**
239 * @see java.util.Collection#iterator()
240 */
241 public Iterator iterator() {
242 read();
243 return new IteratorProxy( bag.iterator() );
244 }
245
246 /**
247 * @see java.util.Collection#toArray()
248 */
249 public Object[] toArray() {
250 read();
251 return bag.toArray();
252 }
253
254 /**
255 * @see java.util.Collection#toArray(Object[])
256 */
257 public Object[] toArray(Object[] a) {
258 read();
259 return bag.toArray(a);
260 }
261
262 /**
263 * @see java.util.Collection#add(Object)
264 */
265 public boolean add(Object o) {
266 if ( !queueAdd(o) ) {
267 write();
268 return bag.add(o);
269 }
270 else {
271 return true;
272 }
273 }
274
275 /**
276 * @see java.util.Collection#remove(Object)
277 */
278 public boolean remove(Object o) {
279 write();
280 return bag.remove(o);
281 }
282
283 /**
284 * @see java.util.Collection#containsAll(Collection)
285 */
286 public boolean containsAll(Collection c) {
287 read();
288 return bag.containsAll(c);
289 }
290
291 /**
292 * @see java.util.Collection#addAll(Collection)
293 */
294 public boolean addAll(Collection c) {
295 if ( c.size()==0 ) return false;
296 if ( !queueAddAll(c) ) {
297 write();
298 return bag.addAll(c);
299 }
300 else {
301 return c.size()>0;
302 }
303 }
304
305 public void delayedAddAll(Collection c) {
306 bag.addAll(c);
307 }
308
309 /**
310 * @see java.util.Collection#removeAll(Collection)
311 */
312 public boolean removeAll(Collection c) {
313 if ( c.size()>0 ) {
314 write();
315 return bag.removeAll(c);
316 }
317 else {
318 return false;
319 }
320 }
321
322 /**
323 * @see java.util.Collection#retainAll(Collection)
324 */
325 public boolean retainAll(Collection c) {
326 write();
327 return bag.retainAll(c);
328 }
329
330 /**
331 * @see java.util.Collection#clear()
332 */
333 public void clear() {
334 write();
335 bag.clear();
336 }
337
338 public Object getIndex(Object entry, int i, CollectionPersister persister) {
339 throw new UnsupportedOperationException("Bags don't have indexes");
340 }
341
342 public Object getElement(Object entry) {
343 return entry;
344 }
345
346 public Object getSnapshotElement(Object entry, int i) {
347 java.util.List sn = (java.util.List) getSnapshot();
348 return sn.get(i);
349 }
350
351 public int occurrences(Object o) {
352 read();
353 Iterator iter = bag.iterator();
354 int result=0;
355 while ( iter.hasNext() ) {
356 if ( o.equals( iter.next() ) ) result++;
357 }
358 return result;
359 }
360
361 // List OPERATIONS:
362
363 /**
364 * @see java.util.List#add(int, Object)
365 */
366 public void add(int i, Object o) {
367 write();
368 bag.add(i, o);
369 }
370
371 /**
372 * @see java.util.List#addAll(int, Collection)
373 */
374 public boolean addAll(int i, Collection c) {
375 if ( c.size()>0 ) {
376 write();
377 return bag.addAll(i, c);
378 }
379 else {
380 return false;
381 }
382 }
383
384 /**
385 * @see java.util.List#get(int)
386 */
387 public Object get(int i) {
388 read();
389 return bag.get(i);
390 }
391
392 /**
393 * @see java.util.List#indexOf(Object)
394 */
395 public int indexOf(Object o) {
396 read();
397 return bag.indexOf(o);
398 }
399
400 /**
401 * @see java.util.List#lastIndexOf(Object)
402 */
403 public int lastIndexOf(Object o) {
404 read();
405 return bag.lastIndexOf(o);
406 }
407
408 /**
409 * @see java.util.List#listIterator()
410 */
411 public ListIterator listIterator() {
412 read();
413 return new ListIteratorProxy( bag.listIterator() );
414 }
415
416 /**
417 * @see java.util.List#listIterator(int)
418 */
419 public ListIterator listIterator(int i) {
420 read();
421 return new ListIteratorProxy( bag.listIterator(i) );
422 }
423
424 /**
425 * @see java.util.List#remove(int)
426 */
427 public Object remove(int i) {
428 write();
429 return bag.remove(i);
430 }
431
432 /**
433 * @see java.util.List#set(int, Object)
434 */
435 public Object set(int i, Object o) {
436 write();
437 return bag.set(i, o);
438 }
439
440 /**
441 * @see java.util.List#subList(int, int)
442 */
443 public List subList(int start, int end) {
444 read();
445 return new ListProxy( bag.subList(start, end) );
446 }
447
448 public String toString() {
449 read();
450 return bag.toString();
451 }
452
453 /*public boolean equals(Object other) {
454 read();
455 return bag.equals(other);
456 }
457
458 public int hashCode(Object other) {
459 read();
460 return bag.hashCode();
461 }*/
462
463 public boolean entryExists(Object entry, int i) {
464 return entry!=null;
465 }
466
467 /**
468 * Bag does not respect the collection API and do an
469 * JVM instance comparison to do the equals.
470 * The semantic is broken not to have to initialize a
471 * collection for a simple equals() operation.
472 * @see java.lang.Object#equals(java.lang.Object)
473 */
474 public boolean equals(Object obj) {
475 return super.equals(obj);
476 }
477
478 /**
479 * @see java.lang.Object#hashCode()
480 */
481 public int hashCode() {
482 return super.hashCode();
483 }
484
485 }