Tweaks init command and init doc submission.
[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.ResponseDataObject;\r
29 import com.indexdata.mkjsf.pazpar2.data.ResponseParser;\r
30 import com.indexdata.mkjsf.pazpar2.data.Responses;\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 Responses 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.resetAllSessionData();    \r
100   }\r
101   \r
102   public void resetSearchAndRecordCommands () {\r
103     pzreq.getRecord().removeParametersInState();\r
104     pzreq.getSearch().removeParametersInState();   \r
105   }\r
106 \r
107     \r
108   public void doSearch(String query) {\r
109     pzreq.getSearch().setParameter(new CommandParameter("query","=",query));     \r
110     doSearch();\r
111   }\r
112 \r
113   public void doSearch() { \r
114     stateMgr.hasPendingStateChange("search",false);\r
115     pzresp.resetSearchResponses();\r
116     // resets some record and show command parameters without \r
117     // changing state or creating state change feedback\r
118     pzreq.getRecord().removeParametersInState();        \r
119     pzreq.getShow().setParameterInState(new CommandParameter("start","=",0));    \r
120     logger.debug(Utils.objectId(this) + " is searching using "+pzreq.getCommand("search").getUrlEncodedParameterValue("query"));\r
121     doCommand("search");    \r
122   }\r
123       \r
124   /**\r
125    * Refreshes 'show', 'stat', 'termlist', and 'bytarget' data object from pazpar2\r
126    * \r
127    * @return Number of activeclients at the time of the 'show' command.\r
128    */\r
129   public String update () {\r
130     logger.debug("Updating show,stat,termlist,bytarget from pazpar2");\r
131     return update("show,stat,termlist,bytarget");\r
132   }\r
133    \r
134   /**\r
135    * Refreshes the data objects listed in 'commands' from pazpar2\r
136    * \r
137    * @param commands\r
138    * @return Number of activeclients at the time of the 'show' command\r
139    */\r
140   public String update (String commands) {\r
141     try {\r
142     if (! errors.hasConfigurationErrors()) {\r
143       if (commandsAreValid(commands)) {\r
144         if (hasQuery() || (commands.equals("record") && pzreq.getCommand("record").hasParameterValue("recordquery"))) {\r
145           handleQueryStateChanges(commands);\r
146           logger.debug("Processing request for " + commands); \r
147           List<CommandThread> threadList = new ArrayList<CommandThread>();\r
148           StringTokenizer tokens = new StringTokenizer(commands,",");\r
149           while (tokens.hasMoreElements()) {          \r
150             threadList.add(new CommandThread(pzreq.getCommand(tokens.nextToken()),searchClient));            \r
151           }\r
152           for (CommandThread thread : threadList) {\r
153             thread.start();\r
154           }\r
155           for (CommandThread thread : threadList) {\r
156             try {\r
157               thread.join();\r
158             } catch (InterruptedException e) {\r
159               e.printStackTrace();\r
160             }\r
161           }\r
162           for (CommandThread thread : threadList) {\r
163              String commandName = thread.getCommand().getCommandName();\r
164              HttpResponseWrapper response = thread.getCommandResponse();\r
165              responseLogger.debug("Response was: " + response.getResponseString());\r
166              ResponseDataObject responseObject = ResponseParser.getParser().getDataObject(response.getResponseString());\r
167              if (ResponseParser.docTypes.contains(responseObject.getType())) {\r
168                pzresp.put(commandName, responseObject);\r
169              } else {\r
170                if (commandName.equals("record") && \r
171                    (pzreq.getRecord().hasParameterValue("offset") ||\r
172                     pzreq.getRecord().hasParameterValue("checksum"))) {\r
173                  RecordResponse recordResponse = new RecordResponse();\r
174                  recordResponse.setType("record");\r
175                  recordResponse.setXml(responseObject.getXml());\r
176                  recordResponse.setAttribute("activeclients", "0");\r
177                  pzresp.put(commandName, recordResponse);\r
178                }\r
179              }\r
180           }\r
181           if (commands.equals("record")) {\r
182             return pzresp.getRecord().getActiveClients();\r
183           } else {\r
184             return pzresp.getActiveClients();\r
185           }  \r
186         } else {\r
187           logger.debug("Skipped requests for " + commands + " as there's not yet a query."); \r
188           pzresp.resetSearchResponses();\r
189           return "0";\r
190         }\r
191       } else {\r
192         logger.debug("Did not attempt to run command(s) that were not ready.");\r
193         return "0";\r
194       }\r
195     } else {      \r
196       logger.error("Did not attempt to execute query since there are configuration errors.");\r
197       return "0";\r
198     }\r
199     } catch (ClassCastException cce) {\r
200       cce.printStackTrace();    \r
201       return "";\r
202     } catch (NullPointerException npe) {\r
203       npe.printStackTrace();\r
204       return "";\r
205     } catch (Exception e) {\r
206       e.printStackTrace();\r
207       return "";\r
208     }\r
209     \r
210   }\r
211   \r
212   public boolean commandsAreValid(String commands) {\r
213     if (commands.equals("record")) {\r
214       if (!pzreq.getCommand("record").hasParameterValue("id")) {\r
215         logger.debug("Attempt to send record command without the id parameter");\r
216         return false;\r
217       }\r
218     }\r
219     return true;\r
220   }\r
221                                 \r
222   public String toggleRecord (String recId) {\r
223     if (hasRecord(recId)) {\r
224       pzreq.getRecord().removeParameters();  \r
225       pzresp.put("record", new RecordResponse());\r
226       return "";\r
227     } else {\r
228       pzreq.getRecord().setId(recId);\r
229       return doCommand("record");\r
230     }\r
231   }\r
232   \r
233   @Override\r
234   public boolean hasRecord (String recId) {\r
235     return pzreq.getCommand("record").hasParameters() && pzresp.getRecord().getRecId().equals(recId);\r
236   }\r
237         \r
238   public String getCurrentStateKey () {    \r
239     return stateMgr.getCurrentState().getKey();\r
240   }\r
241       \r
242   public void setCurrentStateKey(String key) {       \r
243     stateMgr.setCurrentStateKey(key);\r
244   }\r
245       \r
246   protected boolean hasQuery() {        \r
247     return pzreq.getCommand("search").hasParameterValue("query"); \r
248   }\r
249     \r
250     \r
251   @Override\r
252   public ResultsPager getPager () {\r
253     if (pager == null) {\r
254       pager = new ResultsPager(pzresp);      \r
255     } \r
256     return pager;      \r
257   }\r
258   \r
259   @Override\r
260   public ResultsPager setPager (int pageRange) {\r
261     pager =  new ResultsPager(pzresp,pageRange,pzreq);\r
262     return pager;\r
263   }\r
264     \r
265   protected void handleQueryStateChanges (String commands) {\r
266     if (stateMgr.hasPendingStateChange("search") && hasQuery()) { \r
267       logger.debug("Found pending search change. Doing search before updating " + commands);      \r
268       doSearch();\r
269     } \r
270     if (stateMgr.hasPendingStateChange("record") && ! commands.equals("record")) {        \r
271       logger.debug("Found pending record ID change. Doing record before updating " + commands);\r
272       stateMgr.hasPendingStateChange("record",false);\r
273       if (pzreq.getCommand("record").hasParameterValue("id")) {\r
274         update("record");\r
275       } else {         \r
276         pzresp.put("record", new RecordResponse());\r
277       }\r
278     }\r
279   }\r
280   \r
281   protected String doCommand(String commandName) {             \r
282     logger.debug(pzreq.getCommand(commandName).getEncodedQueryString() + ": Results for "+ pzreq.getCommand("search").getEncodedQueryString());\r
283     return update(commandName);\r
284   }\r
285   \r
286   @Override\r
287   public void stateUpdated(String commandName) {\r
288     logger.debug("State change reported for [" + commandName + "]");\r
289     if (commandName.equals("show")) {\r
290       logger.debug("Updating show");\r
291       update(commandName);\r
292     } \r
293   }\r
294   \r
295   public void setServiceProxyUrl(String url) {\r
296     searchClient = spClient;\r
297     setServiceType(SERVICE_TYPE_SP);\r
298     setServiceUrl(url);\r
299   }\r
300   \r
301   public String getServiceProxyUrl () {\r
302     if (isServiceProxyService()) {\r
303       return spClient.getServiceUrl();\r
304     } else {\r
305       return "";\r
306     }\r
307   }\r
308   \r
309   public void setPazpar2Url(String url) {\r
310     searchClient = pz2Client;\r
311     setServiceType(SERVICE_TYPE_PZ2);\r
312     setServiceUrl(url);\r
313   }\r
314   \r
315   public String getPazpar2Url() {\r
316     if (isPazpar2Service()) {\r
317       return pz2Client.getServiceUrl();\r
318     } else {\r
319       return "";\r
320     }\r
321   }\r
322 \r
323   \r
324   @Override\r
325   public void setServiceUrl(String url) {\r
326     if (url!=null && searchClient != null && !url.equals(searchClient.getServiceUrl())) {\r
327       pzreq.getRecord().removeParametersInState();\r
328       pzreq.getSearch().removeParametersInState();\r
329       pzresp.resetAllSessionData();\r
330       user.clear();\r
331       searchClient.setServiceUrl(url);\r
332     }    \r
333   }\r
334   \r
335   public String getServiceUrl() {\r
336     return (searchClient!=null ? searchClient.getServiceUrl() : "");\r
337   }\r
338   \r
339   public boolean getServiceUrlIsDefined() {\r
340     return (searchClient != null && searchClient.hasServiceUrl());\r
341   }\r
342   \r
343   public List<String> getServiceProxyUrls() {\r
344     List<String> urls = new ArrayList<String>();\r
345     urls.add("");\r
346     urls.addAll(serviceProxyUrls);\r
347     return urls;\r
348   }\r
349   \r
350   public List<String> getPazpar2Urls () {\r
351     List<String> urls = new ArrayList<String>();\r
352     urls.add("");\r
353     urls.addAll(pazpar2Urls);\r
354     return urls;\r
355   }\r
356   \r
357   public String getServiceType () {\r
358     return serviceType;\r
359   }\r
360   \r
361   public boolean isPazpar2Service () {\r
362     return serviceType.equals(SERVICE_TYPE_PZ2);\r
363   }\r
364   \r
365   public boolean isServiceProxyService() {\r
366     return serviceType.equals(SERVICE_TYPE_SP);\r
367   }\r
368   \r
369   public boolean serviceIsToBeDecided () {\r
370     return serviceType.equals(SERVICE_TYPE_TBD);\r
371   }\r
372   \r
373   public ServiceProxyClient getSpClient () {\r
374     return spClient;\r
375   }  \r
376   \r
377   @Override\r
378   public boolean getAuthenticationRequired () {\r
379     return spClient.isAuthenticatingClient();\r
380   }\r
381 \r
382   @Override\r
383   public String getCheckHistory () {\r
384     return ":pz2watch:stateForm:windowlocationhash";\r
385   }\r
386     \r
387   @Override\r
388   public String getWatchActiveclients () {\r
389     return ":pz2watch:activeclientsForm:activeclientsField";\r
390   }\r
391   \r
392   @Override\r
393   public String getWatchActiveclientsRecord () {\r
394     return ":pz2watch:activeclientsForm:activeclientsFieldRecord";\r
395   }\r
396 \r
397   @Override\r
398   public void configure(ConfigurationReader reader)\r
399       throws ConfigurationException {\r
400     Configuration config = reader.getConfiguration(this);\r
401     if (config == null) {\r
402       serviceType = SERVICE_TYPE_TBD;\r
403     } else {\r
404       String service = config.get("TYPE");\r
405       if (service == null || service.length()==0) {\r
406         serviceType = SERVICE_TYPE_TBD;\r
407       } else if (serviceTypes.contains(service.toUpperCase())) {        \r
408         setServiceType(service.toUpperCase());\r
409       } else {\r
410         logger.error("Unknown serviceType type in configuration [" + service + "], can be one of " + serviceTypes);\r
411         serviceType = SERVICE_TYPE_TBD;\r
412       }\r
413       serviceProxyUrls = config.getMultiProperty(SERVICE_PROXY_URL_LIST,",");\r
414       pazpar2Urls = config.getMultiProperty(PAZPAR2_URL_LIST, ",");\r
415     }\r
416     logger.info("Service Type is configured to " + serviceType);\r
417     \r
418   }\r
419 \r
420   @Override\r
421   public Map<String, String> getDefaults() {\r
422     return new HashMap<String,String>();\r
423   }\r
424 \r
425   @Override\r
426   public String getModuleName() {\r
427     return MODULE_NAME;\r
428   }\r
429 \r
430   @Override\r
431   public List<String> documentConfiguration() {\r
432     return new ArrayList<String>();\r
433   }\r
434 \r
435   @Override\r
436   public void setServiceTypePZ2() {\r
437     setServiceType(SERVICE_TYPE_PZ2);    \r
438   }\r
439 \r
440   @Override\r
441   public void setServiceTypeSP() {\r
442     setServiceType(SERVICE_TYPE_SP);        \r
443   }\r
444 \r
445   @Override\r
446   public void setServiceTypeTBD() {\r
447     setServiceType(SERVICE_TYPE_TBD);    \r
448   }\r
449   \r
450   private void setServiceType(String type) {\r
451     if (!serviceType.equals(type)  &&\r
452         !serviceType.equals(SERVICE_TYPE_TBD)) {\r
453       resetSearchAndRecordCommands();\r
454       pzresp.resetAllSessionData();\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