View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  
22  
23  package org.opencastproject.elasticsearch.impl;
24  
25  import static java.util.Objects.requireNonNull;
26  import static org.opencastproject.elasticsearch.api.SearchTerms.Quantifier.Any;
27  
28  import org.opencastproject.elasticsearch.api.SearchQuery;
29  import org.opencastproject.elasticsearch.api.SearchTerms;
30  import org.opencastproject.elasticsearch.api.SearchTerms.Quantifier;
31  import org.opencastproject.util.requests.SortCriterion.Order;
32  
33  import org.apache.commons.lang3.StringUtils;
34  
35  import java.util.ArrayList;
36  import java.util.Arrays;
37  import java.util.Collection;
38  import java.util.Collections;
39  import java.util.LinkedHashMap;
40  import java.util.List;
41  import java.util.Map;
42  
43  /**
44   * Base implementation for search queries.
45   */
46  public abstract class AbstractSearchQuery implements SearchQuery {
47  
48    /** The document types */
49    protected List<String> types = new ArrayList<>();
50  
51    /** The list of fields to return */
52    protected List<String> fields = null;
53  
54    /** True if the search text should be matched using wildcards */
55    protected boolean fuzzySearch = true;
56  
57    /** Query terms */
58    protected List<SearchTerms<String>> text = null;
59  
60    /** Filter terms */
61    protected String filter = null;
62  
63    /** The query offset */
64    protected int offset = -1;
65  
66    /** The query limit */
67    protected int limit = -1;
68  
69    /** The map with the sort orders */
70    private final Map<String, Order> sortOrders = new LinkedHashMap<String, Order>();
71  
72    /**
73     * Creates a search query that is executed on all document types.
74     */
75    protected AbstractSearchQuery() {
76      // Nothing to be done atm.
77    }
78  
79    /**
80     * Creates a search query that is executed on the given document type.
81     *
82     * @param documentType
83     *          the document type
84     */
85    public AbstractSearchQuery(String documentType) {
86      this();
87      if (StringUtils.isNotBlank(documentType)) {
88        this.types.add(documentType);
89      }
90    }
91  
92    @Override
93    public SearchQuery withTypes(String... types) {
94      this.types.addAll(Arrays.asList(types));
95      return this;
96    }
97  
98    @Override
99    public String[] getTypes() {
100     return types.toArray(new String[0]);
101   }
102 
103   @Override
104   public AbstractSearchQuery withField(String field) {
105     if (fields == null) {
106       fields = new ArrayList<>();
107     }
108     fields.add(field);
109     return this;
110   }
111 
112   @Override
113   public AbstractSearchQuery withFields(String... fields) {
114     for (String field : fields) {
115       withField(field);
116     }
117     return this;
118   }
119 
120   @Override
121   public String[] getFields() {
122     if (fields == null) {
123       return new String[] {};
124     }
125     return fields.toArray(new String[0]);
126   }
127 
128   @Override
129   public SearchQuery withLimit(int limit) {
130     this.limit = limit;
131     return this;
132   }
133 
134   @Override
135   public int getLimit() {
136     return limit;
137   }
138 
139   @Override
140   public SearchQuery withOffset(int offset) {
141     this.offset = Math.max(0, offset);
142     return this;
143   }
144 
145   @Override
146   public int getOffset() {
147     return offset;
148   }
149 
150   @Override
151   public SearchQuery withText(String text) {
152     return withText(true, Any, text);
153   }
154 
155   @Override
156   public SearchQuery withText(boolean fuzzy, String text) {
157     return withText(fuzzy, Any, text);
158   }
159 
160   @Override
161   public SearchQuery withText(boolean fuzzy, Quantifier quantifier, String... text) {
162     if (quantifier == null) {
163       throw new IllegalArgumentException("Quantifier must not be null");
164     }
165     if (text == null) {
166       throw new IllegalArgumentException("Text must not be null");
167     }
168 
169     // Make sure the collection is initialized
170     if (this.text == null) {
171       this.text = new ArrayList<>();
172     }
173 
174     // Add the text to the search terms
175     this.fuzzySearch = fuzzy;
176 
177     // Handle any quantifier
178     if (text.length == 1 || Any.equals(quantifier)) {
179       SearchTerms<String> terms = null;
180 
181       // Check if there is a default terms collection
182       for (SearchTerms<String> t : this.text) {
183         if (Quantifier.Any.equals(t.getQuantifier())) {
184           terms = t;
185           break;
186         }
187       }
188 
189       // Has there been a default terms collection?
190       if (terms == null) {
191         terms = new SearchTermsImpl<>(Quantifier.Any, text);
192         this.text.add(terms);
193       }
194 
195     // All quantifier
196     } else {
197       this.text.add(new SearchTermsImpl<>(quantifier, text));
198     }
199     return this;
200   }
201 
202   @Override
203   public Collection<SearchTerms<String>> getTerms() {
204     if (text == null) {
205       return Collections.emptyList();
206     }
207     return text;
208   }
209 
210   @Override
211   public String getQueryString() {
212     if (text == null) {
213       return null;
214     }
215     StringBuilder query = new StringBuilder();
216     for (SearchTerms<String> s : text) {
217       for (String t : s.getTerms()) {
218         if (query.isEmpty()) {
219           query.append(" ");
220         }
221         query.append(t);
222       }
223     }
224     return query.toString();
225   }
226 
227   @Override
228   public boolean isFuzzySearch() {
229     return fuzzySearch;
230   }
231 
232   @Override
233   public SearchQuery withFilter(String filter) {
234     this.filter = filter;
235     return this;
236   }
237 
238   @Override
239   public String getFilter() {
240     return filter;
241   }
242 
243   @Override
244   public SearchQuery withSortOrder(String field, Order order) {
245     sortOrders.put(requireNonNull(sortOrderFieldName(field)), requireNonNull(order));
246     return this;
247   }
248 
249   @Override
250   public Map<String, Order> getSortOrders() {
251     return Collections.unmodifiableMap(sortOrders);
252   }
253 
254   @Override
255   public Order getSortOrder(String field) {
256     String sortField = sortOrderFieldName(field);
257     if (!sortOrders.containsKey(sortField)) {
258       return Order.None;
259     }
260 
261     return sortOrders.get(sortField);
262   }
263 
264   protected abstract String sortOrderFieldName(String field);
265 
266 }