From: Niels Erik G. Nielsen Date: Thu, 14 Mar 2013 17:11:09 +0000 (-0400) Subject: Making room for a Service Proxy client X-Git-Tag: v0.0.7~204 X-Git-Url: http://lists.indexdata.dk/?a=commitdiff_plain;h=5ce9f5404929b726668d3332c5bdba4dbd1d1d1f;p=mkjsf-moved-to-github.git Making room for a Service Proxy client Work in progress for building in SP support alongside straight Pazpar2 support, generalizing a 'SearchClient' for the purpose --- diff --git a/pom.xml b/pom.xml index bd9c16d..5eda446 100644 --- a/pom.xml +++ b/pom.xml @@ -30,7 +30,12 @@ org.jboss.weld.servlet weld-servlet 1.1.10.Final - + + + org.apache.httpcomponents + httpclient + 4.0-beta1 + com.indexdata diff --git a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/CommandResponse.java b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/CommandResponse.java new file mode 100644 index 0000000..7a92019 --- /dev/null +++ b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/CommandResponse.java @@ -0,0 +1,7 @@ +package com.indexdata.pz2utils4jsf.pazpar2; + +public interface CommandResponse { + public int getStatusCode(); + public String getContentType(); + public String getResponseString(); +} diff --git a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/CommandThread.java b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/CommandThread.java index 95dcf1e..a2c10b8 100644 --- a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/CommandThread.java +++ b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/CommandThread.java @@ -5,9 +5,6 @@ import java.io.IOException; import org.apache.log4j.Logger; -import com.indexdata.masterkey.pazpar2.client.ClientCommand; -import com.indexdata.masterkey.pazpar2.client.Pazpar2Client; -import com.indexdata.masterkey.pazpar2.client.Pazpar2HttpResponse; import com.indexdata.masterkey.pazpar2.client.exceptions.Pazpar2ErrorException; import com.indexdata.pz2utils4jsf.pazpar2.data.CommandError; @@ -15,11 +12,11 @@ public class CommandThread extends Thread { private static Logger logger = Logger.getLogger(CommandThread.class); Pazpar2Command command; - Pazpar2Client client; + SearchClient client; private ByteArrayOutputStream baos = new ByteArrayOutputStream(); private StringBuilder response = new StringBuilder(""); - public CommandThread (Pazpar2Command command, Pazpar2Client client) { + public CommandThread (Pazpar2Command command, SearchClient client) { this.command = command; this.client = client; } @@ -35,22 +32,22 @@ public class CommandThread extends Thread { * */ public void run() { - ClientCommand clientCommand = new ClientCommand(command.getName(), command.getEncodedQueryString()); + if (command.getName().equals("search")) { - client.setSearchCommand(clientCommand); + client.setSearchCommand(command); } try { long start = System.currentTimeMillis(); - Pazpar2HttpResponse httpResponse = client.executeCommand(clientCommand, baos); - if (httpResponse.getStatusCode()==200) { - response.append(baos.toString("UTF-8")); - } else if (httpResponse.getStatusCode()==417) { + CommandResponse commandResponse = client.executeCommand(command, baos); + if (commandResponse.getStatusCode()==200) { + response.append(commandResponse.getResponseString()); + } else if (commandResponse.getStatusCode()==417) { logger.error("Pazpar2 status code 417: " + baos.toString("UTF-8")); response.append(CommandError.insertPazpar2ErrorXml(command.getName(), "Expectation failed (417)", baos.toString("UTF-8"))); } else { String resp = baos.toString("UTF-8"); - logger.error("Pazpar2 status code was " + httpResponse.getStatusCode() + ": " + resp); - throw new Pazpar2ErrorException(resp,httpResponse.getStatusCode(),resp,null); + logger.error("Pazpar2 status code was " + commandResponse.getStatusCode() + ": " + resp); + throw new Pazpar2ErrorException(resp,commandResponse.getStatusCode(),resp,null); } long end = System.currentTimeMillis(); logger.debug("Executed " + command.getName() + " in " + (end-start) + " ms." ); diff --git a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/ProxyPz2Client.java b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/ProxyPz2Client.java new file mode 100644 index 0000000..349b0ff --- /dev/null +++ b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/ProxyPz2Client.java @@ -0,0 +1,102 @@ +package com.indexdata.pz2utils4jsf.pazpar2; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import javax.enterprise.context.SessionScoped; +import javax.enterprise.inject.Alternative; +import javax.inject.Named; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.util.EntityUtils; +import org.apache.log4j.Logger; + +import com.indexdata.masterkey.pazpar2.client.exceptions.Pazpar2ErrorException; +import com.indexdata.pz2utils4jsf.config.Pz2Configurator; +import com.indexdata.pz2utils4jsf.utils.Utils; + +@Named @SessionScoped @Alternative +public class ProxyPz2Client implements SearchClient { + + private static final long serialVersionUID = -4031644009579840277L; + private static Logger logger = Logger.getLogger(ProxyPz2Client.class); + + ProxyPz2ResponseHandler handler = new ProxyPz2ResponseHandler(); + HttpClient client = new DefaultHttpClient(); + + public ProxyPz2Client(HttpClient client) { + } + + @Override + public void configure (Pz2Configurator configurator) { + logger.info(Utils.objectId(this) + " is configuring itself using the provided " + Utils.objectId(configurator)); + + } + + /** + * Makes the request + * @param request + * @return HTTP response as a String + * @throws ClientProtocolException + * @throws IOException + */ + private String send(Pazpar2Command command) throws ClientProtocolException, IOException { + String url = command.getEncodedQueryString(); + logger.debug("Sending request "+url); + HttpGet httpget = new HttpGet(url); + byte[] response = client.execute(httpget, handler); + return new String(response); + } + + + public class ProxyPz2ResponseHandler implements ResponseHandler { + private StatusLine statusLine = null; + public byte[] handleResponse(HttpResponse response) throws ClientProtocolException, IOException { + HttpEntity entity = response.getEntity(); + statusLine = response.getStatusLine(); + if (entity != null) { + return EntityUtils.toByteArray(entity); + } else { + return null; + } + } + public int getStatusCode() { + return statusLine.getStatusCode(); + } + public String getReasonPhrase() { + return statusLine.getReasonPhrase(); + } + } + + public int getStatusCode () { + return handler.getStatusCode(); + } + + public String getReasonPhrase() { + return handler.getReasonPhrase(); + } + + @Override + public void setSearchCommand(Pazpar2Command command) { + // Do nothing, Service Proxy is handling this + } + + @Override + public CommandResponse executeCommand(Pazpar2Command command, + ByteArrayOutputStream baos) throws Pazpar2ErrorException, IOException { + String response = send(command); + return new ProxyPz2ClientCommandResponse(getStatusCode(), response); + } + + public ProxyPz2Client cloneMe() { + return this; + } + +} diff --git a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/ProxyPz2ClientCommandResponse.java b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/ProxyPz2ClientCommandResponse.java new file mode 100644 index 0000000..67cbe45 --- /dev/null +++ b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/ProxyPz2ClientCommandResponse.java @@ -0,0 +1,28 @@ +package com.indexdata.pz2utils4jsf.pazpar2; + +public class ProxyPz2ClientCommandResponse implements CommandResponse { + + private int statusCode = 0; + private String content = null; + + public ProxyPz2ClientCommandResponse(int statusCode, String content) { + this.statusCode = statusCode; + this.content = content; + } + + @Override + public int getStatusCode() { + return statusCode; + } + + @Override + public String getContentType() { + return "text/xml;charset=UTF-8"; + } + + @Override + public String getResponseString() { + return content; + } + +} diff --git a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/Pz2Bean.java b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/Pz2Bean.java index fd3e478..dff3142 100644 --- a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/Pz2Bean.java +++ b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/Pz2Bean.java @@ -28,8 +28,9 @@ public class Pz2Bean implements Pz2Interface, Serializable { private static Logger logger = Logger.getLogger(Pz2Bean.class); Pz2Session pz2; - @Inject Pz2Configurator pz2conf; - + @Inject Pz2Configurator configurator; + @Inject SearchClient searchClient; + public Pz2Bean () { logger.info("Instantiating pz2 bean [" + Utils.objectId(this) + "]"); } @@ -38,8 +39,10 @@ public class Pz2Bean implements Pz2Interface, Serializable { public void initiatePz2Session() { logger.debug(Utils.objectId(this) + " will instantiate a Pz2Session next."); pz2 = new Pz2Session(); - logger.debug(Utils.objectId(this) + " will forward configuration to the new Pz2Session [" + Utils.objectId(pz2) + "]"); - pz2.init(pz2conf); + logger.info("Using [" + Utils.objectId(searchClient) + "] configured by [" + + Utils.objectId(configurator) + "] on session [" + + Utils.objectId(pz2) + "]" ); + pz2.init(searchClient,configurator); } /* (non-Javadoc) diff --git a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/Pz2Session.java b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/Pz2Session.java index 17f8545..58b296f 100644 --- a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/Pz2Session.java +++ b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/Pz2Session.java @@ -1,7 +1,5 @@ package com.indexdata.pz2utils4jsf.pazpar2; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -13,15 +11,8 @@ import javax.inject.Named; import org.apache.log4j.Logger; -import com.indexdata.masterkey.pazpar2.client.ClientCommand; -import com.indexdata.masterkey.pazpar2.client.Pazpar2Client; -import com.indexdata.masterkey.pazpar2.client.Pazpar2ClientConfiguration; -import com.indexdata.masterkey.pazpar2.client.Pazpar2ClientGeneric; -import com.indexdata.masterkey.pazpar2.client.exceptions.Pazpar2ErrorException; -import com.indexdata.masterkey.pazpar2.client.exceptions.ProxyErrorException; import com.indexdata.pz2utils4jsf.config.Pz2Configurator; import com.indexdata.pz2utils4jsf.controls.ResultsPager; -import com.indexdata.pz2utils4jsf.errors.ConfigurationError; import com.indexdata.pz2utils4jsf.errors.ConfigurationException; import com.indexdata.pz2utils4jsf.errors.ErrorHelper; import com.indexdata.pz2utils4jsf.errors.ErrorInterface; @@ -40,53 +31,42 @@ import com.indexdata.pz2utils4jsf.utils.Utils; @Named @SessionScoped public class Pz2Session implements Pz2Interface { - + + private static final long serialVersionUID = 3947514708343320514L; private static Logger logger = Logger.getLogger(Pz2Session.class); private Map dataObjects = new ConcurrentHashMap(); private QueryStates queryStates = new QueryStates(); + private ErrorHelper errorHelper = null; - private static final long serialVersionUID = 3947514708343320514L; - private Pazpar2ClientConfiguration cfg = null; - private Pazpar2Client client = null; + private List configurationErrors = null; + private SearchClient searchClient = null; private TargetFilter targetFilter = null; private ResultsPager pager = null; - private ErrorHelper errorHelper = null; - private List configurationErrors = null; - + public Pz2Session () { logger.info("Instantiating pz2 session object [" + Utils.objectId(this) + "]"); } - public void init(Pz2Configurator pz2conf) { - if (client==null) { - configurationErrors = new ArrayList(); - errorHelper = new ErrorHelper(pz2conf); - logger.info(Utils.objectId(this) + " is configuring itself using the provided " + Utils.objectId(pz2conf)); - try { - cfg = new Pazpar2ClientConfiguration(pz2conf.getConfig()); - } catch (ProxyErrorException pe) { - logger.error("Could not configure Pazpar2 client: " + pe.getMessage()); - configurationErrors.add(new ConfigurationError("Pz2Client Config","ProxyError","Could not configure Pazpar2 client: " + pe.getMessage(),errorHelper)); - } catch (ConfigurationException io) { - logger.error("Could not configure Pazpar2 client: " + io.getMessage()); - configurationErrors.add(new ConfigurationError("Pz2Client Config","ProxyError","Could not configure Pazpar2 client: " + io.getMessage(),errorHelper)); - } - if (cfg != null) { - try { - client = new Pazpar2ClientGeneric(cfg); - } catch (ProxyErrorException pe) { - logger.error("Could not instantiate Pazpar2 client: " + pe.getMessage()); - configurationErrors.add(new ConfigurationError("Pz2Client error","ProxyError","Could not create Pazpar2 client: " +pe.getMessage(),errorHelper)); - } - if (hasConfigurationErrors()) { - logger.info("Found " + configurationErrors.size() + " configuration errors"); - } - } - resetDataObjects(); - } else { - logger.warn("Attempt to configure session but it already has a configured client"); - } + public void init(SearchClient searchClient, Pz2Configurator configurator) { + configurationErrors = new ArrayList(); + errorHelper = new ErrorHelper(configurator); + logger.debug(Utils.objectId(this) + " will configure search client for the session"); + try { + searchClient.configure(configurator); + + // The cloning is a hack: + // At the time of writing this search client is injected using Weld. + // However, the client is used for asynchronously sending off requests + // to the server AND propagation of context to threads is not supported. + // Trying so will throw a WELD-001303 error. To avoid that, a context + // free client is spawned from the context dependent one. + this.searchClient = searchClient.cloneMe(); + + } catch (ConfigurationException e) { + logger.info("Found " + configurationErrors.size() + " configuration errors"); + } + resetDataObjects(); } public void doSearch(String query) { @@ -126,7 +106,7 @@ public class Pz2Session implements Pz2Interface { List threadList = new ArrayList(); StringTokenizer tokens = new StringTokenizer(commands,","); while (tokens.hasMoreElements()) { - threadList.add(new CommandThread(getCommand(tokens.nextToken()),client)); + threadList.add(new CommandThread(getCommand(tokens.nextToken()),searchClient)); } for (CommandThread thread : threadList) { thread.start(); @@ -140,7 +120,9 @@ public class Pz2Session implements Pz2Interface { } for (CommandThread thread : threadList) { String commandName = thread.getCommand().getName(); - Pazpar2ResponseData responseObject = Pazpar2ResponseParser.getParser().getDataObject(thread.getResponse()); + String response = thread.getResponse(); + logger.debug("Response was: " + response); + Pazpar2ResponseData responseObject = Pazpar2ResponseParser.getParser().getDataObject(response); dataObjects.put(commandName, responseObject); } return getActiveClients(); diff --git a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/SearchClient.java b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/SearchClient.java new file mode 100644 index 0000000..7534150 --- /dev/null +++ b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/SearchClient.java @@ -0,0 +1,20 @@ +package com.indexdata.pz2utils4jsf.pazpar2; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.Serializable; + +import com.indexdata.masterkey.pazpar2.client.Pazpar2HttpResponse; +import com.indexdata.masterkey.pazpar2.client.exceptions.Pazpar2ErrorException; +import com.indexdata.pz2utils4jsf.config.Pz2Configurator; +import com.indexdata.pz2utils4jsf.errors.ConfigurationException; + + +public interface SearchClient extends Serializable { + + public void configure(Pz2Configurator configurator) throws ConfigurationException; + public void setSearchCommand(Pazpar2Command command); + public CommandResponse executeCommand(Pazpar2Command command, ByteArrayOutputStream baos) throws Pazpar2ErrorException, IOException; + public SearchClient cloneMe(); + +} diff --git a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/StraightPz2Client.java b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/StraightPz2Client.java new file mode 100644 index 0000000..187b928 --- /dev/null +++ b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/StraightPz2Client.java @@ -0,0 +1,76 @@ +package com.indexdata.pz2utils4jsf.pazpar2; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import javax.enterprise.context.SessionScoped; +import javax.enterprise.inject.Alternative; +import javax.inject.Named; + +import org.apache.log4j.Logger; + +import com.indexdata.masterkey.pazpar2.client.ClientCommand; +import com.indexdata.masterkey.pazpar2.client.Pazpar2Client; +import com.indexdata.masterkey.pazpar2.client.Pazpar2ClientConfiguration; +import com.indexdata.masterkey.pazpar2.client.Pazpar2ClientGeneric; +import com.indexdata.masterkey.pazpar2.client.Pazpar2HttpResponse; +import com.indexdata.masterkey.pazpar2.client.exceptions.Pazpar2ErrorException; +import com.indexdata.masterkey.pazpar2.client.exceptions.ProxyErrorException; +import com.indexdata.pz2utils4jsf.config.Pz2Configurator; +import com.indexdata.pz2utils4jsf.errors.ConfigurationException; +import com.indexdata.pz2utils4jsf.utils.Utils; + +@Named @SessionScoped @Alternative +public class StraightPz2Client implements SearchClient { + + private static final long serialVersionUID = 5414266730169982028L; + private static Logger logger = Logger.getLogger(StraightPz2Client.class); + private Pazpar2Client client = null; + private Pazpar2ClientConfiguration cfg = null; + + public StraightPz2Client() {} + + public void configure(Pz2Configurator configurator) throws ConfigurationException { + logger.info(Utils.objectId(this) + " is configuring itself using the provided " + Utils.objectId(configurator)); + try { + cfg = new Pazpar2ClientConfiguration(configurator.getConfig()); + } catch (ProxyErrorException pe) { + logger.error("Could not configure Pazpar2 client: " + pe.getMessage()); + throw new ConfigurationException("Could not configure StraightPz2Client: "+ pe.getMessage(),pe); + } + if (cfg != null) { + try { + client = new Pazpar2ClientGeneric(cfg); + } catch (ProxyErrorException pe) { + logger.error("Could not configure Pazpar2 client: " + pe.getMessage()); + throw new ConfigurationException("Could not configure StraightPz2Client: "+ pe.getMessage(),pe); + } + } else { + logger.error("There was a problem creating StraightPz2Client. Client is null after configuration."); + throw new ConfigurationException("Pazpar2Client is null after configuration"); + } + } + + @Override + public void setSearchCommand(Pazpar2Command command) { + ClientCommand clientCommand = new ClientCommand(command.getName(), command.getEncodedQueryString()); + client.setSearchCommand(clientCommand); + + } + + @Override + public CommandResponse executeCommand(Pazpar2Command command, ByteArrayOutputStream baos) + throws Pazpar2ErrorException, IOException { + ClientCommand clientCommand = new ClientCommand(command.getName(), command.getEncodedQueryString()); + Pazpar2HttpResponse pz2HttpResponse = client.executeCommand(clientCommand, baos); + return new StraightPz2CommandResponse(pz2HttpResponse,baos); + } + + public StraightPz2Client cloneMe() { + logger.debug("Cloning StraightPz2Client"); + StraightPz2Client clone = new StraightPz2Client(); + clone.client = this.client; + clone.cfg = this.cfg; + return clone; + } +} diff --git a/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/StraightPz2CommandResponse.java b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/StraightPz2CommandResponse.java new file mode 100644 index 0000000..d744e7b --- /dev/null +++ b/src/main/java/com/indexdata/pz2utils4jsf/pazpar2/StraightPz2CommandResponse.java @@ -0,0 +1,39 @@ +package com.indexdata.pz2utils4jsf.pazpar2; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; + +import com.indexdata.masterkey.pazpar2.client.Pazpar2HttpResponse; + +public class StraightPz2CommandResponse implements CommandResponse { + + private Pazpar2HttpResponse pz2httpResponse = null; + private ByteArrayOutputStream content = null; + + public StraightPz2CommandResponse(Pazpar2HttpResponse pz2response, ByteArrayOutputStream content) { + pz2httpResponse = pz2response; + this.content = content; + } + + @Override + public int getStatusCode() { + return pz2httpResponse.getStatusCode(); + } + + @Override + public String getContentType() { + return pz2httpResponse.getContentType(); + } + + @Override + public String getResponseString() { + try { + return content.toString("UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + + +}