KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.access;
21
22 import java.io.Serializable JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.LinkedList JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.ListIterator JavaDoc;
28
29 import org.apache.cayenne.CayenneRuntimeException;
30 import org.apache.cayenne.PersistenceState;
31 import org.apache.cayenne.Persistent;
32 import org.apache.cayenne.ValueHolder;
33 import org.apache.cayenne.query.RelationshipQuery;
34
35 /**
36  * A list that holds objects for to-many relationships. All operations, except for
37  * resolving the list from DB, are not synchronized. The safest way to implement custom
38  * synchronization is to synchronize on parent ObjectStore.
39  *
40  * @author Andrus Adamchik
41  */

42 public class ToManyList implements List JavaDoc, Serializable JavaDoc, ValueHolder {
43
44     private Persistent source;
45     private String JavaDoc relationship;
46
47     // wrapped objects list
48
List JavaDoc objectList;
49
50     // track additions/removals in unresolved...
51
LinkedList JavaDoc addedToUnresolved;
52     LinkedList JavaDoc removedFromUnresolved;
53
54     /**
55      * Creates ToManyList.
56      *
57      * @since 1.1
58      */

59     public ToManyList(Persistent source, String JavaDoc relationship) {
60         if (source == null) {
61             throw new NullPointerException JavaDoc("'source' can't be null.");
62         }
63
64         if (relationship == null) {
65             throw new NullPointerException JavaDoc("'relationship' can't be null.");
66         }
67
68         this.source = source;
69         this.relationship = relationship;
70
71         // if source is new, set object list right away
72
if (isTransientSource()) {
73             objectList = new LinkedList JavaDoc();
74         }
75     }
76
77     /**
78      * @since 1.2
79      */

80     public Persistent getRelationshipOwner() {
81         return source;
82     }
83
84     /**
85      * Returns a name of relationship for this list.
86      *
87      * @since 1.1
88      */

89     public String JavaDoc getRelationship() {
90         return relationship;
91     }
92
93     public void setObjectList(List JavaDoc objectList) {
94         this.objectList = objectList;
95     }
96
97     public Object JavaDoc getValue() throws CayenneRuntimeException {
98         return resolvedObjectList();
99     }
100
101     public void invalidate() {
102         this.objectList = null;
103     }
104
105     public boolean isFault() {
106         return objectList == null;
107     }
108
109     public Object JavaDoc getValueDirectly() throws CayenneRuntimeException {
110         return objectList;
111     }
112
113     public Object JavaDoc setValueDirectly(Object JavaDoc value) throws CayenneRuntimeException {
114         if (value == null || value instanceof List JavaDoc) {
115             Object JavaDoc old = this.objectList;
116             setObjectList((List JavaDoc) value);
117             return old;
118         }
119         else {
120             throw new CayenneRuntimeException("Value must be a list, got: "
121                     + value.getClass().getName());
122         }
123     }
124
125     public Object JavaDoc setValue(Object JavaDoc value) throws CayenneRuntimeException {
126         resolvedObjectList();
127         return setValueDirectly(objectList);
128     }
129
130     // ====================================================
131
// Standard List Methods.
132
// ====================================================
133
public boolean add(Object JavaDoc o) {
134         return (isFault()) ? addLocal(o) : objectList.add(o);
135     }
136
137     public void add(int index, Object JavaDoc element) {
138         resolvedObjectList().add(index, element);
139     }
140
141     public boolean addAll(Collection JavaDoc c) {
142         return resolvedObjectList().addAll(c);
143     }
144
145     public boolean addAll(int index, Collection JavaDoc c) {
146         return resolvedObjectList().addAll(index, c);
147     }
148
149     public void clear() {
150         resolvedObjectList().clear();
151     }
152
153     public boolean contains(Object JavaDoc o) {
154         return resolvedObjectList().contains(o);
155     }
156
157     public boolean containsAll(Collection JavaDoc c) {
158         return resolvedObjectList().containsAll(c);
159     }
160
161     public boolean equals(Object JavaDoc o) {
162         if (o == null) {
163             return false;
164         }
165
166         if (!(o instanceof ToManyList)) {
167             return false;
168         }
169
170         return resolvedObjectList().equals(((ToManyList) o).resolvedObjectList());
171     }
172
173     public int hashCode() {
174         return 15 + resolvedObjectList().hashCode();
175     }
176
177     public Object JavaDoc get(int index) {
178         return resolvedObjectList().get(index);
179     }
180
181     public int indexOf(Object JavaDoc o) {
182         return resolvedObjectList().indexOf(o);
183     }
184
185     public boolean isEmpty() {
186         return resolvedObjectList().isEmpty();
187     }
188
189     public Iterator JavaDoc iterator() {
190         return resolvedObjectList().iterator();
191     }
192
193     public int lastIndexOf(Object JavaDoc o) {
194         return resolvedObjectList().lastIndexOf(o);
195     }
196
197     public ListIterator JavaDoc listIterator() {
198         return resolvedObjectList().listIterator();
199     }
200
201     public ListIterator JavaDoc listIterator(int index) {
202         return resolvedObjectList().listIterator(index);
203     }
204
205     public Object JavaDoc remove(int index) {
206         return resolvedObjectList().remove(index);
207     }
208
209     public boolean remove(Object JavaDoc o) {
210         return (isFault()) ? removeLocal(o) : objectList.remove(o);
211     }
212
213     public boolean removeAll(Collection JavaDoc c) {
214         return resolvedObjectList().removeAll(c);
215     }
216
217     public boolean retainAll(Collection JavaDoc c) {
218         return resolvedObjectList().retainAll(c);
219     }
220
221     public Object JavaDoc set(int index, Object JavaDoc element) {
222         return resolvedObjectList().set(index, element);
223     }
224
225     public int size() {
226         return resolvedObjectList().size();
227     }
228
229     public List JavaDoc subList(int fromIndex, int toIndex) {
230         return resolvedObjectList().subList(fromIndex, toIndex);
231     }
232
233     public Object JavaDoc[] toArray() {
234         return resolvedObjectList().toArray();
235     }
236
237     public Object JavaDoc[] toArray(Object JavaDoc[] a) {
238         return resolvedObjectList().toArray(a);
239     }
240
241     // ====================================================
242
// Tracking list modifications, and resolving it
243
// on demand
244
// ====================================================
245

246     boolean isTransientSource() {
247         int state = source.getPersistenceState();
248         return state == PersistenceState.NEW || state == PersistenceState.TRANSIENT;
249     }
250
251     boolean isUncommittedSource() {
252         int state = source.getPersistenceState();
253         return state == PersistenceState.MODIFIED || state == PersistenceState.DELETED;
254     }
255
256     /**
257      * Returns internal objects list resolving it if needed.
258      */

259     List JavaDoc resolvedObjectList() {
260         if (isFault()) {
261
262             synchronized (this) {
263                 // now that we obtained the lock, check
264
// if another thread just resolved the list
265

266                 if (isFault()) {
267                     List JavaDoc localList;
268
269                     if (isTransientSource()) {
270                         localList = new LinkedList JavaDoc();
271                     }
272                     else {
273                         localList = source.getObjectContext().performQuery(
274                                 new RelationshipQuery(
275                                         source.getObjectId(),
276                                         relationship,
277                                         false));
278                     }
279
280                     mergeLocalChanges(localList);
281                     this.objectList = localList;
282                 }
283             }
284         }
285
286         return objectList;
287     }
288
289     void clearLocalChanges() {
290         addedToUnresolved = null;
291         removedFromUnresolved = null;
292     }
293
294     void mergeLocalChanges(List JavaDoc fetchedList) {
295
296         // only merge if an object is in an uncommitted state
297
// any other state means that our local tracking
298
// is invalid...
299
if (isUncommittedSource()) {
300
301             if (removedFromUnresolved != null) {
302                 fetchedList.removeAll(removedFromUnresolved);
303             }
304
305             // add only those that are not already on the list
306
// do not include transient objects...
307
if (addedToUnresolved != null && !addedToUnresolved.isEmpty()) {
308                 Iterator JavaDoc it = addedToUnresolved.iterator();
309                 while (it.hasNext()) {
310                     Object JavaDoc next = it.next();
311
312                     if (next instanceof Persistent) {
313                         Persistent dataObject = (Persistent) next;
314                         if (dataObject.getPersistenceState() == PersistenceState.TRANSIENT) {
315                             continue;
316                         }
317                     }
318
319                     if (!fetchedList.contains(next)) {
320                         fetchedList.add(next);
321                     }
322                 }
323             }
324         }
325
326         // clear local information in any event
327
clearLocalChanges();
328     }
329
330     boolean addLocal(Object JavaDoc object) {
331
332         if (removedFromUnresolved != null) {
333             removedFromUnresolved.remove(object);
334         }
335
336         if (addedToUnresolved == null) {
337             addedToUnresolved = new LinkedList JavaDoc();
338         }
339
340         addedToUnresolved.addLast(object);
341
342         // this is really meaningless, since we don't know
343
// if an object was present in the list
344
return true;
345     }
346
347     boolean removeLocal(Object JavaDoc object) {
348         if (addedToUnresolved != null) {
349             addedToUnresolved.remove(object);
350         }
351
352         if (removedFromUnresolved == null) {
353             removedFromUnresolved = new LinkedList JavaDoc();
354         }
355
356         // No point in adding a new or transient object -- these will never be fetched
357
// from the database.
358
boolean shouldAddToRemovedFromUnresolvedList = true;
359         if (object instanceof Persistent) {
360             Persistent dataObject = (Persistent) object;
361             if ((dataObject.getPersistenceState() == PersistenceState.TRANSIENT)
362                     || (dataObject.getPersistenceState() == PersistenceState.NEW)) {
363                 shouldAddToRemovedFromUnresolvedList = false;
364             }
365         }
366
367         if (shouldAddToRemovedFromUnresolvedList) {
368             removedFromUnresolved.addLast(object);
369         }
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     public String JavaDoc toString() {
377         return getClass().getName() + "@" + System.identityHashCode(this);
378     }
379 }
380
Popular Tags