Catches and reports missing web.xml init parameter
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / pz2utils4jsf / pazpar2 / Pz2Session.java
1 package com.indexdata.pz2utils4jsf.pazpar2;\r
2 \r
3 import java.io.IOException;\r
4 import java.util.ArrayList;\r
5 import java.util.List;\r
6 import java.util.Map;\r
7 import java.util.StringTokenizer;\r
8 import java.util.concurrent.ConcurrentHashMap;\r
9 \r
10 import javax.enterprise.context.SessionScoped;\r
11 import javax.inject.Named;\r
12 \r
13 import org.apache.log4j.Logger;\r
14 \r
15 import com.indexdata.masterkey.pazpar2.client.Pazpar2Client;\r
16 import com.indexdata.masterkey.pazpar2.client.Pazpar2ClientConfiguration;\r
17 import com.indexdata.masterkey.pazpar2.client.Pazpar2ClientGeneric;\r
18 import com.indexdata.masterkey.pazpar2.client.exceptions.ProxyErrorException;\r
19 import com.indexdata.pz2utils4jsf.config.Pz2Configurator;\r
20 import com.indexdata.pz2utils4jsf.controls.ResultsPager;\r
21 import com.indexdata.pz2utils4jsf.errors.ErrorInterface;\r
22 import com.indexdata.pz2utils4jsf.errors.ErrorHelper;\r
23 import com.indexdata.pz2utils4jsf.errors.ConfigurationError;\r
24 import com.indexdata.pz2utils4jsf.pazpar2.data.CommandError;\r
25 import com.indexdata.pz2utils4jsf.pazpar2.data.ByTarget;\r
26 import com.indexdata.pz2utils4jsf.pazpar2.data.Pazpar2ResponseData;\r
27 import com.indexdata.pz2utils4jsf.pazpar2.data.Pazpar2ResponseParser;\r
28 import com.indexdata.pz2utils4jsf.pazpar2.data.RecordResponse;\r
29 import com.indexdata.pz2utils4jsf.pazpar2.data.SearchResponse;\r
30 import com.indexdata.pz2utils4jsf.pazpar2.data.ShowResponse;\r
31 import com.indexdata.pz2utils4jsf.pazpar2.data.StatResponse;\r
32 import com.indexdata.pz2utils4jsf.pazpar2.data.TermListsResponse;\r
33 import com.indexdata.pz2utils4jsf.pazpar2.data.TermResponse;\r
34 import com.indexdata.pz2utils4jsf.pazpar2.state.QueryStates;\r
35 import com.indexdata.pz2utils4jsf.utils.Utils;\r
36 \r
37 @Named @SessionScoped  \r
38 public class Pz2Session implements Pz2Interface {\r
39   \r
40   private static Logger logger = Logger.getLogger(Pz2Session.class);\r
41   \r
42   private Map<String,Pazpar2ResponseData> dataObjects = new ConcurrentHashMap<String,Pazpar2ResponseData>();\r
43   private QueryStates queryStates = new QueryStates();\r
44   \r
45   private static final long serialVersionUID = 3947514708343320514L;  \r
46   private Pazpar2ClientConfiguration cfg = null;\r
47   private Pazpar2Client client = null;   \r
48   private TargetFilter targetFilter = null;  \r
49   private ResultsPager pager = null; \r
50   private ErrorHelper errorHelper = null;\r
51   private List<ErrorInterface> configurationErrors = null;\r
52   \r
53   public Pz2Session () {\r
54     logger.info("Instantiating pz2 session object [" + Utils.objectId(this) + "]");      \r
55   }\r
56     \r
57   public void init(Pz2Configurator pz2conf) {\r
58     if (client==null) {\r
59       configurationErrors = new ArrayList<ErrorInterface>();\r
60       errorHelper = new ErrorHelper(pz2conf);\r
61       logger.info(Utils.objectId(this) + " is configuring itself using the provided " + Utils.objectId(pz2conf));\r
62       try {\r
63         cfg = new Pazpar2ClientConfiguration(pz2conf.getConfig());\r
64       } catch (ProxyErrorException pe) {\r
65         logger.error("Could not configure Pazpar2 client: " + pe.getMessage());\r
66         configurationErrors.add(new ConfigurationError("Pz2Client Config","ProxyError","Could not configure Pazpar2 client: " + pe.getMessage(),errorHelper));\r
67       } catch (IOException io) {\r
68         logger.error("Could not configure Pazpar2 client: " + io.getMessage());\r
69         configurationErrors.add(new ConfigurationError("Pz2Client Config","ProxyError","Could not configure Pazpar2 client: " + io.getMessage(),errorHelper));\r
70       }\r
71       if (cfg != null) {\r
72         try {\r
73           client = new Pazpar2ClientGeneric(cfg);     \r
74         } catch (ProxyErrorException pe) {\r
75           logger.error("Could not instantiate Pazpar2 client: " + pe.getMessage());\r
76           configurationErrors.add(new ConfigurationError("Pz2Client error","ProxyError","Could not create Pazpar2 client: " +pe.getMessage(),errorHelper));                \r
77         } \r
78         logger.info("Found " + configurationErrors.size() + " configuration errors");        \r
79       }\r
80       resetDataObjects();\r
81     } else {\r
82       logger.warn("Attempt to configure session but it already has a configured client");\r
83     }\r
84   }\r
85     \r
86   public void doSearch(String query) {\r
87     setCommandParameter("search",new CommandParameter("query","=",query));     \r
88     doSearch();\r
89   }\r
90 \r
91   public void doSearch() { \r
92     queryStates.hasPendingStateChange("search",false);\r
93     resetDataObjects();\r
94     setCommandParameter("show",new CommandParameter("start","=",0));    \r
95     logger.debug(Utils.objectId(this) + " is searching using "+getCommand("search").getParameter("query").getEncodedQueryString());\r
96     doCommand("search");    \r
97   }\r
98       \r
99   /**\r
100    * Refreshes 'show', 'stat', 'termlist', and 'bytarget' data object from pazpar2\r
101    * \r
102    * @return Number of activeclients at the time of the 'show' command.\r
103    */\r
104   public String update () {\r
105     logger.debug("Updating show,stat,termlist,bytarget from pazpar2");\r
106     return update("show,stat,termlist,bytarget");\r
107   }\r
108    \r
109   /**\r
110    * Refreshes the data objects listed in 'commands' from pazpar2\r
111    * \r
112    * @param commands\r
113    * @return Number of activeclients at the time of the 'show' command\r
114    */\r
115   public String update (String commands) {\r
116     if (! hasConfigurationErrors()) {\r
117       if (hasQuery()) {\r
118         handleQueryStateChanges(commands);\r
119         logger.debug("Processing request for " + commands); \r
120         List<CommandThread> threadList = new ArrayList<CommandThread>();\r
121         StringTokenizer tokens = new StringTokenizer(commands,",");\r
122         while (tokens.hasMoreElements()) {\r
123           threadList.add(new CommandThread(getCommand(tokens.nextToken()),client));            \r
124         }\r
125         for (CommandThread thread : threadList) {\r
126           thread.start();\r
127         }\r
128         for (CommandThread thread : threadList) {\r
129           try {\r
130             thread.join();\r
131           } catch (InterruptedException e) {\r
132             e.printStackTrace();\r
133           }\r
134         }\r
135         for (CommandThread thread : threadList) {\r
136            String commandName = thread.getCommand().getName();\r
137            Pazpar2ResponseData responseObject = Pazpar2ResponseParser.getParser().getDataObject(thread.getResponse());\r
138            dataObjects.put(commandName, responseObject);        \r
139         }\r
140         return getActiveClients();\r
141       } else {\r
142         logger.debug("Skipped requests for " + commands + " as there's not yet a query."); \r
143         resetDataObjects();\r
144         return "0";\r
145       }\r
146     } else {\r
147       logger.error("Did not attempt to execute query since there are configuration errors.");\r
148       return "0";\r
149     }\r
150     \r
151   }\r
152         \r
153   public void setQuery (String query) {\r
154     logger.debug("Creating new command parameter for " + query);\r
155     setCommandParameter("search",new CommandParameter("query","=",query));\r
156   }\r
157   \r
158   public String getQuery () {\r
159     return getCommandParameterValueSimple("search","query",null);\r
160   }\r
161   \r
162   public void setFacet (String facetKey, String term) {           \r
163     if (term != null && term.length()>0) {\r
164       queryStates.getCurrentState().setCommandParameterExpression("search","query",new Expression(facetKey,"=",term),queryStates);\r
165       doSearch();\r
166     }            \r
167   }\r
168   \r
169   public void setFacetOnQuery (String facetKey, String term) {\r
170     String facetExpression = facetKey + "=" + term;    \r
171     if (term != null && term.length()>0) {\r
172       setCommandParameter("search",new CommandParameter("query","=", getQuery() + " and " + facetExpression));\r
173       doSearch();        \r
174     }            \r
175   }\r
176       \r
177   public void removeFacet(String facetKey, String term) {\r
178     queryStates.getCurrentState().removeCommandParameterExpression("search","query",new Expression(facetKey,"=",term),queryStates);\r
179     doSearch();\r
180   }\r
181   \r
182   public void setTargetFilter (String targetId, String targetName) {    \r
183     if (hasTargetFilter(new TargetFilter(targetId,targetName))) {\r
184       logger.debug("Already using target filter " + this.targetFilter.getFilterExpression());\r
185     } else {      \r
186       this.targetFilter = new TargetFilter(targetId,targetName);\r
187       setCommandParameter("search",new CommandParameter("filter","=",this.targetFilter.getFilterExpression()));      \r
188       doSearch();\r
189     }    \r
190   }\r
191 \r
192   public TargetFilter getTargetFilter () {\r
193     return targetFilter;\r
194   }\r
195     \r
196   public void removeTargetFilter () {\r
197     logger.debug("Removing target filter " + targetFilter.getFilterExpression());\r
198     this.targetFilter = null;\r
199     removeCommandParameter("search","filter");         \r
200     doSearch();\r
201   }\r
202   \r
203   public boolean hasTargetFilter() {\r
204     return targetFilter != null;    \r
205   }\r
206         \r
207   public void setSort (String sortOption) {\r
208     logger.debug("Setting sort option: " + sortOption);\r
209     setCommandParameter("show",new CommandParameter("sort","=",sortOption));\r
210     update("show");\r
211   }\r
212   \r
213   public String getSort () {\r
214     return getCommandParameterValue("show","sort","relevance");\r
215   }\r
216     \r
217   public void setPageSize (int perPageOption) {\r
218     if (getPageSize()!=perPageOption) {\r
219      logger.debug("Setting perpage option to " + perPageOption + " and resetting start page.");\r
220      setCommandParameter("show",new CommandParameter("num","=",perPageOption));\r
221      setCommandParameter("show",new CommandParameter("start","=",0));\r
222      update("show");\r
223     } else {\r
224       logger.debug("Not updating page size, already is " + perPageOption);\r
225     }\r
226   }\r
227   \r
228   public int getPageSize () {\r
229     return getCommandParameterValue("show","num",20);\r
230   }\r
231   \r
232   public void setStart (int start) {\r
233     logger.debug("Setting start num to " + start);\r
234     setCommandParameter("show", new CommandParameter("start","=",start));  \r
235     update("show");\r
236   }\r
237   \r
238   public int getStart() {\r
239     return getCommandParameterValue("show","start",0);\r
240   }\r
241         \r
242   public String toggleRecord (String recId) {\r
243     if (hasRecord(recId)) {\r
244       removeCommand("record");  \r
245       dataObjects.put("record", new RecordResponse());\r
246       return "";\r
247     } else {\r
248       return updateRecord(recId);\r
249     }\r
250   }\r
251   \r
252   private String updateRecord(String recId) {    \r
253     setCommandParameter("record",new CommandParameter("id","=",recId));    \r
254     return doCommand("record");    \r
255   }\r
256   \r
257   public boolean hasRecord (String recId) {\r
258     return getCommand("record").hasParameters() && getRecord().getRecId().equals(recId);\r
259   }\r
260       \r
261   public ShowResponse getShow () {\r
262     return ((ShowResponse) dataObjects.get("show"));\r
263   }\r
264   \r
265   public StatResponse getStat () {\r
266     return ((StatResponse) dataObjects.get("stat"));\r
267   }\r
268   \r
269   public RecordResponse getRecord() {\r
270     return ((RecordResponse) dataObjects.get("record"));\r
271   }\r
272   \r
273   public TermListsResponse getTermLists () {\r
274     return ((TermListsResponse) dataObjects.get("termlist"));\r
275   }\r
276   \r
277   public List<TermResponse> getFacetTerms (String facet, int count) {\r
278     return (getTermLists().getTermList(facet).getTerms(count));\r
279   }\r
280     \r
281   public List<TermResponse> getFacetTerms (String facet) {\r
282     return (getTermLists().getTermList(facet).getTerms());\r
283   }\r
284   \r
285   public ByTarget getByTarget() {\r
286     return ((ByTarget) dataObjects.get("bytarget"));\r
287   }\r
288   \r
289   \r
290   public String getCurrentStateKey () {    \r
291     return queryStates.getCurrentStateKey();\r
292   }\r
293       \r
294   public void setCurrentStateKey(String key) {       \r
295     queryStates.setCurrentStateKey(key);\r
296   }\r
297   \r
298   public boolean hasConfigurationErrors () {\r
299       return (configurationErrors.size()>0);      \r
300   }\r
301   \r
302   public boolean hasCommandErrors () {\r
303     if (dataObjects.get("search").hasApplicationError()) {\r
304       logger.info("Error detected in search");\r
305       return true;\r
306     }\r
307     for (String name : dataObjects.keySet()) {\r
308       if (dataObjects.get(name).hasApplicationError()) {\r
309         logger.info("Error detected in " + name);\r
310         return true;\r
311       }\r
312     }    \r
313     return false;    \r
314   }\r
315   \r
316   /**\r
317    * Returns true if application error found in any response data objects \r
318    */\r
319   public boolean hasErrors () {\r
320     return hasConfigurationErrors() || hasCommandErrors();\r
321   }\r
322 \r
323   public List<ErrorInterface> getConfigurationErrors() {    \r
324     return configurationErrors;\r
325   }\r
326   \r
327   /**\r
328    * Returns a search command error, if any, otherwise the first\r
329    * error found for an arbitrary command, if any, otherwise\r
330    * an empty dummy error. \r
331    */    \r
332   public ErrorInterface getCommandError() {\r
333     CommandError error = new CommandError();    \r
334     if (dataObjects.get("search").hasApplicationError()) {\r
335       error = dataObjects.get("search").getApplicationError();                        \r
336     } else {\r
337       for (String name : dataObjects.keySet()) {     \r
338         if (dataObjects.get(name).hasApplicationError()) {     \r
339           error = dataObjects.get(name).getApplicationError(); \r
340           break;\r
341         } \r
342       }\r
343     }\r
344     error.setErrorHelper(errorHelper);\r
345     return error;         \r
346   }\r
347 \r
348     \r
349   private boolean hasTargetFilter(TargetFilter targetFilter) {\r
350     return hasTargetFilter() && targetFilter.equals(this.targetFilter);\r
351   }\r
352   \r
353   private boolean hasQuery() {\r
354     return !(getCommand("search").getParameter("query") == null);\r
355   }\r
356     \r
357   public boolean hasRecords () {\r
358     return getStat().getRecords() > 0            \r
359            && getShow().getHits() != null \r
360            && getShow().getHits().size()>0;\r
361   }\r
362     \r
363   public ResultsPager getPager () {\r
364     if (pager == null) {\r
365       pager = new ResultsPager(this);      \r
366     } \r
367     return pager;      \r
368   }\r
369   \r
370   public ResultsPager setPager (int pageRange) {\r
371     pager =  new ResultsPager(this,pageRange);\r
372     return pager;\r
373   }\r
374   \r
375   protected ErrorHelper getTroubleshooter() {\r
376     return errorHelper;\r
377   }\r
378   \r
379   private void handleQueryStateChanges (String commands) {\r
380     if (queryStates.hasPendingStateChange("search")) { \r
381       logger.debug("Found pending search change. Doing search before updating " + commands);\r
382       doSearch();\r
383     } \r
384     if (queryStates.hasPendingStateChange("record") && ! commands.equals("record")) {        \r
385       logger.debug("Found pending record ID change. Doing record before updating " + commands);\r
386       queryStates.hasPendingStateChange("record",false);\r
387       if (getCommand("record").hasParameters()) {\r
388         updateRecord(getCommand("record").getParameter("id").getSimpleValue());\r
389       } else {\r
390         removeCommand("record");  \r
391         dataObjects.put("record", new RecordResponse());\r
392       }\r
393     }    \r
394   }\r
395 \r
396   private String getActiveClients() {    \r
397     if (getShow()!=null) {\r
398       logger.debug("Active clients: "+getShow().getActiveClients());\r
399       return getShow().getActiveClients();\r
400     } else {\r
401       return "";\r
402     }\r
403   }\r
404 \r
405   private Pazpar2Command getCommand(String name) {\r
406     return queryStates.getCurrentState().getCommand(name);\r
407   }\r
408   \r
409   private void setCommandParameter(String commandName, CommandParameter parameter) {\r
410     logger.debug("Setting parameter for " + commandName + ": " + parameter);\r
411     queryStates.getCurrentState().setCommandParameter(commandName, parameter, queryStates);    \r
412   }\r
413   \r
414   \r
415   private void removeCommandParameter(String commandName, String parameterName) {\r
416     queryStates.getCurrentState().removeCommandParameter(commandName,parameterName,queryStates);    \r
417   }\r
418   \r
419   private void removeCommand (String commandName) {\r
420     queryStates.getCurrentState().removeCommand(commandName, queryStates);\r
421   }\r
422     \r
423   private String getCommandParameterValue (String commandName, String parameterName, String defaultValue) {    \r
424     Pazpar2Command command = getCommand(commandName);\r
425     if (command != null) {\r
426       CommandParameter parameter = command.getParameter(parameterName);\r
427       if (parameter != null) {\r
428         return parameter.getValueWithExpressions();\r
429       }\r
430     }\r
431     return defaultValue;    \r
432   }\r
433   \r
434   private String getCommandParameterValueSimple (String commandName, String parameterName, String defaultValue) {    \r
435     Pazpar2Command command = getCommand(commandName);\r
436     if (command != null) {\r
437       CommandParameter parameter = command.getParameter(parameterName);\r
438       if (parameter != null) {\r
439         return parameter.getSimpleValue();\r
440       }\r
441     }\r
442     return defaultValue;    \r
443   }\r
444 \r
445   \r
446   private int getCommandParameterValue (String commandName, String parameterName, int defaultValue) {\r
447     Pazpar2Command command = getCommand(commandName);\r
448     if (command != null) {\r
449       CommandParameter parameter = command.getParameter(parameterName);\r
450       if (parameter != null) {\r
451         return Integer.parseInt(parameter.getSimpleValue());\r
452       }\r
453     }\r
454     return defaultValue;    \r
455   }\r
456 \r
457   private String doCommand(String commandName) {      \r
458     Pazpar2Command command = getCommand(commandName);    \r
459     logger.debug(command.getEncodedQueryString() + ": Results for "+ getCommand("search").getEncodedQueryString());\r
460     return update(commandName);      \r
461   }\r
462   \r
463   private void resetDataObjects() {\r
464     logger.debug("Resetting show,stat,termlist,bytarget,search response objects.");\r
465     dataObjects = new ConcurrentHashMap<String,Pazpar2ResponseData>();\r
466     dataObjects.put("show", new ShowResponse());\r
467     dataObjects.put("stat", new StatResponse());\r
468     dataObjects.put("termlist", new TermListsResponse());\r
469     dataObjects.put("bytarget", new ByTarget());\r
470     dataObjects.put("record", new RecordResponse());\r
471     dataObjects.put("search", new SearchResponse());\r
472   }\r
473   \r
474 }\r