1 package com.indexdata.mkjsf.pazpar2.commands;
\r
3 import java.io.Serializable;
\r
4 import java.util.HashMap;
\r
5 import java.util.Map;
\r
6 import java.util.StringTokenizer;
\r
8 import org.apache.log4j.Logger;
\r
10 import com.indexdata.mkjsf.pazpar2.ClientCommandResponse;
\r
11 import com.indexdata.mkjsf.pazpar2.HttpResponseWrapper;
\r
12 import com.indexdata.mkjsf.pazpar2.Pz2Service;
\r
13 import com.indexdata.mkjsf.pazpar2.SearchClient;
\r
14 import com.indexdata.mkjsf.pazpar2.commands.sp.ServiceProxyCommand;
\r
15 import com.indexdata.mkjsf.pazpar2.data.ResponseDataObject;
\r
16 import com.indexdata.mkjsf.pazpar2.data.ResponseParser;
\r
17 import com.indexdata.mkjsf.pazpar2.data.Responses;
\r
20 * Represents a generic Pazpar2 or Service Proxy command with all its current parameters, and has
\r
21 * methods for executing the command against the currently selected Pazpar2 service</p>
\r
22 * <p>Being an abstract class it only has generic methods for getting and setting parameters.
\r
23 * Implementing classes are supposed to create named getters and setters for convenient access
\r
24 * to parameters from the UI.</p>
\r
25 * <p>Parameters can be set with or without notifying the state manager.<p>
\r
27 * <p><i>Note: Internally the application has to be able to set parameters without state changes
\r
28 * - for instance to avoid eternal feedback when copying parameter from one state to the next. A
\r
29 * setting from the UI should spawn a new search state however.</i></p>
\r
31 * @author Niels Erik
\r
34 public abstract class Pazpar2Command implements Serializable {
\r
36 private static Logger logger = Logger.getLogger(Pazpar2Command.class);
\r
37 private static final long serialVersionUID = -6825491856480675917L;
\r
38 protected String name = "";
\r
39 protected Map<String,CommandParameter> parameters = new HashMap<String,CommandParameter>();
\r
41 public Pazpar2Command () {
\r
44 public void setCommandName(String name) {
\r
48 public Pazpar2Command (String name) {
\r
53 * Commands must implement this method to provide an completely detached, deep clone of
\r
56 * The clone is needed by the state manager to transfer commands with current setting
\r
57 * from one state to the next.
\r
59 * Whenever a non-standard attribute is added to a command class, the copy method must
\r
60 * be updated to ensure that the new attribute is brought over as well.
\r
62 * @return a Pazpar2 command of the given type
\r
64 public abstract Pazpar2Command copy ();
\r
66 public String getCommandName() {
\r
71 * Executes the command with the currently selected parameters against
\r
72 * the currently selected Pazpar2 service
\r
74 * @return Response data object based on the Pazpar2 service response.
\r
76 public ResponseDataObject run() {
\r
77 return run(Pz2Service.get().getSearchClient(),
\r
78 Pz2Service.get().getPzresp());
\r
82 * Executes the commands with the currently selected parameters, while adding
\r
83 * the parameters provided
\r
84 * @param parameters A list of parameters on the form [key=value]
\r
86 * @return Response data object based on the Pazpar2 service response
\r
88 public ResponseDataObject runWith(String parameters) {
\r
89 StringTokenizer expressions = new StringTokenizer(parameters,";");
\r
90 while (expressions.hasMoreTokens()) {
\r
91 String expression = expressions.nextToken();
\r
92 StringTokenizer tokenizer = new StringTokenizer(expression,"=");
\r
93 String name = (String) tokenizer.nextElement();
\r
94 String value = (String) tokenizer.nextElement();
\r
95 CommandParameter commandParameter = new CommandParameter(name,"=",value);
\r
96 setParameterInState(commandParameter);
\r
102 * Executes the command in a thread.
\r
104 * Note: Client and Responses must be provided because at this point
\r
105 * CDI beans cannot be retrieved from within a thread.
\r
111 public ResponseDataObject run(SearchClient client,Responses pzresp) {
\r
112 logger.debug("Running " + getCommandName() + " using " + client);
\r
113 HttpResponseWrapper httpResponse = client.executeCommand(this);
\r
114 logger.debug("Parsing response for " + getCommandName());
\r
115 ResponseDataObject responseObject = ResponseParser.getParser().getDataObject((ClientCommandResponse) httpResponse);
\r
116 logger.trace("Storing response for " + getCommandName());
\r
117 pzresp.put(getCommandName(), responseObject);
\r
118 return responseObject;
\r
123 * Sets a parameter on this command and notifies the state manager
\r
126 * @param parameter
\r
128 public void setParameter (CommandParameter parameter) {
\r
129 Pazpar2Command copy = this.copy();
\r
130 logger.trace(name + " command: setting parameter [" + parameter.getName() + "=" + parameter.getValueWithExpressions() + "]");
\r
131 copy.parameters.put(parameter.getName(),parameter);
\r
132 checkInState(copy);
\r
136 * Sets multiple parameters on the command and notifies the state
\r
137 * manager -- once -- about the change
\r
141 public void setParameters (CommandParameter... params) {
\r
142 Pazpar2Command copy = this.copy();
\r
143 for (CommandParameter param : params) {
\r
144 logger.trace(name + " command: setting parameter [" + param.getName() + "=" + param.getValueWithExpressions() + "]");
\r
145 copy.parameters.put(param.getName(),param);
\r
147 checkInState(copy);
\r
151 * Sets multiple parameters on this command without notifying the state manager.
\r
152 * Typically used when one parameter setting should automatically trigger
\r
153 * other parameters to be reset to defaults etc. Intended to avoid
\r
154 * useless proliferation of states
\r
158 public void setParametersInState (CommandParameter... params) {
\r
159 for (CommandParameter param : params) {
\r
160 logger.trace(name + " command: setting parameter [" + param.getName() + "=" + param.getValueWithExpressions() + "] silently");
\r
161 parameters.put(param.getName(),param);
\r
166 * Sets a parameter on this command without notifying the state manager.
\r
167 * Typically used when one parameter setting should automatically trigger
\r
168 * other parameters to be reset to defaults etc. Intended to avoid
\r
169 * useless proliferation of states
\r
173 public void setParameterInState (CommandParameter parameter) {
\r
174 logger.trace(name + " command: setting parameter [" + parameter.getName() + "=" + parameter.getValueWithExpressions() + "] silently");
\r
175 parameters.put(parameter.getName(),parameter);
\r
180 * Retrieves a command parameter by parameter name
\r
182 * @param name of the parameter
\r
183 * @return CommandParameter
\r
185 public CommandParameter getParameter (String name) {
\r
186 return parameters.get(name);
\r
190 * Removes a parameter completely and notifies the state manager
\r
193 * @param name of the parameter to remove
\r
195 public void removeParameter (String name) {
\r
196 Pazpar2Command copy = this.copy();
\r
197 copy.parameters.remove(name);
\r
198 checkInState(copy);
\r
202 * Removes multiple parameters completely and notifies the state manager
\r
203 * -- once -- about the change
\r
205 * @param name of the parameter to remove
\r
207 public void removeParameters() {
\r
208 Pazpar2Command copy = this.copy();
\r
209 copy.parameters = new HashMap<String,CommandParameter>();
\r
210 checkInState(copy);
\r
215 * Removes all parameters without notifying the state manager. For instance
\r
216 * used in case of change of Pazpar2 service or renewed login to a service.
\r
219 public void removeParametersInState() {
\r
220 parameters = new HashMap<String,CommandParameter>();
\r
224 * Adds an expression to an ordered list of expressions on a given parameter
\r
225 * and notifies the state manager of the change
\r
227 * @param parameterName name of the parameter to add the expression to
\r
228 * @param expression
\r
230 public void addExpression(String parameterName, Expression expression) {
\r
231 Pazpar2Command copy = this.copy();
\r
232 copy.getParameter(parameterName).addExpression(expression);
\r
233 checkInState(copy);
\r
236 public void removeExpression(String parameterName, Expression expression) {
\r
237 Pazpar2Command copy = this.copy();
\r
238 copy.getParameter(parameterName).removeExpression(expression);
\r
239 checkInState(copy);
\r
242 public void removeExpressionsAfter(String parameterName, Expression expression,String... expressionFields) {
\r
243 Pazpar2Command copy = this.copy();
\r
244 copy.getParameter(parameterName).removeExpressionsAfter(expression,expressionFields);
\r
245 checkInState(copy);
\r
248 public void removeExpressions(String parameterName, String... expressionFields) {
\r
249 Pazpar2Command copy = this.copy();
\r
250 copy.getParameter(parameterName).removeExpressions(expressionFields);
\r
251 if (!getParameter(parameterName).hasValue() && !getParameter(parameterName).hasExpressions()) {
\r
252 copy.parameters.remove(parameterName);
\r
254 checkInState(copy);
\r
257 public boolean hasParameters () {
\r
258 return (parameters.keySet().size()>0);
\r
261 public boolean hasParameterValue(String parameterName) {
\r
262 return (parameters.get(parameterName) != null && (parameters.get(parameterName).hasValue()));
\r
265 public String getEncodedQueryString () {
\r
266 StringBuilder queryString = new StringBuilder("command="+name);
\r
267 for (CommandParameter parameter : parameters.values()) {
\r
268 if (parameter.hasValue() || parameter.hasExpressions()) {
\r
269 queryString.append("&"+parameter.getEncodedQueryString());
\r
272 return queryString.toString();
\r
275 public String getValueWithExpressions() {
\r
276 StringBuilder value = new StringBuilder("");
\r
277 for (CommandParameter parameter : parameters.values()) {
\r
278 if (parameter.hasValue() || parameter.hasExpressions()) {
\r
279 value.append("&" + parameter.getName() + parameter.operator + parameter.getValueWithExpressions());
\r
282 return value.toString();
\r
286 public boolean equals (Object otherCommand) {
\r
287 logger.trace("Comparing commands ["+this.toString()+"] and ["+otherCommand.toString() +"]");
\r
289 ((otherCommand instanceof Pazpar2Command)
\r
290 && this.getValueWithExpressions().equals(((Pazpar2Command) otherCommand).getValueWithExpressions()));
\r
294 public int hashCode () {
\r
295 return getValueWithExpressions().hashCode();
\r
298 public String toString () {
\r
299 return parameters.toString();
\r
302 public String getParameterValue(String parameterName) {
\r
303 return getParameter(parameterName)==null ? "" : getParameter(parameterName).getValueWithExpressions();
\r
307 public String getUrlEncodedParameterValue(String parameterName) {
\r
308 return getParameter(parameterName).getEncodedQueryString();
\r
312 public void setSession (String sessionId) {
\r
313 setParameter(new CommandParameter("session","=",sessionId));
\r
316 public String getSession() {
\r
317 return getParameterValue("session");
\r
321 * Notifies the state manager that this command changed a parameter
\r
325 protected void checkInState(Pazpar2Command command) {
\r
326 Pz2Service.get().getStateMgr().checkIn(command);
\r
330 * Implementing classes must provide their Service Proxy
\r
331 * extension command if any extension parameters exists,
\r
332 * or -- just to be polite -- 'this' if there is no
\r
333 * Service Proxy extension to the given command.
\r
336 public abstract ServiceProxyCommand getSp();
\r
339 * Here implementing commands publish whether they only
\r
340 * apply to the Service Proxy or can be executed
\r
341 * against straight Pazpar2 as well. This is convenient for a
\r
342 * UI that switches between service types either
\r
343 * deployment time or run time.
\r
345 * @return false if the command applies to straight Pazpar2
\r
347 public abstract boolean spOnly();
\r