KickJava   Java API By Example, From Geeks To Geeks.

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


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.ArrayList JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25
26 import org.apache.cayenne.ObjectContext;
27 import org.apache.cayenne.ObjectId;
28 import org.apache.cayenne.PersistenceState;
29 import org.apache.cayenne.Persistent;
30 import org.apache.cayenne.QueryResponse;
31 import org.apache.cayenne.cache.QueryCache;
32 import org.apache.cayenne.cache.QueryCacheEntryFactory;
33 import org.apache.cayenne.query.ObjectIdQuery;
34 import org.apache.cayenne.query.Query;
35 import org.apache.cayenne.query.QueryMetadata;
36 import org.apache.cayenne.query.RelationshipQuery;
37 import org.apache.cayenne.reflect.ArcProperty;
38 import org.apache.cayenne.reflect.ClassDescriptor;
39
40 /**
41  * A helper class that implements
42  * {@link org.apache.cayenne.DataChannel#onQuery(ObjectContext, Query)} logic on behalf of
43  * an ObjectContext.
44  * <p>
45  * <i>Intended for internal use only.</i>
46  * </p>
47  *
48  * @since 1.2
49  * @author Andrus Adamchik
50  */

51 public abstract class ObjectContextQueryAction {
52
53     protected static final boolean DONE = true;
54
55     protected ObjectContext targetContext;
56     protected ObjectContext actingContext;
57     protected Query query;
58     protected QueryMetadata metadata;
59
60     protected transient QueryResponse response;
61
62     public ObjectContextQueryAction(ObjectContext actingContext,
63             ObjectContext targetContext, Query query) {
64
65         this.actingContext = actingContext;
66         this.query = query;
67
68         // no special target context and same target context as acting context mean the
69
// same thing. "normalize" the internal state to avoid confusion
70
this.targetContext = targetContext != actingContext ? targetContext : null;
71         this.metadata = query.getMetaData(actingContext.getEntityResolver());
72     }
73
74     /**
75      * Worker method that perfomrs internal query.
76      */

77     public QueryResponse execute() {
78
79         if (interceptOIDQuery() != DONE) {
80             if (interceptRelationshipQuery() != DONE) {
81                 if (interceptLocalCache() != DONE) {
82                     runQuery();
83                 }
84             }
85         }
86
87         interceptObjectConversion();
88
89         return response;
90     }
91
92     /**
93      * Transfers fetched objects into the target context if it is different from "acting"
94      * context. Note that when this method is invoked, result objects are already
95      * registered with acting context by the parent channel.
96      */

97     protected void interceptObjectConversion() {
98
99         if (targetContext != null && !metadata.isFetchingDataRows()) {
100
101             // rewrite response to contain objects from the query context
102

103             GenericResponse childResponse = new GenericResponse();
104
105             for (response.reset(); response.next();) {
106                 if (response.isList()) {
107
108                     List JavaDoc objects = response.currentList();
109                     if (objects.isEmpty()) {
110                         childResponse.addResultList(objects);
111                     }
112                     else {
113
114                         // TODO: Andrus 1/31/2006 - IncrementalFaultList is not properly
115
// transferred between contexts....
116

117                         List JavaDoc childObjects = new ArrayList JavaDoc(objects.size());
118                         Iterator JavaDoc it = objects.iterator();
119                         while (it.hasNext()) {
120                             Persistent object = (Persistent) it.next();
121                             childObjects.add(targetContext.localObject(object
122                                     .getObjectId(), object));
123                         }
124
125                         childResponse.addResultList(childObjects);
126                     }
127                 }
128                 else {
129                     childResponse.addBatchUpdateCount(response.currentUpdateCount());
130                 }
131             }
132
133             response = childResponse;
134         }
135
136     }
137
138     protected boolean interceptOIDQuery() {
139         if (query instanceof ObjectIdQuery) {
140             ObjectIdQuery oidQuery = (ObjectIdQuery) query;
141
142             if (!oidQuery.isFetchMandatory() && !oidQuery.isFetchingDataRows()) {
143                 Object JavaDoc object = actingContext.getGraphManager().getNode(
144                         oidQuery.getObjectId());
145                 if (object != null) {
146                     
147                     // do not return hollow objects
148
if (((Persistent) object).getPersistenceState() == PersistenceState.HOLLOW) {
149                         return !DONE;
150                     }
151
152                     this.response = new ListResponse(object);
153                     return DONE;
154                 }
155             }
156         }
157
158         return !DONE;
159     }
160
161     protected boolean interceptRelationshipQuery() {
162
163         if (query instanceof RelationshipQuery) {
164             RelationshipQuery relationshipQuery = (RelationshipQuery) query;
165             if (!relationshipQuery.isRefreshing()) {
166
167                 // don't intercept to-many relationships if fetch is done to the same
168
// context as the root context of this action - this will result in an
169
// infinite loop.
170

171                 if (targetContext == null
172                         && relationshipQuery.getRelationship(
173                                 actingContext.getEntityResolver()).isToMany()) {
174                     return !DONE;
175                 }
176
177                 ObjectId id = relationshipQuery.getObjectId();
178                 Object JavaDoc object = actingContext.getGraphManager().getNode(id);
179
180                 if (object != null) {
181
182                     ClassDescriptor descriptor = actingContext
183                             .getEntityResolver()
184                             .getClassDescriptor(id.getEntityName());
185
186                     if (!descriptor.isFault(object)) {
187
188                         ArcProperty property = (ArcProperty) descriptor
189                                 .getProperty(relationshipQuery.getRelationshipName());
190
191                         if (!property.isFault(object)) {
192
193                             Object JavaDoc related = property.readPropertyDirectly(object);
194
195                             List JavaDoc result;
196
197                             // null to-one
198
if (related == null) {
199                                 result = new ArrayList JavaDoc(1);
200                             }
201                             // to-many
202
else if (related instanceof List JavaDoc) {
203                                 result = (List JavaDoc) related;
204                             }
205                             // non-null to-one
206
else {
207                                 result = new ArrayList JavaDoc(1);
208                                 result.add(related);
209                             }
210
211                             this.response = new ListResponse(result);
212                             return DONE;
213
214                         }
215                     }
216                 }
217             }
218         }
219
220         return !DONE;
221     }
222
223     /**
224      * @since 3.0
225      */

226     protected boolean interceptLocalCache() {
227
228         if (metadata.getCacheKey() == null) {
229             return !DONE;
230         }
231
232         boolean cache = QueryMetadata.LOCAL_CACHE.equals(metadata.getCachePolicy());
233         boolean cacheOrCacheRefresh = cache
234                 || QueryMetadata.LOCAL_CACHE_REFRESH.equals(metadata.getCachePolicy());
235
236         if (!cacheOrCacheRefresh) {
237             return !DONE;
238         }
239
240         QueryCache queryCache = getQueryCache();
241         QueryCacheEntryFactory factory = getCacheObjectFactory();
242
243         if (cache) {
244             List JavaDoc cachedResults = queryCache.get(metadata, factory);
245
246             // response may already be initialized by the factory above ... it is null if
247
// there was a preexisting cache entry
248
if (response == null) {
249                 response = new ListResponse(cachedResults);
250             }
251         }
252         else {
253             // on cache-refresh request, fetch without blocking and fill the cache
254
queryCache.put(metadata, (List JavaDoc) factory.createObject());
255         }
256
257         return DONE;
258     }
259
260     /**
261      * @since 3.0
262      */

263     protected abstract QueryCache getQueryCache();
264
265     /**
266      * @since 3.0
267      */

268     protected QueryCacheEntryFactory getCacheObjectFactory() {
269         return new QueryCacheEntryFactory() {
270
271             public Object JavaDoc createObject() {
272                 runQuery();
273                 return response.firstList();
274             }
275         };
276     }
277
278     /**
279      * Fetches data from the channel.
280      */

281     protected void runQuery() {
282         this.response = actingContext.getChannel().onQuery(actingContext, query);
283     }
284 }
285
Popular Tags