KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > util > PersistentObjectList


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.util;
21
22 import java.util.Collection JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.LinkedList JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.ListIterator JavaDoc;
27
28 import org.apache.cayenne.CayenneRuntimeException;
29 import org.apache.cayenne.PersistenceState;
30 import org.apache.cayenne.Persistent;
31 import org.apache.cayenne.ValueHolder;
32
33 /**
34  * A list of persistent objects lazily resolved on the first access.
35  *
36  * @since 1.2
37  * @author Andrus Adamchik
38  */

39 public class PersistentObjectList extends RelationshipFault implements List JavaDoc, ValueHolder {
40
41     // wrapped objects list
42
protected List JavaDoc objectList;
43
44     // track additions/removals in unresolved...
45
protected LinkedList JavaDoc addedToUnresolved;
46     protected LinkedList JavaDoc removedFromUnresolved;
47
48     // exists for the benefit of manual serialization schemes such as the one in Hessian.
49
private PersistentObjectList() {
50
51     }
52
53     /**
54      * Creates PersistentObjectList initializing it with list owner persistent object and
55      * relationship name that this list maps to.
56      *
57      * @param relationshipOwner persistent object that owns this list.
58      * @param relationshipName a query used to resolve the list
59      */

60     public PersistentObjectList(Persistent relationshipOwner, String JavaDoc relationshipName) {
61         super(relationshipOwner, relationshipName);
62     }
63
64     /**
65      * Returns whether this list is not yet resolved and requires a fetch.
66      */

67     public boolean isFault() {
68
69         if (objectList != null) {
70             return false;
71         }
72         // resolve on the fly if owner is transient... Can't do it in constructor, as
73
// object may be in an inconsistent state during construction time
74
// synchronize??
75
else if (isTransientParent()) {
76             objectList = new LinkedList JavaDoc();
77             return false;
78         }
79         else {
80             return true;
81         }
82     }
83
84     /**
85      * Turns itself into a fault, thus forcing a refresh on the next access.
86      */

87     public void invalidate() {
88         setObjectList(null);
89     }
90
91     public Object JavaDoc setValueDirectly(Object JavaDoc value) throws CayenneRuntimeException {
92         if (value == null || value instanceof List JavaDoc) {
93             Object JavaDoc old = this.objectList;
94             setObjectList((List JavaDoc) value);
95             return old;
96         }
97         else {
98             throw new CayenneRuntimeException("Value must be a list, got: "
99                     + value.getClass().getName());
100         }
101     }
102
103     public Object JavaDoc getValue() throws CayenneRuntimeException {
104         return resolvedObjectList();
105     }
106
107     public Object JavaDoc getValueDirectly() throws CayenneRuntimeException {
108         return objectList;
109     }
110
111     public Object JavaDoc setValue(Object JavaDoc value) throws CayenneRuntimeException {
112         resolvedObjectList();
113         return setValueDirectly(objectList);
114     }
115
116     public void setObjectList(List JavaDoc objectList) {
117         this.objectList = objectList;
118     }
119
120     // ====================================================
121
// Standard List Methods.
122
// ====================================================
123

124     public boolean add(Object JavaDoc o) {
125         if ((isFault()) ? addLocal(o) : objectList.add(o)) {
126             postprocessAdd(o);
127             return true;
128         }
129
130         return false;
131     }
132
133     public void add(int index, Object JavaDoc o) {
134         resolvedObjectList().add(index, o);
135         postprocessAdd(o);
136     }
137
138     public boolean addAll(Collection JavaDoc c) {
139         if (resolvedObjectList().addAll(c)) {
140             // TODO: here we assume that all objects were added, while addAll may
141
// technically return true and add only some objects... need a smarter
142
// approach (maybe use "contains" in postprocessAdd"?)
143
postprocessAdd(c);
144
145             return true;
146         }
147
148         return false;
149     }
150
151     public boolean addAll(int index, Collection JavaDoc c) {
152         if (resolvedObjectList().addAll(index, c)) {
153             // TODO: here we assume that all objects were added, while addAll may
154
// technically return true and add only some objects... need a smarter
155
// approach (maybe use "contains" in postprocessAdd"?)
156
postprocessAdd(c);
157
158             return true;
159         }
160
161         return false;
162     }
163
164     public void clear() {
165         List JavaDoc resolved = resolvedObjectList();
166         postprocessRemove(resolved);
167         resolved.clear();
168     }
169
170     public boolean contains(Object JavaDoc o) {
171         return resolvedObjectList().contains(o);
172     }
173
174     public boolean containsAll(Collection JavaDoc c) {
175         return resolvedObjectList().containsAll(c);
176     }
177
178     public boolean equals(Object JavaDoc o) {
179         if (o == null) {
180             return false;
181         }
182
183         if (!(o instanceof PersistentObjectList)) {
184             return false;
185         }
186
187         return resolvedObjectList().equals(
188                 ((PersistentObjectList) o).resolvedObjectList());
189     }
190
191     public int hashCode() {
192         return 37 + resolvedObjectList().hashCode();
193     }
194
195     public Object JavaDoc get(int index) {
196         return resolvedObjectList().get(index);
197     }
198
199     public int indexOf(Object JavaDoc o) {
200         return resolvedObjectList().indexOf(o);
201     }
202
203     public boolean isEmpty() {
204         return resolvedObjectList().isEmpty();
205     }
206
207     public Iterator JavaDoc iterator() {
208         return resolvedObjectList().iterator();
209     }
210
211     public int lastIndexOf(Object JavaDoc o) {
212         return resolvedObjectList().lastIndexOf(o);
213     }
214
215     public ListIterator JavaDoc listIterator() {
216         return resolvedObjectList().listIterator();
217     }
218
219     public ListIterator JavaDoc listIterator(int index) {
220         return resolvedObjectList().listIterator(index);
221     }
222
223     public Object JavaDoc remove(int index) {
224         Object JavaDoc removed = resolvedObjectList().remove(index);
225         postprocessRemove(removed);
226         return removed;
227     }
228
229     public boolean remove(Object JavaDoc o) {
230         if ((isFault()) ? removeLocal(o) : objectList.remove(o)) {
231             postprocessRemove(o);
232             return true;
233         }
234
235         return false;
236     }
237
238     public boolean removeAll(Collection JavaDoc c) {
239         if (resolvedObjectList().removeAll(c)) {
240             // TODO: here we assume that all objects were removed, while removeAll may
241
// technically return true and remove only some objects... need a smarter
242
// approach
243
postprocessRemove(c);
244             return true;
245         }
246
247         return false;
248     }
249
250     public boolean retainAll(Collection JavaDoc c) {
251         // TODO: handle object graoh change notifications on object removals...
252
return resolvedObjectList().retainAll(c);
253     }
254
255     public Object JavaDoc set(int index, Object JavaDoc o) {
256         Object JavaDoc oldValue = resolvedObjectList().set(index, o);
257
258         postprocessAdd(o);
259         postprocessRemove(oldValue);
260
261         return oldValue;
262     }
263
264     public int size() {
265         return resolvedObjectList().size();
266     }
267
268     public List JavaDoc subList(int fromIndex, int toIndex) {
269         // TODO: should we wrap a sublist into a list that does notifications on
270
// additions/removals?
271
return resolvedObjectList().subList(fromIndex, toIndex);
272     }
273
274     public Object JavaDoc[] toArray() {
275         return resolvedObjectList().toArray();
276     }
277
278     public Object JavaDoc[] toArray(Object JavaDoc[] a) {
279         return resolvedObjectList().toArray(a);
280     }
281
282     // ====================================================
283
// Tracking list modifications, and resolving it
284
// on demand
285
// ====================================================
286

287     /**
288      * Returns internal objects list resolving it if needed.
289      */

290     protected List JavaDoc resolvedObjectList() {
291         if (isFault()) {
292
293             synchronized (this) {
294
295                 // now that we obtained the lock, check
296
// if another thread just resolved the list
297
if (isFault()) {
298                     List JavaDoc localList = resolveFromDB();
299
300                     mergeLocalChanges(localList);
301                     this.objectList = localList;
302                 }
303             }
304         }
305
306         return objectList;
307     }
308
309     void clearLocalChanges() {
310         addedToUnresolved = null;
311         removedFromUnresolved = null;
312     }
313
314     void mergeLocalChanges(List JavaDoc fetchedList) {
315
316         // only merge if an object is in an uncommitted state
317
// any other state means that our local tracking
318
// is invalid...
319
if (isUncommittedParent()) {
320
321             if (removedFromUnresolved != null) {
322                 fetchedList.removeAll(removedFromUnresolved);
323             }
324
325             // add only those that are not already on the list
326
// do not include transient objects...
327
if (addedToUnresolved != null && !addedToUnresolved.isEmpty()) {
328                 Iterator JavaDoc it = addedToUnresolved.iterator();
329                 while (it.hasNext()) {
330                     Object JavaDoc next = it.next();
331
332                     if (next instanceof Persistent) {
333                         Persistent dataObject = (Persistent) next;
334                         if (dataObject.getPersistenceState() == PersistenceState.TRANSIENT) {
335                             continue;
336                         }
337                     }
338
339                     if (!fetchedList.contains(next)) {
340                         fetchedList.add(next);
341                     }
342                 }
343             }
344         }
345
346         // clear local information in any event
347
clearLocalChanges();
348     }
349
350     boolean addLocal(Object JavaDoc object) {
351
352         if (removedFromUnresolved != null) {
353             removedFromUnresolved.remove(object);
354         }
355
356         if (addedToUnresolved == null) {
357             addedToUnresolved = new LinkedList JavaDoc();
358         }
359
360         addedToUnresolved.addLast(object);
361
362         // this is really meaningless, since we don't know
363
// if an object was present in the list
364
return true;
365     }
366
367     boolean removeLocal(Object JavaDoc object) {
368         if (addedToUnresolved != null) {
369             addedToUnresolved.remove(object);
370         }
371
372         if (removedFromUnresolved == null) {
373             removedFromUnresolved = new LinkedList JavaDoc();
374         }
375
376         removedFromUnresolved.addLast(object);
377
378         // this is really meaningless, since we don't know
379
// if an object was present in the list
380
return true;
381     }
382
383     void postprocessAdd(Collection JavaDoc collection) {
384         Iterator JavaDoc it = collection.iterator();
385         while (it.hasNext()) {
386             postprocessAdd(it.next());
387         }
388     }
389
390     void postprocessRemove(Collection JavaDoc collection) {
391         Iterator JavaDoc it = collection.iterator();
392         while (it.hasNext()) {
393             postprocessRemove(it.next());
394         }
395     }
396
397     void postprocessAdd(Object JavaDoc addedObject) {
398
399         // notify ObjectContext
400
if (relationshipOwner.getObjectContext() != null) {
401             relationshipOwner.getObjectContext().propertyChanged(
402                     relationshipOwner,
403                     relationshipName,
404                     null,
405                     addedObject);
406         }
407     }
408
409     void postprocessRemove(Object JavaDoc removedObject) {
410
411         // notify ObjectContext
412
if (relationshipOwner.getObjectContext() != null) {
413             relationshipOwner.getObjectContext().propertyChanged(
414                     relationshipOwner,
415                     relationshipName,
416                     removedObject,
417                     null);
418         }
419     }
420
421     public String JavaDoc toString() {
422         return (objectList != null) ? objectList.toString() : "[<unresolved>]";
423     }
424 }
425
Popular Tags