KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > access > ToManyList


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56
57 package org.objectstyle.cayenne.access;
58
59 import java.io.Serializable JavaDoc;
60 import java.util.Collection JavaDoc;
61 import java.util.Iterator JavaDoc;
62 import java.util.LinkedList JavaDoc;
63 import java.util.List JavaDoc;
64 import java.util.ListIterator JavaDoc;
65
66 import org.objectstyle.cayenne.CayenneRuntimeException;
67 import org.objectstyle.cayenne.DataObject;
68 import org.objectstyle.cayenne.PersistenceState;
69 import org.objectstyle.cayenne.query.RelationshipQuery;
70
71 /**
72  * A list that holds objects for to-many relationships. All operations, except for
73  * resolving the list from DB, are not synchronized. The safest way to implement custom
74  * synchronization is to synchronize on parent ObjectStore.
75  *
76  * <p><i>For more information see <a HREF="../../../../../../userguide/index.html"
77  * target="_top">Cayenne User Guide.</a></i></p>
78  *
79  * @author Andrei Adamchik
80  */

81 public class ToManyList implements List JavaDoc, Serializable JavaDoc {
82     private DataObject source;
83     private String JavaDoc relationship;
84
85     // wrapped objects list
86
List JavaDoc objectList;
87
88     // track additions/removals in unresolved...
89
LinkedList JavaDoc addedToUnresolved;
90     LinkedList JavaDoc removedFromUnresolved;
91
92     /**
93      * Creates ToManyList.
94      *
95      * @since 1.1
96      */

97     public ToManyList(DataObject source, String JavaDoc relationship) {
98         if (source == null) {
99             throw new NullPointerException JavaDoc("'source' can't be null.");
100         }
101
102         if (relationship == null) {
103             throw new NullPointerException JavaDoc("'relationship' can't be null.");
104         }
105
106         this.source = source;
107         this.relationship = relationship;
108
109         // if source is new, set object list right away
110
if (isTransientSource()) {
111             objectList = new LinkedList JavaDoc();
112         }
113     }
114
115     /**
116      * Returns a source object of this relationship.
117      *
118      * @since 1.1
119      */

120     public DataObject getSource() {
121         return source;
122     }
123
124     /**
125      * Returns a name of relationship for this list.
126      *
127      * @since 1.1
128      */

129     public String JavaDoc getRelationship() {
130         return relationship;
131     }
132
133     /**
134      * Returns whether this list is not yet resolved and requires a fetch.
135      */

136     public boolean needsFetch() {
137         return objectList == null;
138     }
139
140     /**
141      * Will force refresh on the next access.
142      */

143     public void invalidateObjectList() {
144         setObjectList(null);
145     }
146
147     public void setObjectList(List JavaDoc objectList) {
148         this.objectList = objectList;
149     }
150
151     // ====================================================
152
// Standard List Methods.
153
// ====================================================
154

155     public boolean add(Object JavaDoc o) {
156         return (needsFetch()) ? addLocal(o) : objectList.add(o);
157     }
158
159     public void add(int index, Object JavaDoc element) {
160         resolvedObjectList().add(index, element);
161     }
162
163     public boolean addAll(Collection JavaDoc c) {
164         return resolvedObjectList().addAll(c);
165     }
166
167     public boolean addAll(int index, Collection JavaDoc c) {
168         return resolvedObjectList().addAll(index, c);
169     }
170
171     public void clear() {
172         resolvedObjectList().clear();
173     }
174
175     public boolean contains(Object JavaDoc o) {
176         return resolvedObjectList().contains(o);
177     }
178
179     public boolean containsAll(Collection JavaDoc c) {
180         return resolvedObjectList().containsAll(c);
181     }
182
183     public boolean equals(Object JavaDoc o) {
184         if (o == null) {
185             return false;
186         }
187
188         if (!(o instanceof ToManyList)) {
189             return false;
190         }
191
192         return resolvedObjectList().equals(((ToManyList) o).resolvedObjectList());
193     }
194
195     public int hashCode() {
196         return 15 + resolvedObjectList().hashCode();
197     }
198
199     public Object JavaDoc get(int index) {
200         return resolvedObjectList().get(index);
201     }
202
203     public int indexOf(Object JavaDoc o) {
204         return resolvedObjectList().indexOf(o);
205     }
206
207     public boolean isEmpty() {
208         return resolvedObjectList().isEmpty();
209     }
210
211     public Iterator JavaDoc iterator() {
212         return resolvedObjectList().iterator();
213     }
214
215     public int lastIndexOf(Object JavaDoc o) {
216         return resolvedObjectList().lastIndexOf(o);
217     }
218
219     public ListIterator JavaDoc listIterator() {
220         return resolvedObjectList().listIterator();
221     }
222
223     public ListIterator JavaDoc listIterator(int index) {
224         return resolvedObjectList().listIterator(index);
225     }
226
227     public Object JavaDoc remove(int index) {
228         return resolvedObjectList().remove(index);
229     }
230
231     public boolean remove(Object JavaDoc o) {
232         return (needsFetch()) ? removeLocal(o) : objectList.remove(o);
233     }
234
235     public boolean removeAll(Collection JavaDoc c) {
236         return resolvedObjectList().removeAll(c);
237     }
238
239     public boolean retainAll(Collection JavaDoc c) {
240         return resolvedObjectList().retainAll(c);
241     }
242
243     public Object JavaDoc set(int index, Object JavaDoc element) {
244         return resolvedObjectList().set(index, element);
245     }
246
247     public int size() {
248         return resolvedObjectList().size();
249     }
250
251     public List JavaDoc subList(int fromIndex, int toIndex) {
252         return resolvedObjectList().subList(fromIndex, toIndex);
253     }
254
255     public Object JavaDoc[] toArray() {
256         return resolvedObjectList().toArray();
257     }
258
259     public Object JavaDoc[] toArray(Object JavaDoc[] a) {
260         return resolvedObjectList().toArray(a);
261     }
262
263     // ====================================================
264
// Tracking list modifications, and resolving it
265
// on demand
266
// ====================================================
267

268     boolean isTransientSource() {
269         int state = source.getPersistenceState();
270         return state == PersistenceState.NEW || state == PersistenceState.TRANSIENT;
271     }
272
273     boolean isUncommittedSource() {
274         int state = source.getPersistenceState();
275         return state == PersistenceState.MODIFIED || state == PersistenceState.DELETED;
276     }
277
278     /**
279      * Returns internal objects list resolving it if needed.
280      */

281     List JavaDoc resolvedObjectList() {
282         if (needsFetch()) {
283
284             synchronized (this) {
285                 // now that we obtained the lock, check
286
// if another thread just resolved the list
287

288                 if (needsFetch()) {
289                     List JavaDoc localList;
290
291                     if (isTransientSource()) {
292                         localList = new LinkedList JavaDoc();
293                     }
294                     else {
295                         if (source.getObjectId().isTemporary()) {
296                             throw new CayenneRuntimeException(
297                                     "Can't resolve relationship for temporary id: "
298                                             + source.getObjectId());
299                         }
300
301                         RelationshipQuery query = new RelationshipQuery(
302                                 source,
303                                 relationship);
304
305                         localList = source.getDataContext().performQuery(query);
306                     }
307
308                     mergeLocalChanges(localList);
309                     this.objectList = localList;
310                 }
311             }
312         }
313
314         return objectList;
315     }
316
317     void clearLocalChanges() {
318         addedToUnresolved = null;
319         removedFromUnresolved = null;
320     }
321
322     void mergeLocalChanges(List JavaDoc fetchedList) {
323
324         // only merge if an object is in an uncommitted state
325
// any other state means that our local tracking
326
// is invalid...
327
if (isUncommittedSource()) {
328
329             if (removedFromUnresolved != null) {
330                 fetchedList.removeAll(removedFromUnresolved);
331             }
332
333             // add only those that are not already on the list
334
// do not include transient objects...
335
if (addedToUnresolved != null && !addedToUnresolved.isEmpty()) {
336                 Iterator JavaDoc it = addedToUnresolved.iterator();
337                 while (it.hasNext()) {
338                     Object JavaDoc next = it.next();
339
340                     if (next instanceof DataObject) {
341                         DataObject dataObject = (DataObject) next;
342                         if (dataObject.getPersistenceState()
343                             == PersistenceState.TRANSIENT) {
344                             continue;
345                         }
346                     }
347
348                     if (!fetchedList.contains(next)) {
349                         fetchedList.add(next);
350                     }
351                 }
352             }
353         }
354
355         // clear local information in any event
356
clearLocalChanges();
357     }
358
359     boolean addLocal(Object JavaDoc object) {
360
361         if (removedFromUnresolved != null) {
362             removedFromUnresolved.remove(object);
363         }
364
365         if (addedToUnresolved == null) {
366             addedToUnresolved = new LinkedList JavaDoc();
367         }
368
369         addedToUnresolved.addLast(object);
370
371         // this is really meaningless, since we don't know
372
// if an object was present in the list
373
return true;
374     }
375
376     boolean removeLocal(Object JavaDoc object) {
377         if (addedToUnresolved != null) {
378             addedToUnresolved.remove(object);
379         }
380
381         if (removedFromUnresolved == null) {
382             removedFromUnresolved = new LinkedList JavaDoc();
383         }
384
385         removedFromUnresolved.addLast(object);
386
387         // this is really meaningless, since we don't know
388
// if an object was present in the list
389
return true;
390     }
391 }
392
Popular Tags