View Javadoc

1   /***
2    *  Copyright 2003-2010 Terracotta, Inc.
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.ehcache;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Set;
24  
25  import net.sf.ehcache.search.Attribute;
26  import net.sf.ehcache.search.Direction;
27  import net.sf.ehcache.search.Query;
28  import net.sf.ehcache.search.Results;
29  import net.sf.ehcache.search.SearchException;
30  import net.sf.ehcache.search.aggregator.Aggregator;
31  import net.sf.ehcache.search.aggregator.AggregatorException;
32  import net.sf.ehcache.search.aggregator.AggregatorInstance;
33  import net.sf.ehcache.search.expression.AlwaysMatch;
34  import net.sf.ehcache.search.expression.Criteria;
35  import net.sf.ehcache.store.StoreQuery;
36  
37  /***
38   * Query builder implementation. Instances are bound to a specific cache
39   *
40   * @author teck
41   */
42  class CacheQuery implements Query, StoreQuery {
43  
44      private volatile boolean frozen;
45      private volatile boolean includeKeys;
46      private volatile boolean includeValues;
47      private volatile int maxResults = -1;
48  
49      private final List<Ordering> orderings = Collections.synchronizedList(new ArrayList<Ordering>());
50      private final Set<Attribute<?>> includedAttributes = Collections.synchronizedSet(new HashSet<Attribute<?>>());
51      private final List<Criteria> criteria = Collections.synchronizedList(new ArrayList<Criteria>());
52      private final List<Aggregator> aggregators = Collections.synchronizedList(new ArrayList<Aggregator>());
53      private final Cache cache;
54  
55      /***
56       * Create a new builder instance
57       *
58       * @param cache
59       */
60      public CacheQuery(Cache cache) {
61          this.cache = cache;
62      }
63  
64      /***
65       * {@inheritDoc}
66       */
67      public Query includeKeys() {
68          checkFrozen();
69          this.includeKeys = true;
70          return this;
71      }
72  
73      /***
74       * {@inheritDoc}
75       */
76      public Query includeValues() {
77          checkFrozen();
78          this.includeValues = true;
79          return this;
80      }
81  
82      /***
83       * {@inheritDoc}
84       */
85      public Query includeAttribute(Attribute<?>... attributes) {
86          checkFrozen();
87  
88          if (attributes == null) {
89              throw new NullPointerException();
90          }
91  
92          for (Attribute<?> attribute : attributes) {
93              if (attribute == null) {
94                  throw new NullPointerException("null attribute");
95              }
96  
97              this.includedAttributes.add(attribute);
98          }
99  
100         return this;
101     }
102 
103     /***
104      * {@inheritDoc}
105      */
106     public Query includeAggregator(Aggregator... aggregators) throws SearchException, AggregatorException {
107         checkFrozen();
108 
109         if (aggregators == null) {
110             throw new NullPointerException();
111         }
112 
113         for (Aggregator aggregator : aggregators) {
114             if (aggregator == null) {
115                 throw new NullPointerException("null aggregator");
116             }
117 
118             this.aggregators.add(aggregator);
119         }
120 
121         return this;
122     }
123 
124     /***
125      * {@inheritDoc}
126      */
127     public Query addOrderBy(Attribute<?> attribute, Direction direction) {
128         checkFrozen();
129         this.orderings.add(new OrderingImpl(attribute, direction));
130         return this;
131     }
132 
133     /***
134      * {@inheritDoc}
135      */
136     public Query maxResults(int maxResults) {
137         checkFrozen();
138         this.maxResults = maxResults;
139         return this;
140     }
141 
142     /***
143      * {@inheritDoc}
144      */
145     public Query addCriteria(Criteria criteria) {
146         checkFrozen();
147 
148         if (criteria == null) {
149             throw new NullPointerException("null criteria");
150         }
151 
152         this.criteria.add(criteria);
153         return this;
154     }
155 
156     /***
157      * {@inheritDoc}
158      */
159     public Results execute() throws SearchException {
160         return cache.executeQuery(snapshot());
161     }
162 
163     /***
164      * {@inheritDoc}
165      */
166     public Query end() {
167         frozen = true;
168         return this;
169     }
170 
171     /***
172      * {@inheritDoc}
173      */
174     public List<Ordering> getOrdering() {
175         assertFrozen();
176         return Collections.unmodifiableList(orderings);
177     }
178 
179     /***
180      * {@inheritDoc}
181      */
182     public Criteria getCriteria() {
183         assertFrozen();
184         return getEffectiveCriteriaCopy();
185     }
186 
187     /***
188      * {@inheritDoc}
189      */
190     public boolean requestsKeys() {
191         assertFrozen();
192         return includeKeys;
193     }
194 
195     /***
196      * {@inheritDoc}
197      */
198     public boolean requestsValues() {
199         assertFrozen();
200         return includeValues;
201     }
202 
203     /***
204      * {@inheritDoc}
205      */
206     public Cache getCache() {
207         assertFrozen();
208         return cache;
209     }
210 
211     /***
212      * {@inheritDoc}
213      */
214     public Set<Attribute<?>> requestedAttributes() {
215         assertFrozen();
216         return Collections.unmodifiableSet(this.includedAttributes);
217     }
218 
219     /***
220      * {@inheritDoc}
221      */
222     public int maxResults() {
223         assertFrozen();
224         return maxResults;
225     }
226 
227     /***
228      * {@inheritDoc}
229      */
230     public List<AggregatorInstance<?>> getAggregatorInstances() {
231         assertFrozen();
232         return Collections.unmodifiableList(createAggregatorInstances(aggregators));
233     }
234 
235     private static List<AggregatorInstance<?>> createAggregatorInstances(List<Aggregator> aggregators) {
236         List<AggregatorInstance<?>> rv = new ArrayList<AggregatorInstance<?>>(aggregators.size());
237         for (Aggregator aggregator : aggregators) {
238             rv.add(aggregator.createInstance());
239         }
240 
241         return rv;
242     }
243 
244     private Criteria getEffectiveCriteriaCopy() {
245         Criteria result = new AlwaysMatch();
246         for (Criteria c : criteria) {
247           result = result.and(c);
248         }
249         return result;
250     }
251 
252     private void assertFrozen() {
253         if (!frozen) {
254             throw new AssertionError("not frozen");
255         }
256     }
257 
258     private StoreQuery snapshot() {
259         if (frozen) {
260             return this;
261         }
262 
263         return new StoreQueryImpl();
264     }
265 
266     private void checkFrozen() {
267         if (frozen) {
268             throw new SearchException("Query is frozen and cannot be mutated");
269         }
270     }
271 
272     /***
273      * StoreQuery implementation (essentially a snapshot of this (non-frozen) query builder
274      */
275     private class StoreQueryImpl implements StoreQuery {
276         private final Criteria copiedCriteria = CacheQuery.this.getEffectiveCriteriaCopy();
277         private final boolean copiedIncludeKeys = includeKeys;
278         private final boolean copiedIncludeValues = includeValues;
279         private final Set<Attribute<?>> copiedAttributes = Collections.unmodifiableSet(new HashSet<Attribute<?>>(includedAttributes));
280         private final int copiedMaxResults = maxResults;
281         private final List<Ordering> copiedOrdering = Collections.unmodifiableList(new ArrayList<Ordering>(orderings));
282         private final List<AggregatorInstance<?>> copiedAggregators = Collections.unmodifiableList(createAggregatorInstances(aggregators));
283 
284         public Criteria getCriteria() {
285             return copiedCriteria;
286         }
287 
288         public boolean requestsKeys() {
289             return copiedIncludeKeys;
290         }
291 
292         public boolean requestsValues() {
293             return copiedIncludeValues;
294         }
295 
296         public Cache getCache() {
297             return cache;
298         }
299 
300         public Set<Attribute<?>> requestedAttributes() {
301             return copiedAttributes;
302         }
303 
304         public int maxResults() {
305             return copiedMaxResults;
306         }
307 
308         public List<Ordering> getOrdering() {
309             return copiedOrdering;
310         }
311 
312         public List<AggregatorInstance<?>> getAggregatorInstances() {
313             return copiedAggregators;
314         }
315     }
316 
317     /***
318      * An attribute/direction pair
319      */
320     private static class OrderingImpl implements Ordering {
321 
322         private final Attribute<?> attribute;
323         private final Direction direction;
324 
325         public OrderingImpl(Attribute<?> attribute, Direction direction) {
326             if ((attribute == null) || (direction == null)) {
327                 throw new NullPointerException();
328             }
329 
330             this.attribute = attribute;
331             this.direction = direction;
332         }
333 
334         public Attribute<?> getAttribute() {
335             return attribute;
336         }
337 
338         public Direction getDirection() {
339             return direction;
340         }
341     }
342 
343 }