KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.ArrayList JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Map JavaDoc;
27
28 import org.apache.cayenne.CayenneRuntimeException;
29 import org.apache.cayenne.Fault;
30 import org.apache.cayenne.Persistent;
31 import org.apache.cayenne.ValueHolder;
32 import org.apache.cayenne.query.PrefetchTreeNode;
33 import org.apache.cayenne.reflect.ArcProperty;
34 import org.apache.cayenne.reflect.ToOneProperty;
35
36 /**
37  * A specialized PrefetchTreeNode used for disjoint prefetch resolving.
38  *
39  * @since 1.2
40  * @author Andrus Adamchik
41  */

42 // TODO: Andrus 2/9/2006 optional to-one relationships (Painting -> Artist) are not
43
// connected by this algorithm. They are being intercepted later when a corresponding
44
// fault is being resolved, but this seems like a wasteful approach. Test case that
45
// succeeds, but goes through this wasteful route is
46
// DataContextPrefetchTst.testPrefetchingToOneNull().
47
class PrefetchProcessorNode extends PrefetchTreeNode {
48
49     List JavaDoc dataRows;
50     List JavaDoc objects;
51
52     ArcProperty incoming;
53     ObjectResolver resolver;
54
55     Map JavaDoc partitionByParent;
56     boolean jointChildren;
57     boolean partitionedByParent;
58
59     Persistent lastResolved;
60
61     PrefetchProcessorNode(PrefetchTreeNode parent, String JavaDoc segmentPath) {
62         super(parent, segmentPath);
63     }
64
65     /**
66      * Sets up derived flags and values for faster lookup during traversal. Called after
67      * all properties are initialized.
68      */

69     void afterInit() {
70
71         partitionedByParent = !phantom
72                 && incoming != null
73                 && incoming.getRelationship().isSourceIndependentFromTargetChange();
74
75         if (partitionedByParent) {
76             partitionByParent = new HashMap JavaDoc();
77         }
78     }
79
80     /**
81      * Creates a temporary association between child and parent objects. Permanent
82      * relationship is set using the information created here, by calling
83      * 'connectToParents'.
84      */

85     void linkToParent(Persistent object, Persistent parent) {
86         if (parent != null) {
87
88             // if a relationship is to-one (i.e. flattened to-one), can connect right
89
// away.... write directly to prevent changing persistence state.
90
if (incoming instanceof ToOneProperty) {
91                 incoming.writePropertyDirectly(parent, null, object);
92             }
93             else {
94
95                 List JavaDoc peers = (List JavaDoc) partitionByParent.get(parent);
96
97                 // wrap in a list even if relationship is to-one... will unwrap at the end
98
// of the processing cycle.
99
if (peers == null) {
100                     peers = new ArrayList JavaDoc();
101                     partitionByParent.put(parent, peers);
102                 }
103                 // checking for duplicates is needed in case of nested joint prefetches
104
// when there is more than one row with the same combination of adjacent
105
// parent and child...
106
else if (peers.contains(object)) {
107                     return;
108                 }
109
110                 peers.add(object);
111             }
112         }
113     }
114
115     void connectToParents() {
116
117         // to-one's were connected earlier...
118
if (isPartitionedByParent()) {
119
120             // depending on whether parent is a "phantom" node,
121
// use different strategy
122

123             PrefetchProcessorNode parent = (PrefetchProcessorNode) getParent();
124             boolean parentObjectsExist = parent.getObjects() != null
125                     && parent.getObjects().size() > 0;
126             if (incoming.getRelationship().isToMany()) {
127                 if (parentObjectsExist) {
128                     connectToNodeParents(parent.getObjects());
129                 }
130                 else {
131                     connectToFaultedParents();
132                 }
133             }
134             else {
135                 // optional to-one ... need to fill in unresolved relationships with
136
// null...
137
if (parentObjectsExist) {
138                     clearNullRelationships(parent.getObjects());
139                 }
140             }
141         }
142     }
143
144     private final void clearNullRelationships(List JavaDoc parentObjects) {
145         Iterator JavaDoc it = parentObjects.iterator();
146         while (it.hasNext()) {
147             Object JavaDoc object = it.next();
148             if (incoming.readPropertyDirectly(object) instanceof Fault) {
149                 incoming.writeProperty(object, null, null);
150             }
151         }
152     }
153
154     private final void connectToNodeParents(List JavaDoc parentObjects) {
155
156         Iterator JavaDoc it = parentObjects.iterator();
157         while (it.hasNext()) {
158             Persistent object = (Persistent) it.next();
159             List JavaDoc related = (List JavaDoc) partitionByParent.get(object);
160             connect(object, related);
161         }
162     }
163
164     private final void connectToFaultedParents() {
165         Iterator JavaDoc it = partitionByParent.entrySet().iterator();
166         while (it.hasNext()) {
167             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
168
169             Persistent object = (Persistent) entry.getKey();
170             List JavaDoc related = (List JavaDoc) entry.getValue();
171             connect(object, related);
172         }
173     }
174
175     private final void connect(Persistent object, List JavaDoc related) {
176         if (incoming.getRelationship().isToMany()) {
177             ValueHolder toManyList = (ValueHolder) incoming.readProperty(object);
178
179             // TODO, Andrus 11/15/2005 - if list is modified, shouldn't we attempt to
180
// merge the changes instead of overwriting?
181
toManyList.setValueDirectly(related != null ? related : new ArrayList JavaDoc(1));
182         }
183         else {
184             // this should've been handled elsewhere
185
throw new CayenneRuntimeException(
186                     "To-one relationship wasn't handled properly: " + incoming.getName());
187         }
188     }
189
190     List JavaDoc getDataRows() {
191         return dataRows;
192     }
193
194     List JavaDoc getObjects() {
195         return objects;
196     }
197
198     void setResolver(ObjectResolver resolver) {
199         this.resolver = resolver;
200     }
201
202     ObjectResolver getResolver() {
203         return resolver;
204     }
205
206     ArcProperty getIncoming() {
207         return incoming;
208     }
209
210     void setIncoming(ArcProperty incoming) {
211         this.incoming = incoming;
212     }
213
214     void setDataRows(List JavaDoc dataRows) {
215         this.dataRows = dataRows;
216     }
217
218     void setObjects(List JavaDoc objects) {
219         this.objects = objects;
220     }
221
222     boolean isJointChildren() {
223         return jointChildren;
224     }
225
226     void setJointChildren(boolean jointChildren) {
227         this.jointChildren = jointChildren;
228     }
229
230     boolean isPartitionedByParent() {
231         return partitionedByParent;
232     }
233
234     Persistent getLastResolved() {
235         return lastResolved;
236     }
237
238     void setLastResolved(Persistent lastResolved) {
239         this.lastResolved = lastResolved;
240     }
241 }
242
Popular Tags