Javadoc
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / mkjsf / pazpar2 / commands / SearchCommand.java
index ce8c50b..7d74b6c 100644 (file)
 package com.indexdata.mkjsf.pazpar2.commands;\r
 \r
+import java.util.Arrays;\r
+import java.util.List;\r
+\r
 import javax.enterprise.context.SessionScoped;\r
+import javax.inject.Named;\r
 \r
 import org.apache.log4j.Logger;\r
 \r
+import com.indexdata.mkjsf.pazpar2.Pz2Service;\r
+import com.indexdata.mkjsf.pazpar2.commands.sp.SearchCommandSp;\r
 import com.indexdata.mkjsf.pazpar2.commands.sp.ServiceProxyCommand;\r
-import com.indexdata.mkjsf.pazpar2.state.StateManager;\r
+import com.indexdata.mkjsf.pazpar2.data.ResponseDataObject;\r
 \r
-@SessionScoped\r
+/**\r
+ * <b><code>search</code></b> Pazpar2 command, referenced as: <code>pzreq.search</code> \r
+ * \r
+ * @author Niels Erik\r
+ *\r
+ */\r
+@SessionScoped @Named\r
 public class SearchCommand extends Pazpar2Command implements ServiceProxyCommand {\r
   \r
   private static final long serialVersionUID = -1888520867838597236L;\r
-  private static Logger logger = Logger.getLogger(SearchCommand.class);\r
-  private SingleTargetFilter singleTargetFilter = null;\r
+  private static Logger logger = Logger.getLogger(SearchCommand.class);  \r
+    \r
+  public SearchCommand() {\r
+    super("search");\r
+  }\r
   \r
-  public SearchCommand(StateManager stateMgr) {\r
-    super("search",stateMgr);\r
+  public ResponseDataObject run() {\r
+    logger.info("Running " + getCommandName());\r
+    Pz2Service.get().getStateMgr().hasPendingStateChange("search",false);\r
+    Pz2Service.get().getPzresp().resetSearchAndBeyond();\r
+    Pz2Service.get().getPzreq().getRecord().removeParametersInState();        \r
+    Pz2Service.get().getPzreq().getShow().setParameterInState(new CommandParameter("start","=",0));    \r
+    Pz2Service.get().getSearchClient().setSearchCommand(this);\r
+    return super.run();\r
   }\r
-    \r
+\r
+  /**\r
+   * Sets the <code>query</code> parameter. See Pazpar2 documentation for details.\r
+   */  \r
   public void setQuery(String query) {    \r
-    setParameter(new CommandParameter("query","=",query));\r
+    setParameter(new QueryParameter("query","=",query));\r
   }\r
   \r
-  public String getQuery () {    \r
-    return getParameter("query") == null ? null  : getParameter("query").getValueWithExpressions();\r
+  public void setBooleanOperatorForQuery(String operator) {\r
+    Pazpar2Command copy = this.copy();\r
+    ((QueryParameter) getParameter("query")).setBooleanOperator(operator);\r
+    checkInState(copy);\r
   }\r
   \r
+  /** \r
+   * Returns the simple part of the <code>query</code> parameter value, excluding parts that \r
+   * were added as expressions (that is, not set with <code>setQuery()</code>).\r
+   */\r
+  public String getQuery () {    \r
+    return getParameter("query") == null ? null  : ((QueryParameter)getParameter("query")).getSimpleValue();\r
+  }\r
+\r
+  /** \r
+   * Returns the complete <code>query</code> parameter value, including expressions.\r
+   */\r
+  public String getExtendedQuery () {    \r
+    return getParameter("query") == null ? null  : ((QueryParameter)getParameter("query")).getValueWithExpressions();\r
+  }\r
+    \r
+  /**\r
+   * Sets the <code>filter</code> parameter. See Pazpar2 documentation for details.\r
+   */  \r
   public void setFilter(String filterExpression) {\r
-    setParameter(new CommandParameter("filter","=",filterExpression));\r
+    if (filterExpression != null && filterExpression.length()>0) {\r
+      if (filterExpression.split("[=~]").length==1) {\r
+        removeFilters(filterExpression.split("[=~]")[0]);\r
+      } else if (filterExpression.split("[=~]").length==2) {\r
+        setParameter(new FilterParameter(new Expression(filterExpression)));\r
+      } else {\r
+        logger.error("Could not parse filter expression [" + filterExpression + "]");\r
+      }\r
+    }\r
   }\r
   \r
+  /**\r
+   * Sets the <code>filter</code> parameter. See Pazpar2 documentation for details.\r
+   */  \r
+  public void setFilter(String field, String operator, String value, String label) {\r
+    setParameter(new FilterParameter(new Expression(field,operator,value,label)));\r
+  }\r
+\r
+  /**\r
+   * Checks if there are any filter expressions matching any of the given expressionFields\r
+   * @param expressionFields expression fields (left-of-operator entities) to look for\r
+   * @return true if expression(s) found with any of <code>expressionFields</code> \r
+   */\r
+  public boolean hasFilterExpression(String... expressionFields) {\r
+    logger.trace("Checking for filter expression for " + Arrays.deepToString(expressionFields));\r
+    for (String field : expressionFields) {\r
+      if (getFilterExpressions(field) != null && getFilterExpressions(field).size()>0) {\r
+        logger.trace("Filter expression found (" + field + ")");\r
+        return true;\r
+      }  \r
+    }\r
+    logger.trace("No filter expressions found");\r
+    return false;\r
+  }\r
+\r
+  \r
+  /** \r
+   * Returns the <code>filter</code> parameter value.\r
+   */\r
   public String getFilter() {\r
-    return getParameter("filter") == null ? null : getParameter("filter").getValueWithExpressions();\r
+    return getParameter("filter") == null ? null : ((FilterParameter)getParameter("filter")).getValueWithExpressions();\r
   }\r
   \r
-  public void addFilter(String filterExpression) {\r
-    // TODO: implement\r
-    if (hasParameterValue("filter")) {\r
-      setFilter(filterExpression);\r
+  /**\r
+   * Returns the first filter expression of the given type\r
+   * @param expressionField expression field (left-of-operator entity) to look for\r
+   * @return the first filter expression found with the field <code>expressionField</code> or null if none found \r
+   */\r
+  public Expression getOneFilterExpression(String expressionField) {\r
+    List<Expression> exprs = getFilterExpressions(expressionField);\r
+    if (exprs != null && exprs.size()>0) {\r
+      if (exprs.size()>1) {\r
+        logger.warn("More that one filter expression found for [" + expressionField + "] but only asked to return the first one");\r
+      }\r
+      return exprs.get(0);\r
     } else {\r
-      getParameter("filter");\r
+      return null;\r
+    }    \r
+  }\r
+\r
+  \r
+  /**\r
+   * Returns list of all filter expressions \r
+   */\r
+  public List<Expression> getFilterExpressions() {\r
+    return getParameter("filter").getExpressions();\r
+  }\r
+    \r
+  \r
+  public List<Expression> getFilterExpressions(String... expressionFields) {\r
+    logger.trace("Checking for filter parameter");\r
+    if (parameters.get("filter")!=null) {\r
+      logger.trace("Found");\r
+      return getParameter("filter").getExpressions(expressionFields);\r
+    } else {\r
+      logger.trace("Not found");\r
+      return null;\r
     }\r
-    throw new UnsupportedOperationException("removeFilter(filterExpression) yet to be implemented.");\r
   }\r
   \r
+  public boolean hasFilter () {\r
+    return getFilter().length()>0;\r
+  }\r
+\r
+  /**\r
+   * Adds a filter expression with a label for display. The filter is added to the end\r
+   * of an ordered list.  \r
+   * \r
+   * @param field\r
+   * @param operator\r
+   * @param value\r
+   * @param label\r
+   */\r
+  public void addFilter(String field, String operator, String value, String label) {\r
+    if (getParameter("filter") == null) {\r
+      setFilter(field + operator + value);\r
+    } else {\r
+      addExpression("filter",new Expression(field,operator,value,(label != null ? label : value)));\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Clears the filter parameter\r
+   */\r
   public void removeFilters () {\r
     removeParameter("filter");\r
   }\r
+\r
+  /**\r
+   * Removes a filter expression by exact attributes\r
+   * \r
+   * @param field\r
+   * @param operator\r
+   * @param value\r
+   */\r
+  public void removeFilter(String field, String operator, String value) {\r
+    removeExpression("filter",new Expression(field, operator, value, null));\r
+  }\r
   \r
-  public void removeFilter(String filterExpression) {\r
-    // TODO: implement\r
-    throw new UnsupportedOperationException("removeFilter(filterExpression) yet to be implemented.");\r
+  /**\r
+   * Removes all filter expressions matching a field listed in <code>fieldsToRemove</code>\r
+   * @param fieldsToRemove\r
+   */\r
+  public void removeFilters(String... fieldsToRemove) {    \r
+    removeExpressions("filter",fieldsToRemove);    \r
+  }  \r
+\r
+  /**\r
+   * Removes filter expressions coming after the expression matching the provided filter expression, \r
+   * if they have a field listed in <code>fieldsToRemove</code>. To be used for bread crumb like UI \r
+   * controls.\r
+   * \r
+   * @param field\r
+   * @param operator\r
+   * @param value\r
+   * @param fieldsToRemove\r
+   */\r
+  public void removeFiltersAfter(String field, String operator, String value, String... fieldsToRemove) {     \r
+    removeExpressionsAfter("filter",new Expression(field,operator,value,null),fieldsToRemove);    \r
   }\r
 \r
-  public boolean hasFilter () {\r
-    return getFilter().length()>0;\r
+  /**\r
+   * Sets the <code>limit</code> parameter. See Pazpar2 documentation for details.\r
+   */  \r
+  public void setLimit (String limitExpression) {   \r
+    if (limitExpression != null && limitExpression.length()>0) {\r
+      setParameter(new LimitParameter(new Expression(limitExpression)));\r
+    }\r
   }\r
   \r
-  public void setLimit (String limitExpression) {\r
-    setParameter(new CommandParameter("limit","=",limitExpression));\r
+  /**\r
+   * Sets the <code>limit</code> parameter including a label. See Pazpar2 documentation for details.\r
+   */  \r
+  public void setLimit(String field, String operator, String value, String label) {\r
+    setParameter(new LimitParameter(new Expression(field,operator,value,label)));\r
   }\r
-  \r
+      \r
+  /** \r
+   * Returns the <code>limit</code> parameter value.\r
+   */\r
   public String getLimit () {\r
-    return getParameterValue("limit");\r
+    return getParameter("limit") == null ? null : ((LimitParameter)getParameter("limit")).getValueWithExpressions();    \r
   }\r
-      \r
+    \r
+  /**\r
+   * Checks if there are any limit expressions matching any of the given expressionFields\r
+   * @param expressionFields expression fields (left-of-operator entities) to look for\r
+   * @return true if expression(s) found with any of <code>expressionFields</code> \r
+   */\r
+  public boolean hasLimitExpression(String... expressionFields) {\r
+    logger.trace("Checking for limit expression for " + Arrays.deepToString(expressionFields));\r
+    for (String field : expressionFields) {\r
+      if (getLimitExpressions(field) != null && getLimitExpressions(field).size()>0) {\r
+        logger.trace("Limit expression found (" + field + ")");\r
+        return true;\r
+      }  \r
+    }\r
+    logger.trace("No limit expressions found");\r
+    return false;\r
+  }\r
+  \r
+  /**\r
+   * Returns the first limit expression of the given type\r
+   * @param expressionField expression field (left-of-operator entity) to look for\r
+   * @return the first limit expression found with the field <code>expressionField</code> or null if none found \r
+   */\r
+  public Expression getOneLimitExpression(String expressionField) {\r
+    List<Expression> exprs = getLimitExpressions(expressionField);\r
+    if (exprs != null && exprs.size()>0) {\r
+      if (exprs.size()>1) {\r
+        logger.warn("More that one limit expression found for [" + expressionField + "] but only asked to return the first one");\r
+      }\r
+      return exprs.get(0);\r
+    } else {\r
+      return null;\r
+    }    \r
+  }\r
+  \r
+  /**\r
+   * Return a list of all current limit expressions\r
+   */\r
+  public List<Expression> getLimitExpressions() {\r
+    return getParameter("limit").getExpressions();\r
+  }\r
+  \r
+  /**\r
+   * Returns a list of limit expressions with fields that matches on of <code>expressionFields</code>\r
+   * \r
+   * @param expressionFields limit expressions to look for\r
+   */\r
+  public List<Expression> getLimitExpressions(String... expressionFields) {\r
+    logger.trace("Checking for limit parameter");\r
+    if (parameters.get("limit")!=null) {\r
+      logger.trace("Found");\r
+      return getParameter("limit").getExpressions(expressionFields);\r
+    } else {\r
+      logger.trace("Not found");\r
+      return null;\r
+    }\r
+  }\r
+  \r
+  /**\r
+   * Adds a limit expression with a label for display. The limit is added to the end\r
+   * of an ordered list.  \r
+   * \r
+   * @param field\r
+   * @param operator\r
+   * @param value\r
+   * @param label\r
+   */\r
+  public void addLimit(String field, String operator, String value, String label) {\r
+    if (getParameter("limit") == null) {\r
+      setLimit(field, operator, value, label);\r
+    } else {\r
+      addExpression("limit",new Expression(field,operator,value,label));      \r
+    }\r
+  }\r
+  \r
+  /**\r
+   * Clears the limit parameter\r
+   */\r
+  public void removeLimits() {\r
+    removeParameter("limit");\r
+  }\r
+  \r
+  /**\r
+   * Removes all limit expressions that have fields as listed in <code>fieldsToRemove</code>\r
+   * @param fieldsToRemove\r
+   */\r
+  public void removeLimits(String... fieldsToRemove) {    \r
+    removeExpressions("limit",fieldsToRemove);    \r
+  }\r
+  \r
+  /**\r
+   * Removes a limit expression by exact attributes\r
+   * \r
+   * @param field\r
+   * @param operator\r
+   * @param value\r
+   */\r
+  public void removeLimit(String field, String operator, String value) {\r
+    removeExpression("limit",new Expression(field, operator, value, null));    \r
+  }\r
+  \r
+  /**\r
+   * Removes limit expressions coming after the provided limit expression, if they have a field listed in\r
+   * <code>fieldsToRemove</code>. To be used for bread crumb like UI controls.\r
+   * \r
+   * @param field\r
+   * @param operator\r
+   * @param value\r
+   * @param fieldsToRemove\r
+   */\r
+  public void removeLimitsAfter(String field, String operator, String value, String... fieldsToRemove) {     \r
+    removeExpressionsAfter("limit",new Expression(field,operator,value,null),fieldsToRemove);    \r
+  }\r
+\r
+        \r
+  /**\r
+   * Sets the <code>startrecs</code> parameter. See Pazpar2 documentation for details.\r
+   */  \r
   public void setStartrecs (String startrecs) {\r
     setParameter(new CommandParameter("startrecs","=",startrecs));\r
   }\r
   \r
+  /** \r
+   * Returns the <code>startrecs</code> parameter value.\r
+   */\r
   public String getStartrecs () {\r
     return getParameterValue("startrecs");\r
   }\r
   \r
+  /**\r
+   * Sets the <code>maxrecs</code> parameter. See Pazpar2 documentation for details.\r
+   */  \r
   public void setMaxrecs (String maxrecs) {\r
     setParameter(new CommandParameter("maxrecs","=",maxrecs));\r
   }\r
   \r
+  /** \r
+   * Returns the <code>maxrecs</code> parameter value.\r
+   */\r
   public String getMaxrecs () {\r
     return getParameterValue("maxrecs");\r
   }\r
   \r
-  public void setSort () {\r
-    setParameter(new CommandParameter("sort","=","sort"));\r
+  /**\r
+   * Sets the <code>sort</code> parameter. See Pazpar2 documentation for details.\r
+   */  \r
+  public void setSort (String sort) {\r
+    setParameter(new CommandParameter("sort","=",sort));\r
   }\r
   \r
+  /** \r
+   * Returns the <code>sort</code> parameter value.\r
+   */\r
   public String getSort () {\r
     return getParameterValue("sort");\r
   }\r
   \r
   /**\r
-   * Sets a facet, in CQL, to restrict the current results,\r
-   * then executes the search \r
+   * Sets the <code>rank</code> parameter. See Pazpar2 documentation for details.\r
+   */  \r
+  public void setRank (String rank) {\r
+    setParameter(new CommandParameter("rank","=",rank));\r
+  }\r
+  \r
+  /** \r
+   * Returns the <code>rank</code> parameter value.\r
+   */\r
+  public String getRank () {\r
+    return getParameterValue("rank");\r
+  }\r
+  \r
+  /**\r
+   * Sets the <code>mergekey</code> parameter. See Pazpar2 documentation for details.\r
+   */  \r
+  public void setMergekey (String mergekey) {\r
+    setParameter(new CommandParameter("mergekey","=",mergekey));\r
+  }\r
+  \r
+  /** \r
+   * Returns the <code>mergekey</code> parameter value.\r
+   */\r
+  public String getMergekey () {\r
+    return getParameterValue("mergekey");\r
+  }\r
+  \r
+  \r
+  /**\r
+   * Adds an expression - for instance a facet criterion, with an optional label - to the query parameter\r
    * \r
-   * @param facetKey  i.e.  'au' for author\r
-   * @param term  i.e. 'Dickens, Charles'\r
+   * <p>Example:</p>\r
+   * <ul>\r
+   *  <li><code>{au}{=}{"Steinbeck, John"}{Steinbeck, John}</code>\r
+   * </ul>\r
    */\r
-  public void setFacet(String facetKey, String term) {\r
-    if (term != null && term.length()>0) {         \r
-      getParameter("query").addExpression(new Expression(facetKey,"=",term));            \r
+  public void addQueryExpression(String field, String operator, String term, String label) {\r
+    if (term != null && term.length()>0) { \r
+      addExpression("query", new Expression(field,operator,term,label));                  \r
     }            \r
   }\r
   \r
   /**\r
+   * Removes a query expression - for instance a facet criterion - by its exact attributes\r
+   * \r
+   * @param field\r
+   * @param operator\r
+   * @param value\r
+   */\r
+  public void removeQueryExpression(String field, String operator, String value) {\r
+    removeExpression("query",new Expression(field, operator, value, null));    \r
+  }\r
+\r
+  \r
+  /**\r
    * Sets a facet to limit the current query by. The \r
    * facet is appended to the query string itself (rather\r
    * as a separately managed entity. It will thus appear\r
@@ -115,14 +459,13 @@ public class SearchCommand extends Pazpar2Command implements ServiceProxyCommand
   public void setFacetOnQuery (String facetKey, String term) {\r
     String facetExpression = facetKey + "=" + term;    \r
     if (term != null && term.length()>0) {\r
-      String currentQuery= getParameterValue("query");\r
-      setParameter(new CommandParameter("query","=", currentQuery + " and " + facetExpression));      \r
+      String currentQuery= getQuery();\r
+      setParameter(new QueryParameter("query","=", currentQuery + " and " + facetExpression));      \r
     }            \r
   }\r
       \r
   /**\r
-   * Removes a facet set by setFacet(...), then executes\r
-   * the search.\r
+   * Removes a facet set by setFacet(...)\r
    * \r
    * Will not remove facets set by setFacetOnQuery(...)\r
    *  \r
@@ -131,81 +474,21 @@ public class SearchCommand extends Pazpar2Command implements ServiceProxyCommand
    */\r
   public void removeFacet(String facetKey, String term) {\r
     if (getParameter("query") != null) {\r
-      getParameter("query").removeExpression(new Expression(facetKey,"=",term));\r
+      removeExpression("query",new Expression(facetKey,"=",term,null));\r
     }\r
   }\r
-  \r
-  \r
-  /**\r
-   * Adds a single target filter to restrict the current query by, \r
-   * then executes the current search.\r
-   * \r
-   * This is a special case of the general setFilter function, \r
-   * allowing to associate a descriptive target name with the \r
-   * filter expression for display in UI. \r
-   * \r
-   * @param targetId pazpar2's ID for the target to limit by\r
-   * @param targetName a descriptive name for the target\r
-   */\r
-  public void setSingleTargetFilter (String targetId, String targetName) {    \r
-    if (hasSingleTargetFilter(new SingleTargetFilter(targetId,targetName))) {\r
-      logger.debug("Already using target filter " + this.singleTargetFilter.getFilterExpression());\r
-    } else {      \r
-      logger.debug("Setting new single target filter for [" + targetName + "]");\r
-      this.singleTargetFilter = new SingleTargetFilter(targetId,targetName);\r
-      setParameter(new CommandParameter("filter","=",this.singleTargetFilter.getFilterExpression()));            \r
-    }    \r
-  }\r
-\r
-  public SingleTargetFilter getSingleTargetFilter () {\r
-    logger.debug("request to get the current single target filter " + singleTargetFilter);\r
-    return singleTargetFilter;\r
-  }\r
-   \r
-  /**\r
-   * Removes the current target filter from the search\r
-   * \r
-   */\r
-  public String removeSingleTargetFilter () {\r
-    logger.debug("Removing target filter " + singleTargetFilter.getFilterExpression());\r
-    this.singleTargetFilter = null;\r
-    removeParameter("filter");\r
-    return null;\r
-  }\r
-  \r
-  /**\r
-   * \r
-   * @return The target filter set on the current search command\r
-   */\r
-  public boolean hasSingleTargetFilter() {\r
-    logger.debug("Checking if a single target filter is set: " + (singleTargetFilter != null));\r
-    return singleTargetFilter != null;    \r
-  }\r
-  \r
-  /**\r
-   * Resolves if the current search command has a target filter - to\r
-   * be used by the UI for conditional rendering of target filter info.\r
-   * \r
-   * @return true if the current search command is limited by a target \r
-   * filter\r
-   */\r
-  protected boolean hasSingleTargetFilter(SingleTargetFilter targetFilter) {\r
-    logger.debug("Checking if target filter for [" + targetFilter.getTargetName() + "] is set.");\r
-    return hasSingleTargetFilter() && targetFilter.equals(this.singleTargetFilter);\r
-  }\r
-    \r
+      \r
   public SearchCommand copy () {\r
-    SearchCommand newCommand = new SearchCommand(stateMgr);\r
+    SearchCommand newCommand = new SearchCommand();\r
     for (String parameterName : parameters.keySet()) {\r
       newCommand.setParameterInState(parameters.get(parameterName).copy());      \r
     }\r
-    newCommand.singleTargetFilter = this.singleTargetFilter;\r
     return newCommand;\r
   }\r
 \r
   @Override\r
   public ServiceProxyCommand getSp() {\r
-    return this;\r
+    return new SearchCommandSp(this);\r
   }\r
 \r
   @Override\r