Changes response object naming
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / mkjsf / pazpar2 / Pz2Bean.java
1 package com.indexdata.mkjsf.pazpar2;\r
2 \r
3 import java.io.Serializable;\r
4 import java.util.ArrayList;\r
5 import java.util.Arrays;\r
6 import java.util.HashMap;\r
7 import java.util.List;\r
8 import java.util.Map;\r
9 import java.util.StringTokenizer;\r
10 \r
11 import javax.annotation.PostConstruct;\r
12 import javax.enterprise.context.SessionScoped;\r
13 import javax.inject.Inject;\r
14 import javax.inject.Named;\r
15 \r
16 import org.apache.log4j.Logger;\r
17 \r
18 import com.indexdata.mkjsf.config.Configurable;\r
19 import com.indexdata.mkjsf.config.Configuration;\r
20 import com.indexdata.mkjsf.config.ConfigurationReader;\r
21 import com.indexdata.mkjsf.controls.ResultsPager;\r
22 import com.indexdata.mkjsf.errors.ConfigurationError;\r
23 import com.indexdata.mkjsf.errors.ConfigurationException;\r
24 import com.indexdata.mkjsf.errors.ErrorCentral;\r
25 import com.indexdata.mkjsf.errors.ErrorHelper;\r
26 import com.indexdata.mkjsf.pazpar2.commands.CommandParameter;\r
27 import com.indexdata.mkjsf.pazpar2.commands.Pazpar2Commands;\r
28 import com.indexdata.mkjsf.pazpar2.data.Pazpar2ResponseData;\r
29 import com.indexdata.mkjsf.pazpar2.data.Pazpar2ResponseParser;\r
30 import com.indexdata.mkjsf.pazpar2.data.Pazpar2Responses;\r
31 import com.indexdata.mkjsf.pazpar2.data.RecordResponse;\r
32 import com.indexdata.mkjsf.pazpar2.sp.auth.ServiceProxyUser;\r
33 import com.indexdata.mkjsf.pazpar2.state.StateListener;\r
34 import com.indexdata.mkjsf.pazpar2.state.StateManager;\r
35 import com.indexdata.mkjsf.utils.Utils;\r
36 \r
37 @Named("pz2") @SessionScoped\r
38 public class Pz2Bean implements Pz2Interface, StateListener, Configurable, Serializable {\r
39 \r
40   private static final String MODULE_NAME = "service";\r
41   private static String SERVICE_TYPE_TBD = "TBD", SERVICE_TYPE_PZ2 = "PZ2", SERVICE_TYPE_SP = "SP";\r
42   private static final List<String> serviceTypes = \r
43                 Arrays.asList(SERVICE_TYPE_PZ2,SERVICE_TYPE_SP,SERVICE_TYPE_TBD);\r
44   private String serviceType = SERVICE_TYPE_TBD;\r
45   private List<String> serviceProxyUrls = new ArrayList<String>();\r
46   public static final String SERVICE_PROXY_URL_LIST = "SERVICE_PROXY_URL_LIST";\r
47   private List<String> pazpar2Urls = new ArrayList<String>();\r
48   public static final String PAZPAR2_URL_LIST = "PAZPAR2_URL_LIST";\r
49 \r
50 \r
51   private static final long serialVersionUID = 3440277287081557861L;\r
52   private static Logger logger = Logger.getLogger(Pz2Bean.class);\r
53   private static Logger responseLogger = Logger.getLogger("com.indexdata.mkjsf.pazpar2.responses");   \r
54   protected Pz2Client pz2Client = null;\r
55   protected ServiceProxyClient spClient = null;\r
56   protected SearchClient searchClient = null;  \r
57     \r
58   @Inject ConfigurationReader configurator;\r
59   @Inject StateManager stateMgr;\r
60   @Inject Pazpar2Commands pzreq;\r
61   @Inject Pazpar2Responses pzresp;\r
62   @Inject ErrorCentral errors;\r
63   @Inject ServiceProxyUser user;\r
64   \r
65   protected ResultsPager pager = null; \r
66   \r
67   protected ErrorHelper errorHelper = null;\r
68               \r
69   public Pz2Bean () {\r
70     logger.info("Instantiating pz2 bean [" + Utils.objectId(this) + "]");    \r
71   }\r
72   \r
73   @PostConstruct\r
74   public void postConstruct() {    \r
75     logger.debug("Pz2Bean post-construct: Configurator is " + configurator);\r
76     logger.debug(Utils.objectId(this) + " will instantiate a Pz2Client next.");\r
77     pz2Client = new Pz2Client();\r
78     configureClient(pz2Client,configurator);\r
79     spClient = new ServiceProxyClient();\r
80     configureClient(spClient,configurator);\r
81     try {\r
82       this.configure(configurator);\r
83     } catch (ConfigurationException e) {\r
84       logger.error("There was a problem configuring the Pz2Bean (\"pz2\")");\r
85       e.printStackTrace();\r
86     }    \r
87     stateMgr.addStateListener(this);    \r
88   }  \r
89   \r
90   public void configureClient(SearchClient client, ConfigurationReader configReader) {\r
91     logger.debug(Utils.objectId(this) + " will configure search client for the session");\r
92     try {\r
93       client.configure(configReader);            \r
94     } catch (ConfigurationException e) {\r
95       logger.debug("Pz2Bean adding configuration error");\r
96       errors.addConfigurationError(new ConfigurationError("Search Client","Configuration",e.getMessage()));                \r
97     } \r
98     logger.info(configReader.document());\r
99     pzresp.reset();    \r
100   }\r
101   \r
102   public void resetSearchAndResults () {\r
103     pzreq.getRecord().removeParametersInState();\r
104     pzreq.getSearch().removeParametersInState();\r
105     pzresp.reset();    \r
106   }\r
107 \r
108     \r
109   public void doSearch(String query) {\r
110     pzreq.getSearch().setParameter(new CommandParameter("query","=",query));     \r
111     doSearch();\r
112   }\r
113 \r
114   public void doSearch() { \r
115     stateMgr.hasPendingStateChange("search",false);\r
116     pzresp.reset();\r
117     // resets some record and show command parameters without \r
118     // changing state or creating state change feedback\r
119     pzreq.getRecord().removeParametersInState();        \r
120     pzreq.getShow().setParameterInState(new CommandParameter("start","=",0));    \r
121     logger.debug(Utils.objectId(this) + " is searching using "+pzreq.getCommand("search").getUrlEncodedParameterValue("query"));\r
122     doCommand("search");    \r
123   }\r
124       \r
125   /**\r
126    * Refreshes 'show', 'stat', 'termlist', and 'bytarget' data object from pazpar2\r
127    * \r
128    * @return Number of activeclients at the time of the 'show' command.\r
129    */\r
130   public String update () {\r
131     logger.debug("Updating show,stat,termlist,bytarget from pazpar2");\r
132     return update("show,stat,termlist,bytarget");\r
133   }\r
134    \r
135   /**\r
136    * Refreshes the data objects listed in 'commands' from pazpar2\r
137    * \r
138    * @param commands\r
139    * @return Number of activeclients at the time of the 'show' command\r
140    */\r
141   public String update (String commands) {\r
142     try {\r
143     if (! errors.hasConfigurationErrors()) {\r
144       if (commandsAreValid(commands)) {\r
145         if (hasQuery() || (commands.equals("record") && pzreq.getCommand("record").hasParameterValue("recordquery"))) {\r
146           handleQueryStateChanges(commands);\r
147           logger.debug("Processing request for " + commands); \r
148           List<CommandThread> threadList = new ArrayList<CommandThread>();\r
149           StringTokenizer tokens = new StringTokenizer(commands,",");\r
150           while (tokens.hasMoreElements()) {          \r
151             threadList.add(new CommandThread(pzreq.getCommand(tokens.nextToken()),searchClient));            \r
152           }\r
153           for (CommandThread thread : threadList) {\r
154             thread.start();\r
155           }\r
156           for (CommandThread thread : threadList) {\r
157             try {\r
158               thread.join();\r
159             } catch (InterruptedException e) {\r
160               e.printStackTrace();\r
161             }\r
162           }\r
163           for (CommandThread thread : threadList) {\r
164              String commandName = thread.getCommand().getCommandName();\r
165              HttpResponseWrapper response = thread.getCommandResponse();\r
166              responseLogger.debug("Response was: " + response.getResponseString());\r
167              Pazpar2ResponseData responseObject = Pazpar2ResponseParser.getParser().getDataObject(response.getResponseString());\r
168              if (Pazpar2ResponseParser.docTypes.contains(responseObject.getType())) {\r
169                pzresp.put(commandName, responseObject);\r
170              } else {\r
171                if (commandName.equals("record") && \r
172                    (pzreq.getRecord().hasParameterValue("offset") ||\r
173                     pzreq.getRecord().hasParameterValue("checksum"))) {\r
174                  RecordResponse recordResponse = new RecordResponse();\r
175                  recordResponse.setType("record");\r
176                  recordResponse.setXml(responseObject.getXml());\r
177                  recordResponse.setAttribute("activeclients", "0");\r
178                  pzresp.put(commandName, recordResponse);\r
179                }\r
180              }\r
181           }\r
182           if (commands.equals("record")) {\r
183             return pzresp.getRecord().getActiveClients();\r
184           } else {\r
185             return pzresp.getActiveClients();\r
186           }  \r
187         } else {\r
188           logger.debug("Skipped requests for " + commands + " as there's not yet a query."); \r
189           pzresp.reset();\r
190           return "0";\r
191         }\r
192       } else {\r
193         logger.error("Did not attemt to run command(s) due to a validation error.");\r
194         return "0";\r
195       }\r
196     } else {      \r
197       logger.error("Did not attempt to execute query since there are configuration errors.");\r
198       return "0";\r
199     }\r
200     } catch (ClassCastException cce) {\r
201       cce.printStackTrace();    \r
202       return "";\r
203     } catch (NullPointerException npe) {\r
204       npe.printStackTrace();\r
205       return "";\r
206     } catch (Exception e) {\r
207       e.printStackTrace();\r
208       return "";\r
209     }\r
210     \r
211   }\r
212   \r
213   public boolean commandsAreValid(String commands) {\r
214     if (commands.equals("record")) {\r
215       if (!pzreq.getCommand("record").hasParameterValue("id")) {\r
216         logger.error("Attempt to send record command without the id parameter");\r
217         return false;\r
218       }\r
219     }\r
220     return true;\r
221   }\r
222                                 \r
223   public String toggleRecord (String recId) {\r
224     if (hasRecord(recId)) {\r
225       pzreq.getRecord().removeParameters();  \r
226       pzresp.put("record", new RecordResponse());\r
227       return "";\r
228     } else {\r
229       pzreq.getRecord().setId(recId);\r
230       return doCommand("record");\r
231     }\r
232   }\r
233   \r
234   @Override\r
235   public boolean hasRecord (String recId) {\r
236     return pzreq.getCommand("record").hasParameters() && pzresp.getRecord().getRecId().equals(recId);\r
237   }\r
238         \r
239   public String getCurrentStateKey () {    \r
240     return stateMgr.getCurrentState().getKey();\r
241   }\r
242       \r
243   public void setCurrentStateKey(String key) {       \r
244     stateMgr.setCurrentStateKey(key);\r
245   }\r
246       \r
247   protected boolean hasQuery() {        \r
248     return pzreq.getCommand("search").hasParameterValue("query"); \r
249   }\r
250     \r
251     \r
252   @Override\r
253   public ResultsPager getPager () {\r
254     if (pager == null) {\r
255       pager = new ResultsPager(pzresp);      \r
256     } \r
257     return pager;      \r
258   }\r
259   \r
260   @Override\r
261   public ResultsPager setPager (int pageRange) {\r
262     pager =  new ResultsPager(pzresp,pageRange,pzreq);\r
263     return pager;\r
264   }\r
265     \r
266   protected void handleQueryStateChanges (String commands) {\r
267     if (stateMgr.hasPendingStateChange("search") && hasQuery()) { \r
268       logger.debug("Found pending search change. Doing search before updating " + commands);      \r
269       doSearch();\r
270     } \r
271     if (stateMgr.hasPendingStateChange("record") && ! commands.equals("record")) {        \r
272       logger.debug("Found pending record ID change. Doing record before updating " + commands);\r
273       stateMgr.hasPendingStateChange("record",false);\r
274       if (pzreq.getCommand("record").hasParameterValue("id")) {\r
275         update("record");\r
276       } else {         \r
277         pzresp.put("record", new RecordResponse());\r
278       }\r
279     }\r
280   }\r
281   \r
282   protected String doCommand(String commandName) {             \r
283     logger.debug(pzreq.getCommand(commandName).getEncodedQueryString() + ": Results for "+ pzreq.getCommand("search").getEncodedQueryString());\r
284     return update(commandName);\r
285   }\r
286   \r
287   @Override\r
288   public void stateUpdated(String commandName) {\r
289     logger.debug("State change reported for [" + commandName + "]");\r
290     if (commandName.equals("show")) {\r
291       logger.debug("Updating show");\r
292       update(commandName);\r
293     } \r
294   }\r
295   \r
296   public void setServiceProxyUrl(String url) {\r
297     searchClient = spClient;\r
298     setServiceType(SERVICE_TYPE_SP);\r
299     setServiceUrl(url);\r
300   }\r
301   \r
302   public String getServiceProxyUrl () {\r
303     if (isServiceProxyService()) {\r
304       return spClient.getServiceUrl();\r
305     } else {\r
306       return "";\r
307     }\r
308   }\r
309   \r
310   public void setPazpar2Url(String url) {\r
311     searchClient = pz2Client;\r
312     setServiceType(SERVICE_TYPE_PZ2);\r
313     setServiceUrl(url);\r
314   }\r
315   \r
316   public String getPazpar2Url() {\r
317     if (isPazpar2Service()) {\r
318       return pz2Client.getServiceUrl();\r
319     } else {\r
320       return "";\r
321     }\r
322   }\r
323 \r
324   \r
325   @Override\r
326   public void setServiceUrl(String url) {\r
327     if (url!=null && searchClient != null && !url.equals(searchClient.getServiceUrl())) {\r
328       pzreq.getRecord().removeParametersInState();\r
329       pzreq.getSearch().removeParametersInState();\r
330       pzresp.reset();\r
331       user.clear();\r
332       searchClient.setServiceUrl(url);\r
333     }    \r
334   }\r
335   \r
336   public String getServiceUrl() {\r
337     return (searchClient!=null ? searchClient.getServiceUrl() : "");\r
338   }\r
339   \r
340   public boolean getServiceUrlIsDefined() {\r
341     return (searchClient != null && searchClient.hasServiceUrl());\r
342   }\r
343   \r
344   public List<String> getServiceProxyUrls() {\r
345     List<String> urls = new ArrayList<String>();\r
346     urls.add("");\r
347     urls.addAll(serviceProxyUrls);\r
348     return urls;\r
349   }\r
350   \r
351   public List<String> getPazpar2Urls () {\r
352     List<String> urls = new ArrayList<String>();\r
353     urls.add("");\r
354     urls.addAll(pazpar2Urls);\r
355     return urls;\r
356   }\r
357   \r
358   public String getServiceType () {\r
359     return serviceType;\r
360   }\r
361   \r
362   public boolean isPazpar2Service () {\r
363     return serviceType.equals(SERVICE_TYPE_PZ2);\r
364   }\r
365   \r
366   public boolean isServiceProxyService() {\r
367     return serviceType.equals(SERVICE_TYPE_SP);\r
368   }\r
369   \r
370   public boolean serviceIsToBeDecided () {\r
371     return serviceType.equals(SERVICE_TYPE_TBD);\r
372   }\r
373   \r
374   public ServiceProxyClient getSpClient () {\r
375     return spClient;\r
376   }  \r
377   \r
378   @Override\r
379   public boolean getAuthenticationRequired () {\r
380     return spClient.isAuthenticatingClient();\r
381   }\r
382 \r
383   @Override\r
384   public String getCheckHistory () {\r
385     return ":pz2watch:stateForm:windowlocationhash";\r
386   }\r
387     \r
388   @Override\r
389   public String getWatchActiveclients () {\r
390     return ":pz2watch:activeclientsForm:activeclientsField";\r
391   }\r
392   \r
393   @Override\r
394   public String getWatchActiveclientsRecord () {\r
395     return ":pz2watch:activeclientsForm:activeclientsFieldRecord";\r
396   }\r
397 \r
398   @Override\r
399   public void configure(ConfigurationReader reader)\r
400       throws ConfigurationException {\r
401     Configuration config = reader.getConfiguration(this);\r
402     if (config == null) {\r
403       serviceType = SERVICE_TYPE_TBD;\r
404     } else {\r
405       String service = config.get("TYPE");\r
406       if (service == null || service.length()==0) {\r
407         serviceType = SERVICE_TYPE_TBD;\r
408       } else if (serviceTypes.contains(service.toUpperCase())) {        \r
409         setServiceType(service.toUpperCase());\r
410       } else {\r
411         logger.error("Unknown serviceType type in configuration [" + service + "], can be one of " + serviceTypes);\r
412         serviceType = SERVICE_TYPE_TBD;\r
413       }\r
414       serviceProxyUrls = config.getMultiProperty(SERVICE_PROXY_URL_LIST,",");\r
415       pazpar2Urls = config.getMultiProperty(PAZPAR2_URL_LIST, ",");\r
416     }\r
417     logger.info("Service Type is configured to " + serviceType);\r
418     \r
419   }\r
420 \r
421   @Override\r
422   public Map<String, String> getDefaults() {\r
423     return new HashMap<String,String>();\r
424   }\r
425 \r
426   @Override\r
427   public String getModuleName() {\r
428     return MODULE_NAME;\r
429   }\r
430 \r
431   @Override\r
432   public List<String> documentConfiguration() {\r
433     return new ArrayList<String>();\r
434   }\r
435 \r
436   @Override\r
437   public void setServiceTypePZ2() {\r
438     setServiceType(SERVICE_TYPE_PZ2);    \r
439   }\r
440 \r
441   @Override\r
442   public void setServiceTypeSP() {\r
443     setServiceType(SERVICE_TYPE_SP);        \r
444   }\r
445 \r
446   @Override\r
447   public void setServiceTypeTBD() {\r
448     setServiceType(SERVICE_TYPE_TBD);    \r
449   }\r
450   \r
451   private void setServiceType(String type) {\r
452     if (!serviceType.equals(type)  &&\r
453         !serviceType.equals(SERVICE_TYPE_TBD)) {\r
454       resetSearchAndResults();\r
455     }\r
456     serviceType = type;\r
457     if (serviceType.equals(SERVICE_TYPE_PZ2)) {\r
458       searchClient = pz2Client;\r
459       logger.info("Setting a Pazpar2 client to serve requests.");\r
460     } else if (serviceType.equals(SERVICE_TYPE_SP)) {\r
461       searchClient = spClient;\r
462       logger.info("Setting a Service Proxy client to serve requests.");\r
463     } else {\r
464       logger.info("Clearing search client. No client defined to serve requests at this point.");\r
465       searchClient = null;\r
466     }\r
467   }\r
468   \r
469 }\r