Merge branch 'master' of ssh://git.indexdata.com/home/git/private/mkjsf.git into...
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / mkjsf / pazpar2 / commands / CommandParameter.java
diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/CommandParameter.java b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/CommandParameter.java
new file mode 100644 (file)
index 0000000..6c6df86
--- /dev/null
@@ -0,0 +1,333 @@
+package com.indexdata.mkjsf.pazpar2.commands;\r
+\r
+import java.io.Serializable;\r
+import java.io.UnsupportedEncodingException;\r
+import java.net.URLEncoder;\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import org.apache.log4j.Logger;\r
+\r
+/**\r
+ * Represents a Pazpar2 command parameter with a name, an operator, \r
+ * a simple value and/or one or more complex values (expressions).\r
+ * <p><i>Examples:</i></p>\r
+ * <ul>\r
+ *  <li><code>{name}{=}{value}</code></li>\r
+ *  <li><code>{name}{=}{value} AND {expr1=value1} AND {expr2=value2}</code></li>\r
+ *  <li><code>{name}{=}{expr1~value1},{expr2~value2}</code></li> \r
+ * </ul> \r
+ * @author Niels Erik\r
+ *\r
+ */\r
+public class CommandParameter implements Serializable {\r
+\r
+  private static Logger logger = Logger.getLogger(CommandParameter.class);\r
+  \r
+  private static final long serialVersionUID = 625502285668766749L;  \r
+  String name = null;\r
+  String operator = null;\r
+  String value = null;\r
+  List<Expression> expressions = new ArrayList<Expression>();\r
+  private static List<String> nologparams = Arrays.asList("password");\r
+  \r
+  public CommandParameter (String name) {\r
+    logger.trace("Instantiating command parameter '" + name + "'");\r
+    this.name = name;\r
+  }\r
+  \r
+  /**\r
+   * Instantiates a parameter with a simple value and one or more expressions\r
+   * \r
+   * @param name\r
+   * @param operator\r
+   * @param value\r
+   * @param expressions\r
+   */\r
+  public CommandParameter (String name, String operator, String value, Expression... expressions) {\r
+    logger.trace("Instantiating command parameter " + name + " with value [" + value + "] and expressions: [" + expressions + "]");\r
+    this.name = name;\r
+    this.operator = operator;\r
+    this.value = value;\r
+    for (Expression expr : expressions) {\r
+      this.expressions.add(expr);\r
+    }\r
+  }\r
+  \r
+  /**\r
+   * Instantiates a parameter with one or more expressions\r
+   * @param name\r
+   * @param operator\r
+   * @param expressions\r
+   */\r
+  public CommandParameter (String name, String operator, Expression... expressions) {\r
+    logger.trace("Instantiating command parameter " + name + " with expressions: [" + expressions + "]");\r
+    this.name = name;\r
+    this.operator = operator;    \r
+    for (Expression expr : expressions) {\r
+      this.expressions.add(expr);\r
+    }\r
+  }\r
+\r
+\r
+  /**\r
+   * Instantiates a parameter with a simple value\r
+   * @param name\r
+   * @param operator\r
+   * @param value\r
+   */\r
+  public CommandParameter (String name, String operator, String value) {\r
+    if (!nologparams.contains(name)) logger.trace("Instantiating command parameter '" + name + "' with String: [" + value + "]");    \r
+    this.name = name;\r
+    this.operator = operator;\r
+    this.value = value;    \r
+  }\r
+  \r
+  /**\r
+   * Instantiates a parameter with a numeric value\r
+   * @param name\r
+   * @param operator\r
+   * @param value\r
+   */\r
+  public CommandParameter (String name, String operator, int value) {\r
+    logger.trace("Instantiating command parameter '" + name + "' with int: [" + value + "]");\r
+    this.name = name;\r
+    this.operator = operator;\r
+    this.value = value+"";    \r
+  }\r
+\r
+  /**\r
+   * Returns the name (left of operator) of this parameter\r
+   * \r
+   * @return name (left of operator) of this parameter\r
+   */\r
+  public String getName () {\r
+    return name;\r
+  }\r
+  \r
+  /**\r
+   * Returns a list of all current expressions\r
+   * \r
+   * @return a list of all current expressions\r
+   */\r
+  public List<Expression> getExpressions () {\r
+    return expressions;\r
+  }\r
+\r
+  /**\r
+   * Returns expressions selected by their left-hand keys - as in 'expressionField=value'.\r
+   * <p>\r
+   * If the parameter has expressions expr1=x,expr2=y,expr3=z,expr1=u then invoking this method \r
+   * with {"expr1","expr3"} would return expr1=x,expr3=z,expr1=u but not expr2=y.   \r
+   * </p>\r
+   * @param expressionFields The expression types to return\r
+   * @return a list of expressions with the given keys to the left of the operator\r
+   * \r
+   */\r
+  public List<Expression> getExpressions(String... expressionFields) {\r
+    List<String> requestedFields = Arrays.asList(expressionFields);\r
+    List<Expression> exprs = new ArrayList<Expression>();\r
+    for (Expression expr : expressions) {\r
+      if (requestedFields.contains(expr.getField())) {\r
+        exprs.add(expr);\r
+      }\r
+    }\r
+    return exprs;\r
+  }\r
+  \r
+  /**\r
+   * Adds an expression to the end of the list of current expressions (if any)\r
+   * \r
+   * @param expression to add\r
+   */\r
+  public void addExpression(Expression expression) {\r
+    logger.debug("Adding expression [" + expression + "] to '" + name + "'");\r
+    this.expressions.add(expression);\r
+  }\r
+  \r
+  /**\r
+   * Removes a single expression identified by all its characteristics\r
+   * \r
+   * @param expression to remove\r
+   */\r
+  public void removeExpression(Expression expression) {\r
+    for (Expression expr : expressions) {\r
+      if (expr.toString().equals(expression.toString())) {\r
+        expressions.remove(expr);\r
+        break;\r
+      }\r
+    }    \r
+  }\r
+  \r
+  /**\r
+   * Removes all expressions that appear after the provided expression and that \r
+   * have the given keys to the left of their operators - as in 'expressionField=value'.\r
+   * <p>\r
+   * This method is intended for bread crumb-like UI controls\r
+   * </p>\r
+   * @param expression The expression to use a starting point for removal (not inclusive)\r
+   * @param expressionFields The expression fields to remove\r
+   */\r
+  public void removeExpressionsAfter (Expression expression, String... expressionFields) {\r
+    List<String> exprFieldsToRemove = Arrays.asList(expressionFields);\r
+    int fromIdx = 0;    \r
+    for (Expression expr : expressions) {      \r
+      fromIdx++;\r
+      if (expr.toString().equals(expression.toString())) {        \r
+        break;\r
+      }      \r
+    }\r
+    if (fromIdx<expressions.size()) {      \r
+      Iterator<Expression> candidatesForRemoval = expressions.subList(fromIdx, expressions.size()).iterator();\r
+      while (candidatesForRemoval.hasNext()) {\r
+        Expression exp = candidatesForRemoval.next();\r
+        if (exprFieldsToRemove.contains(exp.getField())) {\r
+          expressions.remove(exp);\r
+        }\r
+      }\r
+    }\r
+  }\r
+  \r
+  /**\r
+   * Removes expressions selected by their left-of-operator fields/keys - as in 'expressionField=value'.\r
+   * <p>\r
+   * If the parameter has expressions expr1=x,expr2=y,expr3=z,expr1=u then invoking this method \r
+   * with {"expr1","expr3"} would remove expr1=x,expr3=z and expr1=u but leave expr2=y.   \r
+   * </p>\r
+   * @param expressionFields The expression types (by field) to remove\r
+   * @return a list of expressions with the given left-of-operator keys\r
+   * \r
+   */\r
+  public void removeExpressions (String... expressionFields) {\r
+    List<String> fieldsToRemove = Arrays.asList(expressionFields);\r
+    Iterator<Expression> i = expressions.iterator();\r
+    while (i.hasNext()) {\r
+       Expression expr = i.next(); \r
+       if (fieldsToRemove.contains(expr.getField())) {\r
+         logger.trace("Removing expression: " + expr.toString());\r
+         i.remove();\r
+       }\r
+    }\r
+  }\r
+\r
+  /**\r
+   *   \r
+   * @return true if an operator was defined for this parameter yet\r
+   */\r
+  public boolean hasOperator() {\r
+    return operator != null;\r
+  }\r
+  \r
+  /**\r
+   * Returns true if this parameter has a simple value\r
+   * \r
+   * @return true if this parameter has a simple value\r
+   */\r
+  public boolean hasValue() {\r
+    return value != null && value.length()>0;\r
+  }\r
+  \r
+  /**\r
+   * Returns true if this parameter has expressions (complex values)\r
+   * \r
+   * @return true if this parameter has expressions (complex values)\r
+   */\r
+  public boolean hasExpressions() {\r
+    return expressions.size()>0;\r
+  }\r
+  \r
+  /**\r
+   * Returns true if this parameter has expressions of the given type,\r
+   * that is, expressions where the left-of-operator key equals 'expressionField'\r
+   * \r
+   * @param expressionField the type of expression to look for\r
+   * @return true if this parameter has expressions of the given type,\r
+   *  that is, expressions where the left-of-operator key equals 'expressionField'\r
+   */\r
+  public boolean hasExpressions(String expressionField) {    \r
+    for (Expression expr : expressions) {\r
+      if (expr.getField().equals(expressionField)) {\r
+        return true;\r
+      }\r
+    }     \r
+    return false;    \r
+  }\r
+  \r
+  /**\r
+   * Returns a URL encoded string of this parameter with name, operator, simple value and/or expressions\r
+   * \r
+   * @return URL encoded string of this parameter with name, operator, simple value and/or expressions\r
+   */\r
+  public String getEncodedQueryString () {\r
+    try {\r
+      return name + operator + URLEncoder.encode(getValueWithExpressions(),"UTF-8");\r
+    } catch (UnsupportedEncodingException e) {\r
+      e.printStackTrace();\r
+      return null;\r
+    }\r
+  }\r
+    \r
+  /**\r
+   * Returns the simple parameter value or null if no simple value was set for this parameter\r
+   * \r
+   * @return the simple parameter value, null if no simple value was set for this parameter \r
+   */\r
+  public String getSimpleValue() {    \r
+    return value; \r
+  }\r
+  \r
+  /**\r
+   * Returns the simple parameter value and/or any expressions, separated by 'AND'\r
+   * \r
+   * @return the simple parameter value and/or any expressions separated by 'AND'\r
+   */\r
+  public String getValueWithExpressions () {\r
+    StringBuilder completeValue = new StringBuilder((value==null ? "" : value));\r
+    boolean first=true;\r
+    for (Expression expr : expressions) {      \r
+      if (value == null && first) {\r
+        first = false;\r
+        completeValue.append(expr.toString());\r
+      } else {\r
+        completeValue.append(" AND " + expr.toString());\r
+      }\r
+    }\r
+    return completeValue.toString();    \r
+  }  \r
+  \r
+  @Override\r
+  public boolean equals (Object otherParameter) {\r
+    return\r
+        ((otherParameter instanceof CommandParameter)\r
+         && this.getValueWithExpressions().equals(((CommandParameter) otherParameter).getValueWithExpressions()));\r
+  }\r
+  \r
+  @Override\r
+  public int hashCode () {\r
+    return getValueWithExpressions().hashCode();\r
+  }\r
+  \r
+  public String toString() {\r
+    return getValueWithExpressions();\r
+  }\r
+  \r
+  /**\r
+   * Clones the CommandParameter\r
+   * \r
+   * @return a deep, detached clone of this command parameter, for copying \r
+   * a parameter to a new state.  \r
+   */\r
+  public CommandParameter copy() {\r
+    logger.trace("Copying parameter '"+ name + "' for modification");\r
+    CommandParameter newParam = new CommandParameter(name);\r
+    newParam.value = this.value;\r
+    newParam.operator = this.operator;\r
+    for (Expression expr : expressions) {\r
+      newParam.addExpression(expr.copy());      \r
+    }\r
+    return newParam;\r
+  }\r
+  \r
+}\r