KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > query > NamedQuery


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.query;
21
22 import java.util.Arrays JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Map JavaDoc;
27
28 import org.apache.cayenne.CayenneRuntimeException;
29 import org.apache.cayenne.Persistent;
30 import org.apache.cayenne.map.EntityResolver;
31 import org.apache.cayenne.util.Util;
32 import org.apache.commons.lang.StringUtils;
33 import org.apache.commons.lang.builder.EqualsBuilder;
34 import org.apache.commons.lang.builder.HashCodeBuilder;
35
36 /**
37  * A query that is a reference to a named parameterized query stored in the mapping. The
38  * actual query is resolved during execution.
39  *
40  * @since 1.2
41  * @author Andrus Adamchik
42  */

43 public class NamedQuery extends IndirectQuery {
44
45     protected Map JavaDoc parameters;
46
47     protected boolean forceNoCache;
48
49     protected BaseQueryMetadata overrideMetadata;
50
51     // metadata fields...
52
transient int hashCode;
53
54     public NamedQuery(String JavaDoc name) {
55         this(name, null);
56     }
57
58     public NamedQuery(String JavaDoc name, Map JavaDoc parameters) {
59         this.name = name;
60
61         // copy parameters map (among other things to make hessian serilaization work).
62
if (parameters != null && !parameters.isEmpty()) {
63             this.parameters = new HashMap JavaDoc(parameters);
64         }
65     }
66
67     /**
68      * Creates NamedQuery with parameters passed as two matching arrays of keys and
69      * values.
70      */

71     public NamedQuery(String JavaDoc name, String JavaDoc[] keys, Object JavaDoc[] values) {
72         this.name = name;
73         this.parameters = Util.toMap(keys, values);
74     }
75
76     public QueryMetadata getMetaData(EntityResolver resolver) {
77
78         QueryMetadata base = overrideMetadata != null ? overrideMetadata : super
79                 .getMetaData(resolver);
80
81         QueryMetadataWrapper wrapper = new QueryMetadataWrapper(base);
82
83         // override cache policy, forcing refresh if needed
84
if (forceNoCache) {
85             String JavaDoc policy = base.getCachePolicy();
86
87             if (QueryMetadata.LOCAL_CACHE.equals(policy)) {
88                 wrapper.override(
89                         QueryMetadata.CACHE_POLICY_PROPERTY,
90                         QueryMetadata.LOCAL_CACHE_REFRESH);
91             }
92             else if (QueryMetadata.SHARED_CACHE.equals(policy)) {
93                 wrapper.override(
94                         QueryMetadata.CACHE_POLICY_PROPERTY,
95                         QueryMetadata.SHARED_CACHE_REFRESH);
96             }
97         }
98
99         // override cache key to include parameters
100
if (parameters != null
101                 && !parameters.isEmpty()
102                 && replacementQuery instanceof NamedQuery
103                 && base.getCacheKey() != null) {
104
105             // TODO: andrus, 3/29/2006 this is taken from SelectQuery...probably need a
106
// central place for converting parameters to a cache key
107

108             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(name);
109
110             if (parameters != null && !parameters.isEmpty()) {
111                 buffer.append(parameters.hashCode());
112             }
113
114             wrapper.override(QueryMetadataWrapper.CACHE_KEY_PROPERTY, buffer.toString());
115         }
116
117         return wrapper;
118     }
119
120     protected Query createReplacementQuery(EntityResolver resolver) {
121         Query query = resolveQuery(resolver);
122
123         if (query instanceof ParameterizedQuery) {
124             query = ((ParameterizedQuery) query).createQuery(normalizedParameters());
125         }
126
127         return query;
128     }
129
130     /**
131      * Returns a non-null parameter map, substituting all persistent objects in the
132      * initial map with ObjectIds. This is needed so that a query could work uniformly on
133      * the server and client sides.
134      */

135     Map JavaDoc normalizedParameters() {
136         if (parameters == null || parameters.isEmpty()) {
137             return Collections.EMPTY_MAP;
138         }
139
140         Map JavaDoc substitutes = new HashMap JavaDoc(parameters);
141
142         Iterator JavaDoc it = parameters.entrySet().iterator();
143         while (it.hasNext()) {
144             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
145
146             Object JavaDoc value = entry.getValue();
147
148             if (value instanceof Persistent) {
149                 value = ((Persistent) value).getObjectId();
150             }
151
152             substitutes.put(entry.getKey(), value);
153         }
154
155         return substitutes;
156     }
157
158     /**
159      * Returns a query for name, throwing an exception if such query is not mapped in the
160      * EntityResolver.
161      */

162     protected Query resolveQuery(EntityResolver resolver) {
163         Query query = resolver.lookupQuery(getName());
164
165         if (query == null) {
166             throw new CayenneRuntimeException("Can't find named query for name '"
167                     + getName()
168                     + "'");
169         }
170
171         if (query == this) {
172             throw new CayenneRuntimeException("Named query resolves to self: '"
173                     + getName()
174                     + "'");
175         }
176
177         return query;
178     }
179
180     /**
181      * Overrides toString() outputting a short string with query class and name.
182      */

183     public String JavaDoc toString() {
184         return StringUtils.substringAfterLast(getClass().getName(), ".")
185                 + ":"
186                 + getName();
187     }
188
189     /**
190      * Initializes metadata overrides. Needed to store the metadata for the remote query
191      * proxies that have no access to the actual query.
192      */

193     public void initMetadata(QueryMetadata metadata) {
194         if (metadata != null) {
195             this.overrideMetadata = new BaseQueryMetadata();
196             this.overrideMetadata.copyFromInfo(metadata);
197         }
198         else {
199             this.overrideMetadata = null;
200         }
201     }
202
203     /**
204      * An object is considered equal to this NamedQuery if it is a NamedQuery with the
205      * same queryName and same parameters.
206      */

207     public boolean equals(Object JavaDoc object) {
208         if (this == object) {
209             return true;
210         }
211
212         if (!(object instanceof NamedQuery)) {
213             return false;
214         }
215
216         NamedQuery query = (NamedQuery) object;
217
218         if (!Util.nullSafeEquals(name, query.getName())) {
219             return false;
220         }
221
222         if (query.parameters == null && parameters == null) {
223             return true;
224         }
225
226         if (query.parameters == null || parameters == null) {
227             return false;
228         }
229
230         if (query.parameters.size() != parameters.size()) {
231             return false;
232         }
233
234         EqualsBuilder builder = new EqualsBuilder();
235         Iterator JavaDoc entries = parameters.entrySet().iterator();
236         while (entries.hasNext()) {
237             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) entries.next();
238             Object JavaDoc entryKey = entry.getKey();
239             Object JavaDoc entryValue = entry.getValue();
240
241             if (entryValue == null) {
242                 if (query.parameters.get(entryKey) != null
243                         || !query.parameters.containsKey(entryKey)) {
244                     return false;
245                 }
246             }
247             else {
248                 // takes care of comparing primitive arrays, such as byte[]
249
builder.append(entryValue, query.parameters.get(entryKey));
250                 if (!builder.isEquals()) {
251                     return false;
252                 }
253             }
254         }
255
256         return true;
257     }
258
259     /**
260      * Implements a standard hashCode contract considering custom 'equals' implementation.
261      */

262     public int hashCode() {
263
264         if (this.hashCode == 0) {
265
266             HashCodeBuilder builder = new HashCodeBuilder(13, 17);
267
268             if (name != null) {
269                 builder.append(name.hashCode());
270             }
271
272             if (parameters != null) {
273                 Object JavaDoc[] keys = parameters.keySet().toArray();
274                 Arrays.sort(keys);
275
276                 for (int i = 0; i < keys.length; i++) {
277                     // HashCodeBuilder will take care of processing object if it
278
// happens to be a primitive array such as byte[]
279
builder.append(keys[i]).append(parameters.get(keys[i]));
280                 }
281
282             }
283
284             this.hashCode = builder.toHashCode();
285             assert hashCode != 0 : "Generated zero hashCode";
286         }
287
288         return hashCode;
289     }
290
291     public boolean isForceNoCache() {
292         return forceNoCache;
293     }
294
295     public void setForceNoCache(boolean forcingNoCache) {
296         this.forceNoCache = forcingNoCache;
297     }
298 }
299
Popular Tags