From 31a027596723261b413d69c74428b176def3627f Mon Sep 17 00:00:00 2001 From: "Niels Erik G. Nielsen" Date: Mon, 3 Jun 2013 15:44:07 -0400 Subject: [PATCH] Adds methods handling 'filter' and 'limit' expressions --- .../mkjsf/pazpar2/ServiceProxyClient.java | 2 +- .../mkjsf/pazpar2/commands/CommandParameter.java | 101 +++++++++++++--- .../mkjsf/pazpar2/commands/Expression.java | 37 +++++- .../mkjsf/pazpar2/commands/FilterParameter.java | 50 ++++++++ .../mkjsf/pazpar2/commands/LimitParameter.java | 52 ++++++++ .../mkjsf/pazpar2/commands/Pazpar2Command.java | 37 +++++- .../mkjsf/pazpar2/commands/SearchCommand.java | 126 ++++++++++++++++---- 7 files changed, 357 insertions(+), 48 deletions(-) create mode 100644 src/main/java/com/indexdata/mkjsf/pazpar2/commands/FilterParameter.java create mode 100644 src/main/java/com/indexdata/mkjsf/pazpar2/commands/LimitParameter.java diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/ServiceProxyClient.java b/src/main/java/com/indexdata/mkjsf/pazpar2/ServiceProxyClient.java index 67cc8ef..aa54403 100644 --- a/src/main/java/com/indexdata/mkjsf/pazpar2/ServiceProxyClient.java +++ b/src/main/java/com/indexdata/mkjsf/pazpar2/ServiceProxyClient.java @@ -101,7 +101,7 @@ public class ServiceProxyClient implements SearchClient { try { response = client.execute(httpget, handler); if (handler.getStatusCode()==200 && (handler.getContentType().contains("xml") || handler.getContentType().contains("octet-stream"))) { - logger.debug("Creating command response holding content of type " + handler.getContentType()); + logger.trace("Creating command response holding content of type " + handler.getContentType()); commandResponse = new ClientCommandResponse(handler.getStatusCode(),response,handler.getContentType()); } else { logger.error("Service Proxy status code: " + handler.getStatusCode()); diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/CommandParameter.java b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/CommandParameter.java index b22962e..d08cde1 100644 --- a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/CommandParameter.java +++ b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/CommandParameter.java @@ -3,15 +3,13 @@ package com.indexdata.mkjsf.pazpar2.commands; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; +import java.util.Iterator; import java.util.List; -import java.util.Map; import org.apache.log4j.Logger; -import com.indexdata.mkjsf.pazpar2.commands.CommandParameter; - public class CommandParameter implements Serializable { private static Logger logger = Logger.getLogger(CommandParameter.class); @@ -20,7 +18,7 @@ public class CommandParameter implements Serializable { String name = null; String operator = null; String value = null; - Map expressions = new HashMap(); + List expressions = new ArrayList(); private static List nologparams = Arrays.asList("password"); public CommandParameter (String name) { @@ -29,14 +27,24 @@ public class CommandParameter implements Serializable { } public CommandParameter (String name, String operator, String value, Expression... expressions) { - logger.trace("Instantiating command parameter " + name + " with expressions: [" + expressions + "]"); + logger.trace("Instantiating command parameter " + name + " with value [" + value + "] and expressions: [" + expressions + "]"); this.name = name; this.operator = operator; this.value = value; for (Expression expr : expressions) { - this.expressions.put(expr.toString(), expr); + this.expressions.add(expr); } } + + public CommandParameter (String name, String operator, Expression... expressions) { + logger.trace("Instantiating command parameter " + name + " with expressions: [" + expressions + "]"); + this.name = name; + this.operator = operator; + for (Expression expr : expressions) { + this.expressions.add(expr); + } + } + public CommandParameter (String name, String operator, String value) { if (!nologparams.contains(name)) logger.trace("Instantiating command parameter '" + name + "' with String: [" + value + "]"); @@ -57,19 +65,66 @@ public class CommandParameter implements Serializable { return name; } - public Map getExpressions () { + public List getExpressions () { return expressions; } + public List getExpressions(String... expressionFields) { + List requestedFields = Arrays.asList(expressionFields); + List exprs = new ArrayList(); + for (Expression expr : expressions) { + if (requestedFields.contains(expr.getField())) { + exprs.add(expr); + } + } + return exprs; + } + public void addExpression(Expression expression) { logger.debug("Adding expression [" + expression + "] to '" + name + "'"); - this.expressions.put(expression.toString(),expression); + this.expressions.add(expression); } public void removeExpression(Expression expression) { - this.expressions.remove(expression.toString()); + for (Expression expr : expressions) { + if (expr.toString().equals(expression.toString())) { + expressions.remove(expr); + break; + } + } + } + + public void removeExpressionsAfter (Expression expression, String... expressionFields) { + List exprFieldsToRemove = Arrays.asList(expressionFields); + int fromIdx = 0; + for (Expression expr : expressions) { + fromIdx++; + if (expr.toString().equals(expression.toString())) { + break; + } + } + if (fromIdx candidatesForRemoval = expressions.subList(fromIdx, expressions.size()).iterator(); + while (candidatesForRemoval.hasNext()) { + Expression exp = candidatesForRemoval.next(); + if (exprFieldsToRemove.contains(exp.getField())) { + expressions.remove(exp); + } + } + } } + public void removeExpressions (String... expressionFields) { + List fieldsToRemove = Arrays.asList(expressionFields); + Iterator i = expressions.iterator(); + while (i.hasNext()) { + Expression expr = i.next(); + if (fieldsToRemove.contains(expr.getField())) { + logger.trace("Removing expression: " + expr.toString()); + i.remove(); + } + } + } public boolean hasOperator() { return operator != null; @@ -79,6 +134,19 @@ public class CommandParameter implements Serializable { return value != null && value.length()>0; } + public boolean hasExpressions() { + return expressions.size()>0; + } + + public boolean hasExpressions(String expressionField) { + for (Expression expr : expressions) { + if (expr.getField().equals(expressionField)) { + return true; + } + } + return false; + } + public String getEncodedQueryString () { try { return name + operator + URLEncoder.encode(getValueWithExpressions(),"UTF-8"); @@ -94,12 +162,11 @@ public class CommandParameter implements Serializable { public String getValueWithExpressions () { StringBuilder completeValue = new StringBuilder((value==null ? "" : value)); - for (String key : expressions.keySet()) { - completeValue.append(" and " + expressions.get(key)); + for (Expression expr : expressions) { + completeValue.append(" and " + expr.toString()); } - return completeValue.toString(); - - } + return completeValue.toString(); + } @Override public boolean equals (Object otherParameter) { @@ -122,8 +189,8 @@ public class CommandParameter implements Serializable { CommandParameter newParam = new CommandParameter(name); newParam.value = this.value; newParam.operator = this.operator; - for (String key : expressions.keySet()) { - newParam.addExpression(expressions.get(key).copy()); + for (Expression expr : expressions) { + newParam.addExpression(expr.copy()); } return newParam; } diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/Expression.java b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/Expression.java index 3e93e49..3c377e2 100644 --- a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/Expression.java +++ b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/Expression.java @@ -1,28 +1,59 @@ package com.indexdata.mkjsf.pazpar2.commands; import java.io.Serializable; +import java.util.StringTokenizer; + +import org.apache.log4j.Logger; import com.indexdata.mkjsf.pazpar2.commands.Expression; public class Expression implements Serializable { private static final long serialVersionUID = -751704027842027769L; + private static Logger logger = Logger.getLogger(Expression.class); String leftEntity; String operator; String rightEntity; - public Expression (String leftEntity, String operator, String rightEntity) { + String label; + + public Expression (String leftEntity, String operator, String rightEntity, String label) { this.leftEntity = leftEntity; this.operator = operator; this.rightEntity = rightEntity; + this.label = label; + } + + public Expression (String expressionString) { + StringTokenizer tokenizer = new StringTokenizer(expressionString,"="); + this.leftEntity = tokenizer.nextToken(); + this.operator = "="; + this.rightEntity = tokenizer.nextToken(); + this.label=rightEntity; } public Expression copy() { - return new Expression(leftEntity,operator,rightEntity); + logger.trace("Copying " + this.toString()); + return new Expression(leftEntity, operator, rightEntity, label); } public String toString() { return leftEntity + operator + rightEntity; } - + public String getLabel() { + return label; + } + + public String getField () { + return leftEntity; + } + + public String getOperator() { + return operator; + } + + public String getValue() { + return rightEntity; + } + } diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/FilterParameter.java b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/FilterParameter.java new file mode 100644 index 0000000..0d540a2 --- /dev/null +++ b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/FilterParameter.java @@ -0,0 +1,50 @@ +package com.indexdata.mkjsf.pazpar2.commands; + +import org.apache.log4j.Logger; + +public class FilterParameter extends CommandParameter { + + private static final long serialVersionUID = -3697328835895528654L; + private static Logger logger = Logger.getLogger(FilterParameter.class); + + public FilterParameter(String name) { + super(name); + } + + public FilterParameter(Expression... expressions) { + super("filter", "=", expressions); + } + + public String getValueWithExpressions () { + StringBuilder completeValue = new StringBuilder(""); + boolean first = true; + for (Expression expr : expressions) { + if (!first) + completeValue.append(","); + else + first=false; + completeValue.append(pz2escape(expr.toString())); + } + return completeValue.toString(); + } + + public String pz2escape (String expressionString) { + String escaped = expressionString.replaceAll("\\\\","\\\\\\\\"); + escaped = escaped.replaceAll(",","\\\\,"); + escaped = escaped.replaceAll("\\|", "\\\\|"); + return escaped; + } + + public FilterParameter copy() { + logger.trace("Copying parameter '"+ name + "' for modification"); + FilterParameter newParam = new FilterParameter(name); + newParam.value = this.value; + newParam.operator = this.operator; + for (Expression expr : expressions) { + newParam.addExpression(expr.copy()); + } + return newParam; + } + + +} diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/LimitParameter.java b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/LimitParameter.java new file mode 100644 index 0000000..b86c27f --- /dev/null +++ b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/LimitParameter.java @@ -0,0 +1,52 @@ +package com.indexdata.mkjsf.pazpar2.commands; + +import org.apache.log4j.Logger; + +public class LimitParameter extends CommandParameter { + + private static final long serialVersionUID = -1410691265213389826L; + private static Logger logger = Logger.getLogger(LimitParameter.class); + + public LimitParameter(String name) { + super(name); + } + + public LimitParameter(Expression... expressions) { + super("limit", "=", expressions); + } + + public String getValueWithExpressions () { + StringBuilder completeValue = new StringBuilder(""); + boolean first = true; + for (Expression expr : expressions) { + if (!first) + completeValue.append(","); + else + first=false; + completeValue.append(pz2escape(expr.toString())); + logger.trace("valueWithExpressions so far: [" + completeValue + "]"); + } + return completeValue.toString(); + } + + public String pz2escape (String expressionString) { + String escaped = expressionString.replaceAll("\\\\","\\\\\\\\"); + escaped = escaped.replaceAll(",","\\\\,"); + escaped = escaped.replaceAll("\\|", "\\\\|"); + return escaped; + } + + + public LimitParameter copy() { + logger.trace("Copying parameter '"+ name + "' for modification"); + LimitParameter newParam = new LimitParameter(name); + newParam.value = this.value; + newParam.operator = this.operator; + for (Expression expr : expressions) { + newParam.addExpression(expr.copy()); + } + return newParam; + } + + +} diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/Pazpar2Command.java b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/Pazpar2Command.java index c7bff40..7c0ec74 100644 --- a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/Pazpar2Command.java +++ b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/Pazpar2Command.java @@ -124,20 +124,46 @@ public abstract class Pazpar2Command implements Serializable { public void removeParametersInState() { parameters = new HashMap(); } - + + public void addExpression(String parameterName, Expression expression) { + Pazpar2Command copy = this.copy(); + copy.getParameter(parameterName).addExpression(expression); + checkInState(copy); + } + + public void removeExpression(String parameterName, Expression expression) { + Pazpar2Command copy = this.copy(); + copy.getParameter(parameterName).removeExpression(expression); + checkInState(copy); + } + + public void removeExpressionsAfter(String parameterName, Expression expression,String... expressionFields) { + Pazpar2Command copy = this.copy(); + copy.getParameter(parameterName).removeExpressionsAfter(expression,expressionFields); + checkInState(copy); + } + + public void removeExpressions(String parameterName, String... expressionFields) { + Pazpar2Command copy = this.copy(); + copy.getParameter(parameterName).removeExpressions(expressionFields); + if (!getParameter(parameterName).hasValue() && !getParameter(parameterName).hasExpressions()) { + copy.parameters.remove(parameterName); + } + checkInState(copy); + } public boolean hasParameters () { return (parameters.keySet().size()>0); } public boolean hasParameterValue(String parameterName) { - return (parameters.get(parameterName) != null && parameters.get(parameterName).hasValue()); + return (parameters.get(parameterName) != null && (parameters.get(parameterName).hasValue())); } - + public String getEncodedQueryString () { StringBuilder queryString = new StringBuilder("command="+name); for (CommandParameter parameter : parameters.values()) { - if (parameter.hasValue()) { + if (parameter.hasValue() || parameter.hasExpressions()) { queryString.append("&"+parameter.getEncodedQueryString()); } } @@ -147,7 +173,7 @@ public abstract class Pazpar2Command implements Serializable { public String getValueWithExpressions() { StringBuilder value = new StringBuilder(""); for (CommandParameter parameter : parameters.values()) { - if (parameter.hasValue()) { + if (parameter.hasValue() || parameter.hasExpressions()) { value.append("&" + parameter.getName() + parameter.operator + parameter.getValueWithExpressions()); } } @@ -156,6 +182,7 @@ public abstract class Pazpar2Command implements Serializable { @Override public boolean equals (Object otherCommand) { + logger.trace("Comparing commands ["+this.toString()+"] and ["+otherCommand.toString() +"]"); return ((otherCommand instanceof Pazpar2Command) && this.getValueWithExpressions().equals(((Pazpar2Command) otherCommand).getValueWithExpressions())); diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/SearchCommand.java b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/SearchCommand.java index f2eb3be..c094d24 100644 --- a/src/main/java/com/indexdata/mkjsf/pazpar2/commands/SearchCommand.java +++ b/src/main/java/com/indexdata/mkjsf/pazpar2/commands/SearchCommand.java @@ -1,5 +1,7 @@ package com.indexdata.mkjsf.pazpar2.commands; +import java.util.List; + import javax.enterprise.context.SessionScoped; import javax.inject.Named; @@ -29,7 +31,6 @@ public class SearchCommand extends Pazpar2Command implements ServiceProxyCommand Pz2Service.get().getSearchClient().setSearchCommand(this); return super.run(); } - public void setQuery(String query) { setParameter(new CommandParameter("query","=",query)); @@ -40,44 +41,127 @@ public class SearchCommand extends Pazpar2Command implements ServiceProxyCommand } public void setFilter(String filterExpression) { - setParameter(new CommandParameter("filter","=",filterExpression)); + if (filterExpression != null && filterExpression.length()>0) { + setParameter(new FilterParameter(new Expression(filterExpression))); + } + } + + public void setFilter(String field, String operator, String value, String label) { + setParameter(new FilterParameter(new Expression(field,operator,value,label))); } public String getFilter() { - return getParameter("filter") == null ? null : getParameter("filter").getValueWithExpressions(); + return getParameter("filter") == null ? null : ((FilterParameter)getParameter("filter")).getValueWithExpressions(); } - public void addFilter(String filterExpression) { - // TODO: implement - if (hasParameterValue("filter")) { - setFilter(filterExpression); + public List getFilters() { + return getParameter("filter").getExpressions(); + } + + public void addFilter(String field, String operator, String value, String label) { + if (getParameter("filter") == null) { + setFilter(field + operator + value); } else { - getParameter("filter"); + getParameter("filter").addExpression(new Expression(field,operator,value,(label != null ? label : value))); } - throw new UnsupportedOperationException("removeFilter(filterExpression) yet to be implemented."); } public void removeFilters () { removeParameter("filter"); } - public void removeFilter(String filterExpression) { - // TODO: implement - throw new UnsupportedOperationException("removeFilter(filterExpression) yet to be implemented."); + public void removeFilter(String field, String operator, String value) { + removeExpression("filter",new Expression(field, operator, value, null)); } - + + public void removeFiltersAfter(String field, String operator, String value) { + removeExpressionsAfter("filter",new Expression(field,operator,value,null)); + } + public boolean hasFilter () { return getFilter().length()>0; } - public void setLimit (String limitExpression) { - setParameter(new CommandParameter("limit","=",limitExpression)); + public void setLimit (String limitExpression) { + if (limitExpression != null && limitExpression.length()>0) { + setParameter(new LimitParameter(new Expression(limitExpression))); + } } + public void setLimit(String field, String operator, String value, String label) { + setParameter(new LimitParameter(new Expression(field,operator,value,label))); + } + public String getLimit () { - return getParameterValue("limit"); + return getParameter("limit") == null ? null : ((FilterParameter)getParameter("limit")).getValueWithExpressions(); + } + + public List getLimitExpressions() { + return getParameter("limit").getExpressions(); + } + + public boolean hasLimitExpression(String... expressionFields) { + logger.trace("Checking for limit expression for " + expressionFields); + for (String field : expressionFields) { + if (getLimitExpressions(field) != null && getLimitExpressions(field).size()>0) { + logger.trace("Limit expression found (" + field + ")"); + return true; + } + } + logger.trace("No limit expressions found"); + return false; + } + + public Expression getOneLimitExpression(String expressionField) { + List exprs = getLimitExpressions(expressionField); + if (exprs != null && exprs.size()>0) { + if (exprs.size()>1) { + logger.warn("More that one limit expression found for [" + expressionField + "] but only asked to return the first one"); + } + return exprs.get(0); + } else { + return null; + } + } + + public List getLimitExpressions(String... expressionFields) { + logger.trace("Checking for limit parameter"); + if (parameters.get("limit")!=null) { + logger.trace("Found"); + return getParameter("limit").getExpressions(expressionFields); + } else { + logger.trace("Not found"); + return null; + } + } + + public void addLimit(String field, String operator, String value, String label) { + if (getParameter("limit") == null) { + setLimit(field, operator, value, label); + } else { + addExpression("limit",new Expression(field,operator,value,label)); + } + } + + public void removeLimits() { + removeParameter("limit"); + } + + public void removeLimits(String... fields) { + removeExpressions("limit",fields); + } + + public void removeLimit(String field, String operator, String value) { + removeExpression("limit",new Expression(field, operator, value, null)); + } + + public void removeLimitsAfter(String field, String operator, String value, String... fields) { + removeExpressionsAfter("limit",new Expression(field,operator,value,null),fields); + } + + public void setStartrecs (String startrecs) { setParameter(new CommandParameter("startrecs","=",startrecs)); } @@ -120,15 +204,14 @@ public class SearchCommand extends Pazpar2Command implements ServiceProxyCommand /** - * Sets a facet, in CQL, to restrict the current results, - * then executes the search + * Sets a facet, in CQL, to restrict the current results * * @param facetKey i.e. 'au' for author * @param term i.e. 'Dickens, Charles' */ public void setFacet(String facetKey, String term) { if (term != null && term.length()>0) { - getParameter("query").addExpression(new Expression(facetKey,"=",term)); + getParameter("query").addExpression(new Expression(facetKey,"=",term,null)); } } @@ -151,8 +234,7 @@ public class SearchCommand extends Pazpar2Command implements ServiceProxyCommand } /** - * Removes a facet set by setFacet(...), then executes - * the search. + * Removes a facet set by setFacet(...) * * Will not remove facets set by setFacetOnQuery(...) * @@ -161,7 +243,7 @@ public class SearchCommand extends Pazpar2Command implements ServiceProxyCommand */ public void removeFacet(String facetKey, String term) { if (getParameter("query") != null) { - getParameter("query").removeExpression(new Expression(facetKey,"=",term)); + getParameter("query").removeExpression(new Expression(facetKey,"=",term,null)); } } -- 1.7.10.4