From dfcf60a5faa136dbdb104b76799d30f4437f6906 Mon Sep 17 00:00:00 2001 From: "Niels Erik G. Nielsen" Date: Mon, 13 May 2013 14:36:05 -0400 Subject: [PATCH] Disentangles update() logic. Adds option for early feedback. 'search' and 'record' commands are disentangled from the general update() logic, in particular there is no longer recursion into update() in cases where a 'search' is needed before a 'show', say. Dedicated doSearch and doRecord methods are added with the intention of clarifying things. Also adds an option for feedback right after 'search' returns, by having update(show,stat,bytarget,termlist) skip processing on the first round-trip. The UI thus have a change to detect that a search has started and notify the user (before it would need to wait for the first update of show,stat,.. etc). For setups with dozens or even hundreds of targets the wait for the first sign of activity can otherwise be many seconds. --- .../java/com/indexdata/mkjsf/pazpar2/Pz2Bean.java | 79 ++++++++++++++------ .../com/indexdata/mkjsf/pazpar2/Pz2Interface.java | 6 ++ .../mkjsf/pazpar2/data/SearchResponse.java | 9 +++ 3 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/Pz2Bean.java b/src/main/java/com/indexdata/mkjsf/pazpar2/Pz2Bean.java index 16abd12..d7a9235 100644 --- a/src/main/java/com/indexdata/mkjsf/pazpar2/Pz2Bean.java +++ b/src/main/java/com/indexdata/mkjsf/pazpar2/Pz2Bean.java @@ -24,6 +24,7 @@ import com.indexdata.mkjsf.errors.ConfigurationException; import com.indexdata.mkjsf.errors.ErrorCentral; import com.indexdata.mkjsf.errors.ErrorHelper; import com.indexdata.mkjsf.pazpar2.commands.CommandParameter; +import com.indexdata.mkjsf.pazpar2.commands.Pazpar2Command; import com.indexdata.mkjsf.pazpar2.commands.Pazpar2Commands; import com.indexdata.mkjsf.pazpar2.data.RecordResponse; import com.indexdata.mkjsf.pazpar2.data.ResponseDataObject; @@ -118,7 +119,20 @@ public class Pz2Bean implements Pz2Interface, StateListener, Configurable, Seria pzreq.getRecord().removeParametersInState(); pzreq.getShow().setParameterInState(new CommandParameter("start","=",0)); logger.debug(Utils.objectId(this) + " is searching using "+pzreq.getCommand("search").getUrlEncodedParameterValue("query")); - doCommand("search"); + doCommand("search"); + } + + public String doRecord() { + ResponseDataObject responseObject = doCommand("record"); + if (pzreq.getRecord().hasParameterValue("offset") || + pzreq.getRecord().hasParameterValue("checksum")) { + RecordResponse recordResponse = new RecordResponse(); + recordResponse.setType("record"); + recordResponse.setXml(responseObject.getXml()); + recordResponse.setAttribute("activeclients", "0"); + pzresp.put("record", recordResponse); + } + return pzresp.getRecord().getActiveClients(); } /** @@ -160,15 +174,25 @@ public class Pz2Bean implements Pz2Interface, StateListener, Configurable, Seria public String update (String commands) { logger.info("Request to update: " + commands); try { - if (! validateUpdateRequest(commands)) { + if (!validateUpdateRequest(commands)) { return "0"; + } else if (commands.equals("search")) { + doSearch(); + return ""; + } else if (commands.equals("record")) { + return doRecord(); + } else if (pzresp.getSearch().isNew()) { + logger.info("New search. Marking it old, then returning 'new' to trigger another round-trip."); + pzresp.getSearch().setIsNew(false); + return "new"; } else { handleQueryStateChanges(commands); - if (!commands.equals("search") && pzresp.getSearch().hasApplicationError()) { + if (pzresp.getSearch().hasApplicationError()) { logger.error("The command(s) " + commands + " are cancelled because the latest search command had an error."); return "0"; } else { logger.debug("Processing request for " + commands); + List threadList = new ArrayList(); StringTokenizer tokens = new StringTokenizer(commands,","); while (tokens.hasMoreElements()) { @@ -192,22 +216,10 @@ public class Pz2Bean implements Pz2Interface, StateListener, Configurable, Seria if (ResponseParser.docTypes.contains(responseObject.getType())) { pzresp.put(commandName, responseObject); } else { - if (commandName.equals("record") && - (pzreq.getRecord().hasParameterValue("offset") || - pzreq.getRecord().hasParameterValue("checksum"))) { - RecordResponse recordResponse = new RecordResponse(); - recordResponse.setType("record"); - recordResponse.setXml(responseObject.getXml()); - recordResponse.setAttribute("activeclients", "0"); - pzresp.put(commandName, recordResponse); - } + logger.info("Unknown doc type [" + responseObject.getType() + "]. Was not cached."); } } - if (commands.equals("record")) { - return pzresp.getRecord().getActiveClients(); - } else { - return pzresp.getActiveClients(); - } + return pzresp.getActiveClients(); } } } catch (ClassCastException cce) { @@ -240,7 +252,8 @@ public class Pz2Bean implements Pz2Interface, StateListener, Configurable, Seria return ""; } else { pzreq.getRecord().setId(recId); - return doCommand("record"); + doCommand("record"); + return pzresp.getRecord().getActiveClients(); } } @@ -285,18 +298,38 @@ public class Pz2Bean implements Pz2Interface, StateListener, Configurable, Seria logger.debug("Found pending record ID change. Doing record before updating " + commands); stateMgr.hasPendingStateChange("record",false); if (pzreq.getCommand("record").hasParameterValue("id")) { - update("record"); + doRecord(); } else { pzresp.put("record", new RecordResponse()); } } } - protected String doCommand(String commandName) { - logger.debug(pzreq.getCommand(commandName).getEncodedQueryString() + ": Results for "+ pzreq.getCommand("search").getEncodedQueryString()); - return update(commandName); + /** + * Validates the request then executes the command and parses the response. + * If the parsed response is of a known type it will be cached in 'pzresp' + * + * @param commandName The command to be executed + * @return An XML response parsed to form a response data object + */ + protected ResponseDataObject doCommand(String commandName) { + ResponseDataObject responseObject = null; + if (validateUpdateRequest(commandName)) { + logger.debug(pzreq.getCommand(commandName).getEncodedQueryString() + ": Results for "+ pzreq.getCommand("search").getEncodedQueryString()); + Pazpar2Command command = pzreq.getCommand(commandName); + long start = System.currentTimeMillis(); + HttpResponseWrapper commandResponse = searchClient.executeCommand(command); + long end = System.currentTimeMillis(); + logger.debug("Executed " + command.getCommandName() + " in " + (end-start) + " ms." ); + responseLogger.debug("Response was: " + commandResponse.getResponseString()); + responseObject = ResponseParser.getParser().getDataObject((ClientCommandResponse)commandResponse); + if (ResponseParser.docTypes.contains(responseObject.getType())) { + pzresp.put(commandName, responseObject); + } + } + return responseObject; } - + @Override public void stateUpdated(String commandName) { logger.debug("State change reported for [" + commandName + "]"); diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/Pz2Interface.java b/src/main/java/com/indexdata/mkjsf/pazpar2/Pz2Interface.java index 7b0b863..b8b6d24 100644 --- a/src/main/java/com/indexdata/mkjsf/pazpar2/Pz2Interface.java +++ b/src/main/java/com/indexdata/mkjsf/pazpar2/Pz2Interface.java @@ -19,6 +19,12 @@ public interface Pz2Interface extends Serializable { public void doSearch(); /** + * Executes a Pazpar2 record requests + * @return Active clients for the record request + */ + public String doRecord(); + + /** * Updates display data objects by issuing the following pazpar2 commands: * 'show', 'stat', 'termlist' and 'bytarget'. * diff --git a/src/main/java/com/indexdata/mkjsf/pazpar2/data/SearchResponse.java b/src/main/java/com/indexdata/mkjsf/pazpar2/data/SearchResponse.java index 909e05b..c905c26 100644 --- a/src/main/java/com/indexdata/mkjsf/pazpar2/data/SearchResponse.java +++ b/src/main/java/com/indexdata/mkjsf/pazpar2/data/SearchResponse.java @@ -3,9 +3,18 @@ package com.indexdata.mkjsf.pazpar2.data; public class SearchResponse extends ResponseDataObject { private static final long serialVersionUID = -3320013021497018972L; + private boolean isNew = true; public String getStatus() { return getOneElementValue("status"); } + + public boolean isNew () { + return isNew; + } + + public void setIsNew (boolean isNew) { + this.isNew = isNew; + } } -- 1.7.10.4