Documents configuration schemes in more detail
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / mkjsf / pazpar2 / Pz2Service.java
1 package com.indexdata.mkjsf.pazpar2;\r
2 \r
3 import java.io.Serializable;\r
4 import java.lang.annotation.Retention;\r
5 import java.lang.annotation.Target;\r
6 import java.util.ArrayList;\r
7 import java.util.Arrays;\r
8 import java.util.HashMap;\r
9 import java.util.List;\r
10 import java.util.Map;\r
11 import java.util.StringTokenizer;\r
12 \r
13 import javax.annotation.PostConstruct;\r
14 import javax.enterprise.context.SessionScoped;\r
15 import javax.enterprise.inject.Produces;\r
16 import javax.faces.context.FacesContext;\r
17 import javax.inject.Inject;\r
18 import javax.inject.Named;\r
19 import javax.inject.Qualifier;\r
20 \r
21 import org.apache.log4j.Logger;\r
22 \r
23 import com.indexdata.mkjsf.config.Configurable;\r
24 import com.indexdata.mkjsf.config.Configuration;\r
25 import com.indexdata.mkjsf.config.ConfigurationReader;\r
26 import com.indexdata.mkjsf.controls.ResultsPager;\r
27 import com.indexdata.mkjsf.errors.ConfigurationError;\r
28 import com.indexdata.mkjsf.errors.ConfigurationException;\r
29 import com.indexdata.mkjsf.errors.ErrorCentral;\r
30 import com.indexdata.mkjsf.errors.ErrorHelper;\r
31 import com.indexdata.mkjsf.errors.MissingConfigurationContextException;\r
32 import com.indexdata.mkjsf.pazpar2.commands.Pazpar2Commands;\r
33 import com.indexdata.mkjsf.pazpar2.data.RecordResponse;\r
34 import com.indexdata.mkjsf.pazpar2.data.Responses;\r
35 import com.indexdata.mkjsf.pazpar2.state.StateListener;\r
36 import com.indexdata.mkjsf.pazpar2.state.StateManager;\r
37 import com.indexdata.mkjsf.utils.Utils;\r
38 \r
39 /**  \r
40  * Pz2Service is the main controller of the search logic, used for selecting the service \r
41  * type (which can be done by configuration and/or run-time), selecting which search client \r
42  * to use, and performing high-level control of request cycles and state management. \r
43  * <p>\r
44  * Command and response beans are also obtained through Pz2Service - although it is \r
45  * transparent to the UI that they are retrieved through this object.\r
46  * </p>\r
47  * <p>\r
48  * Pz2Service is exposed to the UI as <code>pz2</code>. However, if the service is pre-configured, \r
49  * the Faces pages might never need to reference <code>pz2</code> explicitly. Indirectly they will, \r
50  * though, if the polling mechanism in the tag <code>&lt;pz2utils:pz2watch&gt;</code> is used.\r
51  * \r
52  * \r
53  * <h3>Configuration</h3>\r
54  *\r
55  * Configuration name: service\r
56  *  \r
57  * <p>When configuring the client using the Mk2Config scheme, this is the prefix to\r
58  * use in the .properties file. When using web.xml context parameters for configuration\r
59  * the configuration name has no effect.</p> \r
60  * \r
61  * <p>Pz2Service will acknowledge following configuration parameters:\r
62  * \r
63  * <ul>\r
64  *  <li>(service.)TYPE</li>  \r
65  * </ul> \r
66  * \r
67  * Possible values for service TYPE are: PZ2, SP, TBD. "TBD", meaning "to-be-decided runtime", is the default.\r
68  * \r
69  **/ \r
70 @Named("pz2") @SessionScoped\r
71 public class Pz2Service implements StateListener, Configurable, Serializable {\r
72 \r
73   private static final String MODULE_NAME = "service";\r
74   private static String SERVICE_TYPE_TBD = "TBD", SERVICE_TYPE_PZ2 = "PZ2", SERVICE_TYPE_SP = "SP";\r
75   private static final List<String> serviceTypes = \r
76                 Arrays.asList(SERVICE_TYPE_PZ2,SERVICE_TYPE_SP,SERVICE_TYPE_TBD);\r
77   private String serviceType = SERVICE_TYPE_TBD;\r
78   private List<String> serviceProxyUrls = new ArrayList<String>();\r
79   public static final String SERVICE_PROXY_URL_LIST = "SERVICE_PROXY_URL_LIST";\r
80   private List<String> pazpar2Urls = new ArrayList<String>();\r
81   public static final String PAZPAR2_URL_LIST = "PAZPAR2_URL_LIST";\r
82 \r
83   private static final long serialVersionUID = 3440277287081557861L;\r
84   private static Logger logger = Logger.getLogger(Pz2Service.class);  \r
85   protected Pz2Client pz2Client = null;\r
86   protected ServiceProxyClient spClient = null;\r
87   protected SearchClient searchClient = null;  \r
88     \r
89   @Inject ConfigurationReader configurator;\r
90   \r
91   private StateManager stateMgr = null;\r
92   private Pazpar2Commands pzreq = null;\r
93   private Responses pzresp = null;\r
94   private ErrorCentral errors = null;  \r
95   \r
96   protected ResultsPager pager = null; \r
97   \r
98   protected ErrorHelper errorHelper = null;\r
99               \r
100   public Pz2Service () {\r
101     logger.info("Instantiating pz2 bean [" + Utils.objectId(this) + "]");    \r
102   }\r
103   \r
104   public static Pz2Service get() {\r
105     FacesContext context = FacesContext.getCurrentInstance();\r
106     return (Pz2Service) context.getApplication().evaluateExpressionGet(context, "#{pz2}", Object.class); \r
107   }\r
108     \r
109   @PostConstruct\r
110   public void postConstruct() throws MissingConfigurationContextException {    \r
111     logger.info("Pz2Service PostConstruct of " + this);\r
112     stateMgr = new StateManager();\r
113     pzreq = new Pazpar2Commands();\r
114     pzresp = new Responses();    \r
115     errors = new ErrorCentral(); \r
116     pzresp.setErrorHelper(errors.getHelper());\r
117     \r
118     logger.debug("Pz2Service PostConstruct: Configurator is " + configurator);\r
119     logger.debug(Utils.objectId(this) + " will instantiate a Pz2Client next.");    \r
120     pz2Client = new Pz2Client();\r
121     spClient = new ServiceProxyClient();\r
122     stateMgr.addStateListener(this);\r
123     try {\r
124       configureClient(pz2Client,configurator);      \r
125       configureClient(spClient,configurator);\r
126       this.configure(configurator);\r
127     } catch (MissingConfigurationContextException mcc) {\r
128       logger.info("No configuration context available at this point");\r
129       logger.debug("Configuration invoked from a Servlet filter before application start?");\r
130       throw mcc;\r
131     } catch (ConfigurationException e) {\r
132       logger.warn("There was a problem configuring the Pz2Service and/or clients (\"pz2\")");\r
133       e.printStackTrace();\r
134     }     \r
135   }\r
136   \r
137   @Qualifier\r
138   @Target({java.lang.annotation.ElementType.TYPE,\r
139            java.lang.annotation.ElementType.METHOD,\r
140            java.lang.annotation.ElementType.PARAMETER,\r
141            java.lang.annotation.ElementType.FIELD})\r
142   @Retention(java.lang.annotation.RetentionPolicy.RUNTIME)\r
143   public  @interface Preferred{}\r
144   \r
145   @Produces @Preferred @SessionScoped @Named("pzresp") public Responses getPzresp () {\r
146     logger.trace("Producing pzresp");\r
147     return pzresp;\r
148   }\r
149   \r
150   @Produces @Preferred @SessionScoped @Named("pzreq") public Pazpar2Commands getPzreq () {\r
151     logger.trace("Producing pzreq");\r
152     return pzreq;\r
153   }\r
154   \r
155   @Produces @Preferred @SessionScoped @Named("errors") public ErrorCentral getErrors() {\r
156     logger.trace("Producing errors");\r
157     return errors;\r
158   }\r
159   \r
160   @Produces @Preferred @SessionScoped @Named("stateMgr") public StateManager getStateMgr() {\r
161     logger.trace("Producing stateMgr");\r
162     return stateMgr;\r
163   }\r
164   \r
165   /**\r
166    * Configures the selected search client using the selected configuration reader.\r
167    * \r
168    * The configuration reader is select deploy-time - by configuration in the application's beans.xml.\r
169    * \r
170    * @param client search client to use\r
171    * @param configReader the selected configuration mechanism\r
172    * @throws MissingConfigurationContextException if this object is injected before there is a Faces context\r
173    * for example in a Servlet filter.\r
174    */\r
175   public void configureClient(SearchClient client, ConfigurationReader configReader)  throws MissingConfigurationContextException {\r
176     logger.debug(Utils.objectId(this) + " will configure search client for the session");\r
177     try {\r
178       client.configure(configReader);\r
179     } catch (MissingConfigurationContextException mcce) {\r
180       logger.info("No Faces context is available to the configurator at this time of invocation");\r
181       throw mcce;\r
182     } catch (ConfigurationException e) {\r
183       logger.debug("Pz2Service adding configuration error");\r
184       errors.addConfigurationError(new ConfigurationError("Search Client","Configuration",e.getMessage()));                \r
185     }\r
186     logger.info(configReader.document());\r
187     pzresp.getSp().resetAuthAndBeyond(true);    \r
188   }\r
189   \r
190   public void resetSearchAndRecordCommands () {\r
191     pzreq.getRecord().removeParametersInState();\r
192     pzreq.getSearch().removeParametersInState();   \r
193   }\r
194      \r
195   \r
196   /**\r
197    * Updates display data objects by simultaneously issuing the following Pazpar2 commands: \r
198    * 'show', 'stat', 'termlist' and 'bytarget'. \r
199    * <p>\r
200    * If there are outstanding changes to the search command, a search\r
201    * will be issued before the updates are performed. Outstanding changes could come \r
202    * from the UI changing a search parameter and not executing search before starting \r
203    * the update cycle - OR - it could come from the user clicking the browsers back/forward\r
204    * buttons. \r
205    * </p>\r
206    * <p>\r
207    * This method is invoked from the composite 'pz2watch', which uses Ajax\r
208    * to keep invoking this method until it returns '0' (for zero active clients).\r
209    * </p>\r
210    * <p>\r
211    * UI components that display data from show, stat, termlist or bytarget, \r
212    * should be re-rendered after each update. \r
213    * </p>\r
214    * Example of invocation in UI:\r
215    * <pre>\r
216    *    &lt;pz2utils:pz2watch id="pz2watch"\r
217    *       renderWhileActiveclients="myshowui mystatui mytermsui" /&lt; \r
218    *       \r
219    *    &lt;h:form&gt;\r
220    *     &lt;h:inputText id="query" value="#{pzreq.search.query}" size="50"/&gt;                            \r
221    *      &lt;h:commandButton id="button" value="Search"&gt;              \r
222    *       &lt;f:ajax execute="query" render="${pz2.watchActiveclients}"/&gt;\r
223    *      &lt;/h:commandButton&gt;\r
224    *     &lt;/h:form&gt;\r
225    * </pre>\r
226    * The expression pz2.watchActiveClients will invoke the method repeatedly, and the\r
227    * UI sections myshowui, mystatui, and mytermsui will be rendered on each poll. \r
228    * \r
229    * @return a count of the remaining active clients from the most recent search. \r
230    */  \r
231   public String update () {\r
232     logger.debug("Updating show,stat,termlist,bytarget from pazpar2");\r
233     if (errors.hasConfigurationErrors()) {\r
234       logger.error("Ignoring show,stat,termlist,bytarget commands due to configuration errors.");\r
235       return "";\r
236     } else if (pzresp.getSearch().hasApplicationError()) {\r
237       logger.error("Ignoring show,stat,termlist,bytarget commands due to problem with most recent search.");\r
238       return "";\r
239     } else if (!hasQuery()) {\r
240       logger.debug("Ignoring show,stat,termlist,bytarget commands because there is not yet a query.");\r
241       return "";\r
242     } else {\r
243       return update("show,stat,termlist,bytarget");\r
244     }\r
245   }\r
246      \r
247   /**\r
248    * Simultaneously refreshes the data objects listed in 'commands' from pazpar2, potentially running a\r
249    * search or a record command first if any of these two commands have outstanding parameter changes.\r
250    * \r
251    * @param commands, a comma-separated list of Pazpar2 commands to execute\r
252    * \r
253    * @return Number of activeclients at the time of the 'show' command,\r
254    *         or 'new' if search was just initiated.\r
255    */\r
256   public String update (String commands) {\r
257     logger.debug("Request to update: " + commands);\r
258     try {\r
259       if (commands.equals("search")) {\r
260         pzreq.getSearch().run();\r
261         pzresp.getSearch().setIsNew(false);\r
262         return "new";\r
263       } else if (commands.equals("record")) {\r
264         pzreq.getRecord().run();\r
265         return pzresp.getRecord().getActiveClients();\r
266       } else if (pzresp.getSearch().isNew()) {\r
267         // For returning notification of 'search started' quickly to UI\r
268         logger.info("New search. Marking it old, then returning 'new' to trigger another round-trip.");\r
269         pzresp.getSearch().setIsNew(false);\r
270         return "new";\r
271       } else {\r
272         handleQueryStateChanges(commands);\r
273         if (pzresp.getSearch().hasApplicationError()) {\r
274           logger.error("The command(s) " + commands + " cancelled because the latest search command had an error.");\r
275           return "0";\r
276         } else if (errors.hasConfigurationErrors()) {\r
277           logger.error("The command(s) " + commands + " cancelled due to configuration errors.");\r
278           return "0";\r
279         } else {\r
280           logger.debug("Processing request for " + commands); \r
281           List<CommandThread> threadList = new ArrayList<CommandThread>();\r
282           StringTokenizer tokens = new StringTokenizer(commands,",");\r
283           while (tokens.hasMoreElements()) {          \r
284             threadList.add(new CommandThread(pzreq.getCommand(tokens.nextToken()),searchClient,Pz2Service.get().getPzresp()));            \r
285           }\r
286           for (CommandThread thread : threadList) {\r
287             thread.start();\r
288           }\r
289           for (CommandThread thread : threadList) {\r
290             try {\r
291               thread.join();\r
292             } catch (InterruptedException e) {\r
293               e.printStackTrace();\r
294             }\r
295           }\r
296           return pzresp.getActiveClients();\r
297         }\r
298       }  \r
299     } catch (ClassCastException cce) {\r
300       cce.printStackTrace();    \r
301       return "";\r
302     } catch (NullPointerException npe) {\r
303       npe.printStackTrace();\r
304       return "";\r
305     } catch (Exception e) {\r
306       e.printStackTrace();\r
307       return "";\r
308     }\r
309     \r
310   }\r
311   \r
312   /**\r
313    * This methods main purpose is to support browser history.\r
314    *  \r
315    * When the browsers back or forward buttons are pressed, a  \r
316    * re-search /might/ be required - namely if the query changes.\r
317    * So, as the UI requests updates of the page (show,facets,\r
318    * etc) this method checks if a search must be executed\r
319    * before those updates are performed.\r
320    *  \r
321    * It will consequently also run a search if the UI updates a\r
322    * search parameter without actually explicitly executing the search \r
323    * before setting of the polling.\r
324    *  \r
325    * @see {@link com.indexdata.mkjsf.pazpar2.state.StateManager#setCurrentStateKey} \r
326    * @param commands\r
327    */\r
328   protected void handleQueryStateChanges (String commands) {\r
329     if (stateMgr.hasPendingStateChange("search") && hasQuery()) { \r
330       logger.info("Triggered search: Found pending search change [" + pzreq.getCommand("search").toString() + "], doing search before updating " + commands);      \r
331       pzreq.getSearch().run();\r
332       pzresp.getSearch().setIsNew(false);\r
333     } \r
334     if (stateMgr.hasPendingStateChange("record") && ! commands.equals("record")) {        \r
335       logger.debug("Found pending record ID change. Doing record before updating " + commands);\r
336       stateMgr.hasPendingStateChange("record",false);\r
337       pzreq.getRecord().run();\r
338     }\r
339   }\r
340       \r
341   /**\r
342    * Used by the state manager to notify Pz2Service about state changes\r
343    */\r
344   @Override\r
345   public void stateUpdated(String commandName) {\r
346     logger.debug("State change reported for [" + commandName + "]");\r
347     if (commandName.equals("show")) {\r
348       logger.debug("Updating show");\r
349       update(commandName);\r
350     } \r
351   }\r
352 \r
353       \r
354   /**\r
355    * Will retrieve -- or alternatively remove -- the record with the given \r
356    * recid from memory.\r
357    * \r
358    * A pazpar2 'record' command will then be issued. The part of the UI \r
359    * showing record data should thus be re-rendered.\r
360    *  \r
361    * @param recid\r
362    * @return\r
363    */\r
364   public String toggleRecord (String recId) {\r
365     if (hasRecord(recId)) {\r
366       pzreq.getRecord().removeParameters();  \r
367       pzresp.put("record", new RecordResponse());\r
368       return "";\r
369     } else {\r
370       pzreq.getRecord().setId(recId);\r
371       pzreq.getRecord().run();\r
372       return pzresp.getRecord().getActiveClients();\r
373     }\r
374   }\r
375   \r
376   /**\r
377    * Resolves whether the back-end has a record with the given recid in memory \r
378    * \r
379    * @return true if the bean currently holds the record with recid\r
380    */  \r
381   public boolean hasRecord (String recId) {\r
382     return pzreq.getCommand("record").hasParameters() && pzresp.getRecord().getRecId().equals(recId);\r
383   }\r
384         \r
385   /**\r
386    * Returns the current hash key, used for internal session state tracking\r
387    * and potentially for browser history entries\r
388    * \r
389    * A UI author would not normally be concerned with retrieving this. It's used by the\r
390    * framework internally\r
391    *  \r
392    * @return string that can be used for browsers window.location.hash\r
393    */\r
394   public String getCurrentStateKey () {    \r
395     return stateMgr.getCurrentState().getKey();\r
396   }\r
397       \r
398   /**\r
399    * Sets the current state key, i.e. when user clicks back or forward in browser history.\r
400    * Would normally be automatically handled by the frameworks components.\r
401    *  \r
402    * @param key corresponding to browsers hash string\r
403    */\r
404   public void setCurrentStateKey(String key) {       \r
405     stateMgr.setCurrentStateKey(key);\r
406   }\r
407       \r
408   protected boolean hasQuery() {        \r
409     return pzreq.getCommand("search").hasParameterValue("query"); \r
410   }\r
411     \r
412   /**\r
413    * Returns a component for drawing a pager to navigate by.\r
414    * @return ResultsPager pager component\r
415    */\r
416   public ResultsPager getPager () {\r
417     if (pager == null) {\r
418       pager = new ResultsPager(pzresp);      \r
419     } \r
420     return pager;      \r
421   }\r
422   \r
423  /**\r
424   * Initiates a pager object, a component holding the data to draw a sequence\r
425   * of page numbers to navigate by and mechanisms to navigate with\r
426   * \r
427   * @param pageRange number of pages to display in the pager\r
428   * @return ResultsPager the initiated pager component\r
429   */\r
430   public ResultsPager setPager (int pageRange) {\r
431     pager =  new ResultsPager(pzresp,pageRange,pzreq);\r
432     return pager;\r
433   }\r
434      \r
435   /**\r
436    * Sets the URL of the Service Proxy to use for requests\r
437    * \r
438    * @param url\r
439    */\r
440   public void setServiceProxyUrl(String url) {\r
441     searchClient = spClient;\r
442     setServiceType(SERVICE_TYPE_SP);\r
443     setServiceUrl(url);\r
444   }\r
445   \r
446   /**\r
447    * Returns the Service Proxy URL currently defined for servicing requests\r
448    * \r
449    */\r
450   public String getServiceProxyUrl () {\r
451     if (isServiceProxyService()) {\r
452       return spClient.getServiceUrl();\r
453     } else {\r
454       return "";\r
455     }\r
456   }\r
457 \r
458   /**\r
459    * Sets the URL of the Pazpar2 to use for requests\r
460    * \r
461    * @param url\r
462    */\r
463   public void setPazpar2Url(String url) {\r
464     searchClient = pz2Client;\r
465     setServiceType(SERVICE_TYPE_PZ2);\r
466     setServiceUrl(url);\r
467   }\r
468   \r
469   /**\r
470    * Returns the Pazpar2 URL currently defined for servicing requests\r
471    * \r
472    */  \r
473   public String getPazpar2Url() {\r
474     if (isPazpar2Service()) {\r
475       return pz2Client.getServiceUrl();\r
476     } else {\r
477       return "";\r
478     }\r
479   }\r
480 \r
481   /**\r
482    * Sets the URL to be used by the currently selected search client \r
483    * when running requests. \r
484    * \r
485    * @param url\r
486    */\r
487   public void setServiceUrl(String url) {\r
488     if (url!=null && searchClient != null && !url.equals(searchClient.getServiceUrl())) {\r
489       pzreq.getRecord().removeParametersInState();\r
490       pzreq.getSearch().removeParametersInState();\r
491       pzresp.getSp().resetAuthAndBeyond(true);      \r
492       searchClient.setServiceUrl(url);\r
493     }    \r
494   }\r
495   \r
496   /**\r
497    * Gets the currently selected URL used for executing requests. \r
498    * @return\r
499    */\r
500   public String getServiceUrl() {\r
501     return (searchClient!=null ? searchClient.getServiceUrl() : "");\r
502   }\r
503   \r
504   public void setServiceId () {\r
505     pzreq.getRecord().removeParametersInState();\r
506     pzreq.getSearch().removeParametersInState();\r
507     pzresp.resetSearchAndBeyond();\r
508     pz2Client.setServiceId(pzreq.getInit().getService());\r
509   }\r
510   \r
511   public String getServiceId () {\r
512     return pzreq.getInit().getService();\r
513   }\r
514   \r
515   public boolean getServiceUrlIsDefined() {\r
516     return (searchClient != null && searchClient.hasServiceUrl());\r
517   }\r
518   \r
519   public List<String> getServiceProxyUrls() {\r
520     List<String> urls = new ArrayList<String>();\r
521     urls.add("");\r
522     urls.addAll(serviceProxyUrls);\r
523     return urls;\r
524   }\r
525   \r
526   public List<String> getPazpar2Urls () {\r
527     List<String> urls = new ArrayList<String>();\r
528     urls.add("");\r
529     urls.addAll(pazpar2Urls);\r
530     return urls;\r
531   }\r
532   \r
533   public String getServiceType () {\r
534     return serviceType;\r
535   }\r
536   \r
537   public boolean isPazpar2Service () {\r
538     return serviceType.equals(SERVICE_TYPE_PZ2);\r
539   }\r
540   \r
541   public boolean isServiceProxyService() {\r
542     return serviceType.equals(SERVICE_TYPE_SP);\r
543   }\r
544   \r
545   public boolean serviceIsToBeDecided () {\r
546     return serviceType.equals(SERVICE_TYPE_TBD);\r
547   }\r
548   \r
549   public ServiceProxyClient getSpClient () {\r
550     return spClient;\r
551   }  \r
552   \r
553   public boolean getAuthenticationRequired () {\r
554     return spClient.isAuthenticatingClient();\r
555   }\r
556 \r
557   public String getCheckHistory () {\r
558     return ":pz2watch:stateForm:windowlocationhash";\r
559   }\r
560     \r
561   public String getWatchActiveclients () {\r
562     return ":pz2watch:activeclientsForm:activeclientsField";\r
563   }\r
564   \r
565   public String getWatchActiveclientsRecord () {\r
566     return ":pz2watch:activeclientsForm:activeclientsFieldRecord";\r
567   }\r
568 \r
569   @Override\r
570   public void configure(ConfigurationReader reader)\r
571       throws ConfigurationException {\r
572     Configuration config = reader.getConfiguration(this);\r
573     if (config == null) {\r
574       serviceType = SERVICE_TYPE_TBD;\r
575     } else {\r
576       String service = config.get("TYPE");\r
577       if (service == null || service.length()==0) {\r
578         serviceType = SERVICE_TYPE_TBD;\r
579       } else if (serviceTypes.contains(service.toUpperCase())) {        \r
580         setServiceType(service.toUpperCase());\r
581       } else {\r
582         logger.error("Unknown serviceType type in configuration [" + service + "], can be one of " + serviceTypes);\r
583         serviceType = SERVICE_TYPE_TBD;\r
584       }\r
585       serviceProxyUrls = config.getMultiProperty(SERVICE_PROXY_URL_LIST,",");\r
586       pazpar2Urls = config.getMultiProperty(PAZPAR2_URL_LIST, ",");\r
587     }\r
588     logger.info(reader.document());\r
589     logger.info("Service Type is configured to " + serviceType);\r
590     \r
591   }\r
592 \r
593   @Override\r
594   public Map<String, String> getDefaults() {\r
595     return new HashMap<String,String>();\r
596   }\r
597 \r
598   @Override\r
599   public String getModuleName() {\r
600     return MODULE_NAME;\r
601   }\r
602 \r
603   @Override\r
604   public List<String> documentConfiguration() {\r
605     return new ArrayList<String>();\r
606   }\r
607 \r
608   public void setServiceTypePZ2() {\r
609     setServiceType(SERVICE_TYPE_PZ2);    \r
610   }\r
611 \r
612   public void setServiceTypeSP() {\r
613     setServiceType(SERVICE_TYPE_SP);        \r
614   }\r
615 \r
616   public void setServiceTypeTBD() {\r
617     setServiceType(SERVICE_TYPE_TBD);    \r
618   }\r
619   \r
620   private void setServiceType(String type) {\r
621     if (!serviceType.equals(type)  &&\r
622         !serviceType.equals(SERVICE_TYPE_TBD)) {\r
623       resetSearchAndRecordCommands();\r
624       pzresp.getSp().resetAuthAndBeyond(true);\r
625     }\r
626     serviceType = type;\r
627     if (serviceType.equals(SERVICE_TYPE_PZ2)) {\r
628       searchClient = pz2Client;\r
629       logger.info("Setting a Pazpar2 client to serve requests.");\r
630     } else if (serviceType.equals(SERVICE_TYPE_SP)) {\r
631       searchClient = spClient;\r
632       logger.info("Setting a Service Proxy client to serve requests.");\r
633     } else {\r
634       logger.info("Clearing search client. No client defined to serve requests at this point.");\r
635       searchClient = null;\r
636     }\r
637   }\r
638   \r
639   public SearchClient getSearchClient() {\r
640     return searchClient;\r
641   }\r
642   \r
643 }\r