Bugfixes to compound filter and limit settings
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / mkjsf / pazpar2 / commands / SearchCommand.java
1 package com.indexdata.mkjsf.pazpar2.commands;\r
2 \r
3 import java.util.Arrays;\r
4 import java.util.List;\r
5 \r
6 import javax.enterprise.context.SessionScoped;\r
7 import javax.inject.Named;\r
8 \r
9 import org.apache.log4j.Logger;\r
10 \r
11 import com.indexdata.mkjsf.pazpar2.Pz2Service;\r
12 import com.indexdata.mkjsf.pazpar2.commands.sp.SearchCommandSp;\r
13 import com.indexdata.mkjsf.pazpar2.commands.sp.ServiceProxyCommand;\r
14 import com.indexdata.mkjsf.pazpar2.data.ResponseDataObject;\r
15 \r
16 /**\r
17  * <b><code>search</code></b> Pazpar2 command, referenced as: <code>pzreq.search</code> \r
18  * \r
19  * @author Niels Erik\r
20  *\r
21  */\r
22 @SessionScoped @Named\r
23 public class SearchCommand extends Pazpar2Command implements ServiceProxyCommand {\r
24   \r
25   private static final long serialVersionUID = -1888520867838597236L;\r
26   private static Logger logger = Logger.getLogger(SearchCommand.class);  \r
27     \r
28   public SearchCommand() {\r
29     super("search");\r
30   }\r
31   \r
32   public ResponseDataObject run() {\r
33     logger.info("Running " + getCommandName());\r
34     Pz2Service.get().getStateMgr().hasPendingStateChange("search",false);\r
35     Pz2Service.get().getPzresp().resetSearchAndBeyond();\r
36     Pz2Service.get().getPzreq().getRecord().removeParametersInState();        \r
37     Pz2Service.get().getPzreq().getShow().setParameterInState(new CommandParameter("start","=",0));    \r
38     Pz2Service.get().getSearchClient().setSearchCommand(this);\r
39     return super.run();\r
40   }\r
41 \r
42   /**\r
43    * Sets the <code>query</code> parameter. See Pazpar2 documentation for details.\r
44    */  \r
45   public void setQuery(String query) {    \r
46     setParameter(new QueryParameter("query","=",query));\r
47   }\r
48   \r
49   public void setBooleanOperatorForQuery(String operator) {\r
50     Pazpar2Command copy = this.copy();\r
51     ((QueryParameter) getParameter("query")).setBooleanOperator(operator);\r
52     checkInState(copy);\r
53   }\r
54   \r
55   /** \r
56    * Returns the simple part of the <code>query</code> parameter value, excluding parts that \r
57    * were added as expressions (that is, not set with <code>setQuery()</code>).\r
58    */\r
59   public String getQuery () {    \r
60     return getParameter("query") == null ? null  : ((QueryParameter)getParameter("query")).getSimpleValue();\r
61   }\r
62 \r
63   /** \r
64    * Returns the complete <code>query</code> parameter value, including expressions.\r
65    */\r
66   public String getExtendedQuery () {    \r
67     return getParameter("query") == null ? null  : ((QueryParameter)getParameter("query")).getValueWithExpressions();\r
68   }\r
69     \r
70   /**\r
71    * Sets the <code>filter</code> parameter. See Pazpar2 documentation for details.\r
72    */  \r
73   public void setFilter(String compoundExpression) {\r
74     if (getParameter("filter") != null) removeParameterInState("filter");\r
75     if (compoundExpression != null && compoundExpression.length()>0) {      \r
76       // Split expression by commas that are not escaped with backslash\r
77       String[] subExpressions = compoundExpression.split("(?<!\\\\),");\r
78       for (int i=0; i<subExpressions.length; i++) {\r
79         if (i==0) {\r
80           setParameterInState(new FilterParameter(new Expression(subExpressions[i])));\r
81         } else {\r
82           addExpressionInState("filter",new Expression(subExpressions[i]));\r
83         }\r
84       }\r
85     }\r
86     checkInState(this);\r
87   }\r
88   \r
89   /**\r
90    * Sets the <code>filter</code> parameter. See Pazpar2 documentation for details.\r
91    */  \r
92   public void setFilter(String field, String operator, String value, String label) {\r
93     setParameter(new FilterParameter(new Expression(field,operator,value,label)));\r
94   }\r
95 \r
96   /**\r
97    * Checks if there are any filter expressions matching any of the given expressionFields\r
98    * @param expressionFields expression fields (left-of-operator entities) to look for\r
99    * @return true if expression(s) found with any of <code>expressionFields</code> \r
100    */\r
101   public boolean hasFilterExpression(String... expressionFields) {\r
102     logger.trace("Checking for filter expression for " + Arrays.deepToString(expressionFields));\r
103     for (String field : expressionFields) {\r
104       if (getFilterExpressions(field) != null && getFilterExpressions(field).size()>0) {\r
105         logger.trace("Filter expression found (" + field + ")");\r
106         return true;\r
107       }  \r
108     }\r
109     logger.trace("No filter expressions found");\r
110     return false;\r
111   }\r
112 \r
113   \r
114   /** \r
115    * Returns the <code>filter</code> parameter value.\r
116    */\r
117   public String getFilter() {\r
118     return getParameter("filter") == null ? null : ((FilterParameter)getParameter("filter")).getValueWithExpressions();\r
119   }\r
120   \r
121   /**\r
122    * Returns the first filter expression of the given type\r
123    * @param expressionField expression field (left-of-operator entity) to look for\r
124    * @return the first filter expression found with the field <code>expressionField</code> or null if none found \r
125    */\r
126   public Expression getOneFilterExpression(String expressionField) {\r
127     List<Expression> exprs = getFilterExpressions(expressionField);\r
128     if (exprs != null && exprs.size()>0) {\r
129       if (exprs.size()>1) {\r
130         logger.warn("More that one filter expression found for [" + expressionField + "] but only asked to return the first one");\r
131       }\r
132       return exprs.get(0);\r
133     } else {\r
134       return null;\r
135     }    \r
136   }\r
137 \r
138   \r
139   /**\r
140    * Returns list of all filter expressions \r
141    */\r
142   public List<Expression> getFilterExpressions() {\r
143     return getParameter("filter").getExpressions();\r
144   }\r
145     \r
146   \r
147   public List<Expression> getFilterExpressions(String... expressionFields) {\r
148     logger.trace("Checking for filter parameter");\r
149     if (parameters.get("filter")!=null) {\r
150       logger.trace("Found");\r
151       return getParameter("filter").getExpressions(expressionFields);\r
152     } else {\r
153       logger.trace("Not found");\r
154       return null;\r
155     }\r
156   }\r
157   \r
158   public boolean hasFilter () {\r
159     return getFilter().length()>0;\r
160   }\r
161 \r
162   /**\r
163    * Adds a filter expression with a label for display. The filter is added to the end\r
164    * of an ordered list.  \r
165    * \r
166    * @param field\r
167    * @param operator\r
168    * @param value\r
169    * @param label\r
170    */\r
171   public void addFilter(String field, String operator, String value, String label) {\r
172     if (getParameter("filter") == null) {\r
173       setFilter(field + operator + value);\r
174     } else {\r
175       addExpression("filter",new Expression(field,operator,value,(label != null ? label : value)));\r
176     }\r
177   }\r
178 \r
179   /**\r
180    * Clears the filter parameter\r
181    */\r
182   public void removeFilters () {\r
183     removeParameter("filter");\r
184   }\r
185 \r
186   /**\r
187    * Removes a filter expression by exact attributes\r
188    * \r
189    * @param field\r
190    * @param operator\r
191    * @param value\r
192    */\r
193   public void removeFilter(String field, String operator, String value) {\r
194     removeExpression("filter",new Expression(field, operator, value, null));\r
195   }\r
196   \r
197   /**\r
198    * Removes all filter expressions matching a field listed in <code>fieldsToRemove</code>\r
199    * @param fieldsToRemove\r
200    */\r
201   public void removeFilters(String... fieldsToRemove) {    \r
202     removeExpressions("filter",fieldsToRemove);    \r
203   }  \r
204 \r
205   /**\r
206    * Removes filter expressions coming after the expression matching the provided filter expression, \r
207    * if they have a field listed in <code>fieldsToRemove</code>. To be used for bread crumb like UI \r
208    * controls.\r
209    * \r
210    * @param field\r
211    * @param operator\r
212    * @param value\r
213    * @param fieldsToRemove\r
214    */\r
215   public void removeFiltersAfter(String field, String operator, String value, String... fieldsToRemove) {     \r
216     removeExpressionsAfter("filter",new Expression(field,operator,value,null),fieldsToRemove);    \r
217   }\r
218 \r
219   /**\r
220    * Sets the <code>limit</code> parameter. See Pazpar2 documentation for details.\r
221    */  \r
222   public void setLimit (String compoundExpression) {\r
223     if (getParameter("limit") != null) removeParameterInState("limit");\r
224     if (compoundExpression != null && compoundExpression.length()>0) {      \r
225       // Split expression by commas that are not escaped with backslash\r
226       String[] subExpressions = compoundExpression.split("(?<!\\\\),");\r
227       for (int i=0; i<subExpressions.length; i++) {\r
228         if (i==0) {\r
229           setParameterInState(new LimitParameter(new Expression(subExpressions[i])));\r
230         } else {\r
231           addExpressionInState("limit",new Expression(subExpressions[i]));\r
232         }\r
233       }\r
234     }\r
235     checkInState(this);\r
236   }\r
237   \r
238   /**\r
239    * Sets the <code>limit</code> parameter including a label. See Pazpar2 documentation for details.\r
240    */  \r
241   public void setLimit(String field, String operator, String value, String label) {\r
242     setParameter(new LimitParameter(new Expression(field,operator,value,label)));\r
243   }\r
244       \r
245   /** \r
246    * Returns the <code>limit</code> parameter value.\r
247    */\r
248   public String getLimit () {\r
249     return getParameter("limit") == null ? null : ((LimitParameter)getParameter("limit")).getValueWithExpressions();    \r
250   }\r
251     \r
252   /**\r
253    * Checks if there are any limit expressions matching any of the given expressionFields\r
254    * @param expressionFields expression fields (left-of-operator entities) to look for\r
255    * @return true if expression(s) found with any of <code>expressionFields</code> \r
256    */\r
257   public boolean hasLimitExpression(String... expressionFields) {\r
258     logger.trace("Checking for limit expression for " + Arrays.deepToString(expressionFields));\r
259     for (String field : expressionFields) {\r
260       if (getLimitExpressions(field) != null && getLimitExpressions(field).size()>0) {\r
261         logger.trace("Limit expression found (" + field + ")");\r
262         return true;\r
263       }  \r
264     }\r
265     logger.trace("No limit expressions found");\r
266     return false;\r
267   }\r
268   \r
269   /**\r
270    * Returns the first limit expression of the given type\r
271    * @param expressionField expression field (left-of-operator entity) to look for\r
272    * @return the first limit expression found with the field <code>expressionField</code> or null if none found \r
273    */\r
274   public Expression getOneLimitExpression(String expressionField) {\r
275     List<Expression> exprs = getLimitExpressions(expressionField);\r
276     if (exprs != null && exprs.size()>0) {\r
277       if (exprs.size()>1) {\r
278         logger.warn("More that one limit expression found for [" + expressionField + "] but only asked to return the first one");\r
279       }\r
280       return exprs.get(0);\r
281     } else {\r
282       return null;\r
283     }    \r
284   }\r
285   \r
286   /**\r
287    * Return a list of all current limit expressions\r
288    */\r
289   public List<Expression> getLimitExpressions() {\r
290     return getParameter("limit").getExpressions();\r
291   }\r
292   \r
293   /**\r
294    * Returns a list of limit expressions with fields that matches one of <code>expressionFields</code>\r
295    * \r
296    * @param expressionFields limit expressions to look for\r
297    */\r
298   public List<Expression> getLimitExpressions(String... expressionFields) {\r
299     logger.trace("Checking for limit parameter");\r
300     if (parameters.get("limit")!=null) {\r
301       logger.trace("Found");\r
302       return getParameter("limit").getExpressions(expressionFields);\r
303     } else {\r
304       logger.trace("Not found");\r
305       return null;\r
306     }\r
307   }\r
308   \r
309   /**\r
310    * Adds a limit expression with a label for display. The limit is added to the end\r
311    * of an ordered list.  \r
312    * \r
313    * @param field\r
314    * @param operator\r
315    * @param value\r
316    * @param label\r
317    */\r
318   public void addLimit(String field, String operator, String value, String label) {\r
319     if (getParameter("limit") == null) {\r
320       setLimit(field, operator, value, label);\r
321     } else {\r
322       addExpression("limit",new Expression(field,operator,value,label));      \r
323     }\r
324   }\r
325   \r
326   /**\r
327    * Clears the limit parameter\r
328    */\r
329   public void removeLimits() {\r
330     removeParameter("limit");\r
331   }\r
332   \r
333   /**\r
334    * Removes all limit expressions that have fields as listed in <code>fieldsToRemove</code>\r
335    * @param fieldsToRemove\r
336    */\r
337   public void removeLimits(String... fieldsToRemove) {    \r
338     removeExpressions("limit",fieldsToRemove);    \r
339   }\r
340   \r
341   /**\r
342    * Removes a limit expression by exact attributes\r
343    * \r
344    * @param field\r
345    * @param operator\r
346    * @param value\r
347    */\r
348   public void removeLimit(String field, String operator, String value) {\r
349     removeExpression("limit",new Expression(field, operator, value, null));    \r
350   }\r
351   \r
352   /**\r
353    * Removes limit expressions coming after the provided limit expression, if they have a field listed in\r
354    * <code>fieldsToRemove</code>. To be used for bread crumb like UI controls.\r
355    * \r
356    * @param field\r
357    * @param operator\r
358    * @param value\r
359    * @param fieldsToRemove\r
360    */\r
361   public void removeLimitsAfter(String field, String operator, String value, String... fieldsToRemove) {     \r
362     removeExpressionsAfter("limit",new Expression(field,operator,value,null),fieldsToRemove);    \r
363   }\r
364 \r
365         \r
366   /**\r
367    * Sets the <code>startrecs</code> parameter. See Pazpar2 documentation for details.\r
368    */  \r
369   public void setStartrecs (String startrecs) {\r
370     setParameter(new CommandParameter("startrecs","=",startrecs));\r
371   }\r
372   \r
373   /** \r
374    * Returns the <code>startrecs</code> parameter value.\r
375    */\r
376   public String getStartrecs () {\r
377     return getParameterValue("startrecs");\r
378   }\r
379   \r
380   /**\r
381    * Sets the <code>maxrecs</code> parameter. See Pazpar2 documentation for details.\r
382    */  \r
383   public void setMaxrecs (String maxrecs) {\r
384     setParameter(new CommandParameter("maxrecs","=",maxrecs));\r
385   }\r
386   \r
387   /** \r
388    * Returns the <code>maxrecs</code> parameter value.\r
389    */\r
390   public String getMaxrecs () {\r
391     return getParameterValue("maxrecs");\r
392   }\r
393   \r
394   /**\r
395    * Sets the <code>sort</code> parameter. See Pazpar2 documentation for details.\r
396    */  \r
397   public void setSort (String sort) {\r
398     setParameter(new CommandParameter("sort","=",sort));\r
399   }\r
400   \r
401   /** \r
402    * Returns the <code>sort</code> parameter value.\r
403    */\r
404   public String getSort () {\r
405     return getParameterValue("sort");\r
406   }\r
407   \r
408   /**\r
409    * Sets the <code>rank</code> parameter. See Pazpar2 documentation for details.\r
410    */  \r
411   public void setRank (String rank) {\r
412     setParameter(new CommandParameter("rank","=",rank));\r
413   }\r
414   \r
415   /** \r
416    * Returns the <code>rank</code> parameter value.\r
417    */\r
418   public String getRank () {\r
419     return getParameterValue("rank");\r
420   }\r
421   \r
422   /**\r
423    * Sets the <code>mergekey</code> parameter. See Pazpar2 documentation for details.\r
424    */  \r
425   public void setMergekey (String mergekey) {\r
426     setParameter(new CommandParameter("mergekey","=",mergekey));\r
427   }\r
428   \r
429   /** \r
430    * Returns the <code>mergekey</code> parameter value.\r
431    */\r
432   public String getMergekey () {\r
433     return getParameterValue("mergekey");\r
434   }\r
435   \r
436   \r
437   /**\r
438    * Adds an expression - for instance a facet criterion, with an optional label - to the query parameter\r
439    * \r
440    * <p>Example:</p>\r
441    * <ul>\r
442    *  <li><code>{au}{=}{"Steinbeck, John"}{Steinbeck, John}</code>\r
443    * </ul>\r
444    */\r
445   public void addQueryExpression(String field, String operator, String term, String label) {\r
446     if (term != null && term.length()>0) { \r
447       addExpression("query", new Expression(field,operator,term,label));                  \r
448     }            \r
449   }\r
450   \r
451   /**\r
452    * Removes a query expression - for instance a facet criterion - by its exact attributes\r
453    * \r
454    * @param field\r
455    * @param operator\r
456    * @param value\r
457    */\r
458   public void removeQueryExpression(String field, String operator, String value) {\r
459     removeExpression("query",new Expression(field, operator, value, null));    \r
460   }\r
461 \r
462   \r
463   /**\r
464    * Sets a facet to limit the current query by. The \r
465    * facet is appended to the query string itself (rather\r
466    * as a separately managed entity. It will thus appear\r
467    * in a query field as retrieved by getQuery(). It will\r
468    * not be removed by removeFacet(...)\r
469    * \r
470    * @param facetKey  i.e. 'au' for author\r
471    * @param term i.e. 'Dickens, Charles'\r
472    */\r
473   public void setFacetOnQuery (String facetKey, String term) {\r
474     String facetExpression = facetKey + "=" + term;    \r
475     if (term != null && term.length()>0) {\r
476       String currentQuery= getQuery();\r
477       setParameter(new QueryParameter("query","=", currentQuery + " and " + facetExpression));      \r
478     }            \r
479   }\r
480       \r
481   /**\r
482    * Removes a facet set by setFacet(...)\r
483    * \r
484    * Will not remove facets set by setFacetOnQuery(...)\r
485    *  \r
486    * @param facetKey i.e. 'au' for author\r
487    * @param term i.e. 'Dickens, Charles'\r
488    */\r
489   public void removeFacet(String facetKey, String term) {\r
490     if (getParameter("query") != null) {\r
491       removeExpression("query",new Expression(facetKey,"=",term,null));\r
492     }\r
493   }\r
494       \r
495   public SearchCommand copy () {\r
496     SearchCommand newCommand = new SearchCommand();\r
497     for (String parameterName : parameters.keySet()) {\r
498       newCommand.setParameterInState(parameters.get(parameterName).copy());      \r
499     }\r
500     return newCommand;\r
501   }\r
502 \r
503   @Override\r
504   public ServiceProxyCommand getSp() {\r
505     return new SearchCommandSp(this);\r
506   }\r
507 \r
508   @Override\r
509   public boolean spOnly() {\r
510     return false;\r
511   }\r
512 \r
513 }\r