View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.services.fieldquery;
20  
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.List;
24  import java.util.stream.Collectors;
25  
26  import org.apache.logging.log4j.LogManager;
27  import org.apache.logging.log4j.Logger;
28  import org.jdom2.Document;
29  import org.jdom2.Element;
30  import org.mycore.parsers.bool.MCRCondition;
31  
32  /** Represents a query with its condition and optional parameters */
33  public class MCRQuery {
34  
35      private static final Logger LOGGER = LogManager.getLogger(MCRQuery.class);
36  
37      /** The query condition */
38      private MCRCondition<Void> cond;
39  
40      /** The maximum number of results, default is 0 = unlimited */
41      private int maxResults = 0;
42  
43      /** The number of results per page, default is 10 */
44      private int numPerPage = 10;
45  
46      /** A list of MCRSortBy criteria, may be empty */
47      private List<MCRSortBy> sortBy = new ArrayList<>();
48  
49      /** A List of SOLR fields they should be return in the response */
50      private List<String> returnFields = new ArrayList<>();
51  
52      /** A cached xml representation of the query */
53      private Document doc = null;
54  
55      /**
56       * Builds a new MCRQuery object without sort criteria and unlimited results.
57       * 
58       * @param cond
59       *            the query conditions
60       */
61      public MCRQuery(MCRCondition<Void> cond) {
62          this.cond = MCRQueryParser.normalizeCondition(cond);
63      }
64  
65      /**
66       * Builds a new MCRQuery object with sort criteria and limited number of
67       * results.
68       * 
69       * @param cond
70       *            the query conditions
71       * @param sortBy
72       *            a list of MCRSortBy criteria for sorting the results
73       * @param maxResults
74       *            the maximum number of results to return
75       * @param returnFields
76       *            the return fields for the SOLR parameter fl
77       */
78      public MCRQuery(MCRCondition<Void> cond, List<MCRSortBy> sortBy, int maxResults, List<String> returnFields) {
79          this.cond = MCRQueryParser.normalizeCondition(cond);
80          this.setSortBy(sortBy);
81          setMaxResults(maxResults);
82          this.setReturnFields(returnFields);
83      }
84  
85      /**
86       * Returns the query condition
87       * 
88       * @return the query condition
89       */
90      public MCRCondition<Void> getCondition() {
91          return cond;
92      }
93  
94      /**
95       * Returns the maximum number of results the query should return
96       * 
97       * @return the maximum number of results, or 0
98       */
99      public int getMaxResults() {
100         return maxResults;
101     }
102 
103     /**
104      * Sets the maximum number of results the query should return. Default is 0
105      * which means "return all results".
106      * 
107      * @param maxResults
108      *            the maximum number of results
109      */
110     public void setMaxResults(int maxResults) {
111         if (maxResults < 0) {
112             this.maxResults = 0;
113         } else {
114             this.maxResults = maxResults;
115         }
116         doc = null;
117     }
118 
119     /**
120      * Sets the maximum number of results the query should return. Default is 0
121      * which means "return all results".
122      * 
123      * @param maxResultsString
124      *            the maximum number of results as String
125      */
126     public void setMaxResults(String maxResultsString) {
127         doc = null;
128         if (maxResultsString == null || maxResultsString.length() == 0) {
129             this.maxResults = 0;
130             return;
131         }
132         try {
133             this.maxResults = Integer.parseInt(maxResultsString);
134         } catch (NumberFormatException e) {
135             LOGGER.warn("The Results maxstring " + maxResultsString + " contains not an integer, 0 as default is set");
136             this.maxResults = 0;
137         }
138     }
139 
140     /**
141      * Returns the number of results per page that the query should return
142      * 
143      * @return the number of results per page
144      */
145     public int getNumPerPage() {
146         return numPerPage;
147     }
148 
149     /**
150      * Sets the number of results per page that the query should return. Default is 10.
151      * 
152      * @param numPerPage
153      *            the number of results per page
154      */
155     public void setNumPerPage(int numPerPage) {
156         if (numPerPage < 0) {
157             this.numPerPage = 10;
158         } else {
159             this.numPerPage = numPerPage;
160         }
161         doc = null;
162     }
163 
164     /**
165      * Sets the number of results per page that the query should return. Default is 10.
166      * 
167      * @param numPerPageString
168      *            the number of results per page as String
169      */
170     public void setNumPerPage(String numPerPageString) {
171         doc = null;
172         if (numPerPageString == null || numPerPageString.length() == 0) {
173             this.numPerPage = 10;
174             return;
175         }
176         try {
177             this.numPerPage = Integer.parseInt(numPerPageString);
178         } catch (NumberFormatException e) {
179             LOGGER.warn("The numPerPage string " + numPerPageString + " contains not an integer, 10 as default is set");
180             this.numPerPage = 10;
181         }
182     }
183 
184     /**
185      * Returns the list of MCRSortBy criteria for sorting query results
186      * 
187      * @return a list of MCRSortBy objects, may be empty
188      */
189     public List<MCRSortBy> getSortBy() {
190         return sortBy;
191     }
192 
193     /**
194      * Sets the sort criteria for the query results
195      * 
196      * @param sortBy
197      *            a list of MCRSortBy objects, may be empty
198      */
199     public void setSortBy(List<MCRSortBy> sortBy) {
200         if (sortBy == null) {
201             sortBy = new ArrayList<>();
202         }
203         this.sortBy = sortBy;
204         doc = null;
205     }
206 
207     /**
208      * Sets the sort criteria for the query results
209      * 
210      * @param sortBy
211      *            a MCRSortBy object
212      */
213     public void setSortBy(MCRSortBy sortBy) {
214         this.sortBy = new ArrayList<>();
215         if (sortBy != null) {
216             this.sortBy.add(sortBy);
217         }
218         doc = null;
219     }
220 
221     /**
222      * Returns the list of SOLR-fields they should return for a query
223      * results
224      * 
225      * @return a list of field names, may be empty
226      */
227     public List<String> getReturnFields() {
228         return returnFields;
229     }
230 
231     /**
232      * Returns the CSV-list of SOLR-fields they should return for a query
233      * results
234      * 
235      * @return a list of field names, may be empty
236      */
237     public String getReturnFieldsAsString() {
238         return returnFields.stream().collect(Collectors.joining(","));
239     }
240 
241     /**
242      * Sets the return fields list for the query results
243      * 
244      * @param returnFields
245      *            a list of SOLR return fields, may be empty
246      */
247     public void setReturnFields(List<String> returnFields) {
248         this.returnFields = returnFields == null ? new ArrayList<>() : returnFields;
249     }
250 
251     /**
252      * Sets the return fields as String for the query results
253      * 
254      * @param returnFields
255      *            a CSV-list of SOLR return fields, may be empty
256      */
257     public void setReturnFields(String returnFields) {
258         if (returnFields == null || returnFields.length() == 0) {
259             this.returnFields = new ArrayList<>();
260             return;
261         }
262         this.returnFields = Arrays.asList(returnFields.split(","));
263     }
264 
265     /**
266      * Builds a XML representation of the query
267      * 
268      * @return a XML document containing all query parameters
269      */
270     public synchronized Document buildXML() {
271         if (doc == null) {
272             Element query = new Element("query");
273             query.setAttribute("maxResults", String.valueOf(maxResults));
274             query.setAttribute("numPerPage", String.valueOf(numPerPage));
275 
276             if (sortBy != null && sortBy.size() > 0) {
277                 Element sortByElem = new Element("sortBy");
278                 query.addContent(sortByElem);
279                 for (MCRSortBy sb : sortBy) {
280                     Element ref = new Element("field");
281                     ref.setAttribute("name", sb.getFieldName());
282                     ref.setAttribute("order", sb.getSortOrder() ? "ascending" : "descending");
283                     sortByElem.addContent(ref);
284                 }
285             }
286 
287             if (returnFields != null && returnFields.size() > 0) {
288                 Element returns = new Element("returnFields");
289                 returns.setText(returnFields.stream().collect(Collectors.joining(",")));
290                 query.addContent(returns);
291             }
292 
293             Element conditions = new Element("conditions");
294             query.addContent(conditions);
295             conditions.setAttribute("format", "xml");
296             conditions.addContent(cond.toXML());
297             doc = new Document(query);
298         }
299         return doc;
300     }
301 
302     /**
303      * Parses a XML representation of a query.
304      * 
305      * @param doc
306      *            the XML document
307      * @return the parsed MCRQuery
308      */
309     public static MCRQuery parseXML(Document doc) {
310         Element xml = doc.getRootElement();
311         Element conditions = xml.getChild("conditions");
312         MCRQuery query = null;
313         if (conditions.getAttributeValue("format", "xml").equals("xml")) {
314             Element condElem = conditions.getChildren().get(0);
315             query = new MCRQuery(new MCRQueryParser().parse(condElem));
316         } else {
317             String queryString = conditions.getTextTrim();
318             query = new MCRQuery(new MCRQueryParser().parse(queryString));
319         }
320 
321         String max = xml.getAttributeValue("maxResults", "");
322         query.setMaxResults(max);
323         String num = xml.getAttributeValue("numPerPage", "");
324         query.setNumPerPage(num);
325 
326         List<MCRSortBy> sortBy = null;
327         Element sortByElem = xml.getChild("sortBy");
328 
329         if (sortByElem != null) {
330             List<Element> children = sortByElem.getChildren();
331             sortBy = new ArrayList<>(children.size());
332 
333             for (Element sortByChild : children) {
334                 String name = sortByChild.getAttributeValue("name");
335                 String ad = sortByChild.getAttributeValue("order");
336 
337                 boolean direction = "ascending".equals(ad) ? MCRSortBy.ASCENDING : MCRSortBy.DESCENDING;
338                 sortBy.add(new MCRSortBy(name, direction));
339             }
340         }
341 
342         if (sortBy != null) {
343             query.setSortBy(sortBy);
344         }
345 
346         Element returns = xml.getChild("returnFields");
347         if (returns != null) {
348             query.setReturnFields(returns.getText());
349         }
350 
351         return query;
352     }
353 }