source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/LibraryServlet.java@ 26507

Last change on this file since 26507 was 26507, checked in by davidb, 11 years ago

Support for o=json as output type in Greenstone 3

  • Property svn:keywords set to Author Date Id Revision
File size: 34.2 KB
Line 
1package org.greenstone.gsdl3;
2
3import java.io.IOException;
4import java.io.PrintWriter;
5import java.io.Serializable;
6import java.lang.reflect.Type;
7import java.util.ArrayList;
8import java.util.Enumeration;
9import java.util.HashMap;
10import java.util.Hashtable;
11import java.util.Iterator;
12import java.util.List;
13import java.util.Map;
14
15import javax.servlet.ServletConfig;
16import javax.servlet.ServletException;
17import javax.servlet.http.Cookie;
18import javax.servlet.http.HttpServletRequest;
19import javax.servlet.http.HttpServletResponse;
20import javax.servlet.http.HttpSession;
21import javax.servlet.http.HttpSessionBindingEvent;
22import javax.servlet.http.HttpSessionBindingListener;
23
24import org.apache.commons.lang3.StringUtils;
25import org.apache.log4j.Logger;
26import org.greenstone.gsdl3.action.PageAction;
27import org.greenstone.gsdl3.comms.Communicator;
28import org.greenstone.gsdl3.comms.SOAPCommunicator;
29import org.greenstone.gsdl3.core.DefaultReceptionist;
30import org.greenstone.gsdl3.core.MessageRouter;
31import org.greenstone.gsdl3.core.Receptionist;
32import org.greenstone.gsdl3.service.Authentication;
33import org.greenstone.gsdl3.util.GSConstants;
34import org.greenstone.gsdl3.util.GSParams;
35import org.greenstone.gsdl3.util.GSXML;
36import org.greenstone.gsdl3.util.UserContext;
37import org.greenstone.gsdl3.util.XMLConverter;
38import org.w3c.dom.Document;
39import org.w3c.dom.Element;
40import org.w3c.dom.Node;
41import org.w3c.dom.NodeList;
42
43import org.json.JSONObject;
44import org.json.XML;
45
46import com.google.gson.Gson;
47import com.google.gson.reflect.TypeToken;
48
49/**
50 * a servlet to serve the greenstone library - we are using servlets instead of
51 * cgi the init method is called only once - the first time the servlet classes
52 * are loaded. Each time a request comes in to the servlet, the session() method
53 * is called in a new thread (calls doGet/doPut etc) takes the a=p&p=home type
54 * args and builds a simple request to send to its receptionist, which returns a
55 * result in html, cos output=html is set in the request
56 *
57 * 18/Jul/07 xiao modify to make the cached parameters collection-specific. Most
58 * of the work is done in doGet(), except adding an inner class
59 * UserSessionCache.
60 *
61 * @see Receptionist
62 */
63public class LibraryServlet extends BaseGreenstoneServlet
64{
65 /** the receptionist to send messages to */
66 protected Receptionist recept = null;
67
68 /**
69 * the default language - is specified by setting a servlet param, otherwise
70 * DEFAULT_LANG is used
71 */
72 protected String default_lang = null;
73
74 /** Whether or not client-side XSLT support should be exposed */
75 protected boolean supports_client_xslt = false;
76
77 /**
78 * The default default - used if a default lang is not specified in the
79 * servlet params
80 */
81 protected final String DEFAULT_LANG = "en";
82
83 /** container Document to create XML Nodes */
84 protected Document doc = null;
85
86 /** a converter class to parse XML and create Docs */
87 protected XMLConverter converter = null;
88
89 /**
90 * the cgi stuff - the Receptionist can add new args to this
91 *
92 * its used by the servlet to determine what args to save
93 */
94 protected GSParams params = null;
95
96 /**
97 * user id - new one per session. This doesn't work if session state is
98 * saved between restarts - this requires this value to be saved too.
99 */
100 protected int next_user_id = 0;
101
102 /**
103 * a hash that contains all the active session IDs mapped to the cached
104 * items It is updated whenever the whole site or a particular collection is
105 * reconfigured using the command a=s&sa=c or a=s&sa=c&c=xxx It is in the
106 * form: sid -> (UserSessionCache object)
107 */
108 protected Hashtable<String, UserSessionCache> session_ids_table = new Hashtable<String, UserSessionCache>();
109
110 /**
111 * the maximum interval that the cached info remains in session_ids_table
112 * (in seconds) This is set in web.xml
113 */
114 protected int session_expiration = 1800;
115
116 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.LibraryServlet.class.getName());
117
118 /** initialise the servlet */
119 public void init(ServletConfig config) throws ServletException
120 {
121 // always call super.init;
122 super.init(config);
123 // disable preferences - does this work anyway??
124 //System.setProperty("java.util.prefs.PreferencesFactory", "org.greenstone.gsdl3.util.DisabledPreferencesFactory");
125
126 String library_name = config.getInitParameter(GSConstants.LIBRARY_NAME);
127 String interface_name = config.getInitParameter(GSConstants.INTERFACE_NAME);
128
129 String allowXslt = (String) config.getInitParameter(GSConstants.ALLOW_CLIENT_SIDE_XSLT);
130 supports_client_xslt = allowXslt != null && allowXslt.equals("true");
131
132 this.default_lang = config.getInitParameter(GSConstants.DEFAULT_LANG);
133 String sess_expire = config.getInitParameter(GSXML.SESSION_EXPIRATION);
134
135 if (sess_expire != null && !sess_expire.equals(""))
136 {
137 this.session_expiration = Integer.parseInt(sess_expire);
138 }
139
140 if (library_name == null || interface_name == null)
141 {
142 // must have this
143 System.err.println("initialisation parameters not all set!");
144 System.err.println(" you must have libraryname and interfacename");
145 System.exit(1);
146 }
147
148 String site_name = config.getInitParameter(GSConstants.SITE_NAME);
149 String remote_site_name = null;
150 String remote_site_type = null;
151 String remote_site_address = null;
152
153 if (site_name == null)
154 {
155 // no site, try for communicator
156 remote_site_name = config.getInitParameter("remote_site_name");
157 remote_site_type = config.getInitParameter("remote_site_type");
158 remote_site_address = config.getInitParameter("remote_site_address");
159 if (remote_site_name == null || remote_site_type == null || remote_site_address == null)
160 {
161 System.err.println("initialisation paramters not all set!");
162 System.err.println("if site_name is not set, then you must have remote_site_name, remote_site_type and remote_site_address set");
163 System.exit(1);
164 }
165 }
166
167 if (this.default_lang == null)
168 {
169 // choose english
170 this.default_lang = DEFAULT_LANG;
171 }
172
173 HashMap<String, Comparable> config_params = new HashMap<String, Comparable>();
174
175 config_params.put(GSConstants.LIBRARY_NAME, library_name);
176 config_params.put(GSConstants.INTERFACE_NAME, interface_name);
177 config_params.put(GSConstants.ALLOW_CLIENT_SIDE_XSLT, supports_client_xslt);
178
179 if (site_name != null)
180 {
181 config_params.put(GSConstants.SITE_NAME, site_name);
182 }
183 this.converter = new XMLConverter();
184 this.doc = this.converter.newDOM();
185
186 // the receptionist -the servlet will talk to this
187 String recept_name = (String) config.getInitParameter("receptionist_class");
188 if (recept_name == null)
189 {
190 this.recept = new DefaultReceptionist();
191 }
192 else
193 {
194 try
195 {
196 this.recept = (Receptionist) Class.forName("org.greenstone.gsdl3.core." + recept_name).newInstance();
197 }
198 catch (Exception e)
199 { // cant use this new one, so use normal one
200 System.err.println("LibraryServlet configure exception when trying to use a new Receptionist " + recept_name + ": " + e.getMessage());
201 e.printStackTrace();
202 this.recept = new DefaultReceptionist();
203 }
204 }
205 this.recept.setConfigParams(config_params);
206
207 // the receptionist uses a MessageRouter or Communicator to send its requests to. We either create a MessageRouter here for the designated site (if site_name set), or we create a Communicator for a remote site. The is given to teh Receptionist, and the servlet never talks to it again.directly.
208 if (site_name != null)
209 {
210 String mr_name = (String) config.getInitParameter("messagerouter_class");
211 MessageRouter message_router = null;
212 if (mr_name == null)
213 { // just use the normal MR
214 message_router = new MessageRouter();
215 }
216 else
217 { // try the specified one
218 try
219 {
220 message_router = (MessageRouter) Class.forName("org.greenstone.gsdl3.core." + mr_name).newInstance();
221 }
222 catch (Exception e)
223 { // cant use this new one, so use normal one
224 System.err.println("LibraryServlet configure exception when trying to use a new MessageRouter " + mr_name + ": " + e.getMessage());
225 e.printStackTrace();
226 message_router = new MessageRouter();
227 }
228 }
229
230 message_router.setSiteName(site_name);
231 message_router.setLibraryName(library_name);
232 message_router.configure();
233 this.recept.setMessageRouter(message_router);
234 }
235 else
236 {
237 // talking to a remote site, create a communicator
238 Communicator communicator = null;
239 // we need to create the XML to configure the communicator
240 Element site_elem = this.doc.createElement(GSXML.SITE_ELEM);
241 site_elem.setAttribute(GSXML.TYPE_ATT, remote_site_type);
242 site_elem.setAttribute(GSXML.NAME_ATT, remote_site_name);
243 site_elem.setAttribute(GSXML.ADDRESS_ATT, remote_site_address);
244
245 if (remote_site_type.equals(GSXML.COMM_TYPE_SOAP_JAVA))
246 {
247 communicator = new SOAPCommunicator();
248 }
249 else
250 {
251 System.err.println("LibraryServlet.init Error: invalid Communicator type: " + remote_site_type);
252 System.exit(1);
253 }
254
255 if (!communicator.configure(site_elem))
256 {
257 System.err.println("LibraryServlet.init Error: Couldn't configure communicator");
258 System.exit(1);
259 }
260 this.recept.setMessageRouter(communicator);
261 }
262
263 // the params arg thingy
264
265 String params_name = (String) config.getInitParameter("params_class");
266 if (params_name == null)
267 {
268 this.params = new GSParams();
269 }
270 else
271 {
272 try
273 {
274 this.params = (GSParams) Class.forName("org.greenstone.gsdl3.util." + params_name).newInstance();
275 }
276 catch (Exception e)
277 {
278 System.err.println("LibraryServlet configure exception when trying to use a new params thing " + params_name + ": " + e.getMessage());
279 e.printStackTrace();
280 this.params = new GSParams();
281 }
282 }
283 // pass it to the receptionist
284 this.recept.setParams(this.params);
285 this.recept.configure();
286
287 //Allow the message router and the document to be accessed from anywhere in this servlet context
288 this.getServletContext().setAttribute("GSRouter", this.recept.getMessageRouter());
289 this.getServletContext().setAttribute("GSDocument", this.doc);
290 }
291
292 private void logUsageInfo(HttpServletRequest request)
293 {
294 String usageInfo = "";
295
296 //session-info: get params stored in the session
297 HttpSession session = request.getSession(true);
298 Enumeration attributeNames = session.getAttributeNames();
299 while (attributeNames.hasMoreElements())
300 {
301 String name = (String) attributeNames.nextElement();
302 usageInfo += name + "=" + session.getAttribute(name) + " ";
303 }
304
305 //logged info = general-info + session-info
306 usageInfo = request.getServletPath() + " " + //serlvet
307 "[" + request.getQueryString() + "]" + " " + //the query string
308 "[" + usageInfo.trim() + "]" + " " + // params stored in a session
309 request.getRemoteAddr() + " " + //remote address
310 request.getRequestedSessionId() + " " + //session id
311 request.getHeader("user-agent") + " "; //the remote brower info
312
313 logger.info(usageInfo);
314
315 }
316
317 public class UserSessionCache implements HttpSessionBindingListener
318 {
319
320 String session_id = "";
321
322 /**
323 * a hash that maps the session ID to a hashtable that maps the
324 * coll_name to its parameters coll_name -> Hashtable (param_name ->
325 * param_value)
326 */
327 protected Hashtable<String, Hashtable<String, String>> coll_name_params_table = null;
328
329 public UserSessionCache(String id, Hashtable<String, Hashtable<String, String>> table)
330 {
331 session_id = id;
332 coll_name_params_table = (table == null) ? new Hashtable() : table;
333 }
334
335 protected void cleanupCache(String coll_name)
336 {
337 if (coll_name_params_table.containsKey(coll_name))
338 {
339 coll_name_params_table.remove(coll_name);
340 }
341 }
342
343 protected Hashtable<String, Hashtable<String, String>> getParamsTable()
344 {
345 return coll_name_params_table;
346 }
347
348 public void valueBound(HttpSessionBindingEvent event)
349 {
350 // Do nothing
351 }
352
353 public void valueUnbound(HttpSessionBindingEvent event)
354 {
355 if (session_ids_table.containsKey(session_id))
356 {
357 session_ids_table.remove(session_id);
358 }
359 }
360
361 public int tableSize()
362 {
363 return (coll_name_params_table == null) ? 0 : coll_name_params_table.size();
364 }
365 }
366
367 public void destroy()
368 {
369 recept.cleanUp();
370 }
371
372 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
373 {
374 logUsageInfo(request);
375
376 Map<String, String[]> queryMap = request.getParameterMap();
377 if (queryMap != null)
378 {
379 Iterator<String> queryIter = queryMap.keySet().iterator();
380 boolean redirect = false;
381 String href = null;
382 String rl = null;
383 String el = null;
384 while (queryIter.hasNext())
385 {
386 String q = queryIter.next();
387 if (q.equals(GSParams.EXTERNAL_LINK_TYPE))
388 {
389 el = queryMap.get(q)[0];
390 }
391 else if (q.equals(GSParams.HREF))
392 {
393 href = queryMap.get(q)[0];
394 href = StringUtils.replace(href, "%2f", "/");
395 href = StringUtils.replace(href, "%7e", "~");
396 href = StringUtils.replace(href, "%3f", "?");
397 href = StringUtils.replace(href, "%3A", "\\:");
398 }
399 else if (q.equals(GSParams.RELATIVE_LINK))
400 {
401 rl = queryMap.get(q)[0];
402 }
403 }
404
405 //if query_string contains "el=direct", an href is specified, and its not a relative link, then the web page will be redirected to the external URl, otherwise a greenstone page with an external URL will be displayed
406 //"rl=0" this is an external link
407 //"rl=1" this is an internal link
408 if ((href != null) && (rl.equals("0")))
409 {// This is an external link,
410
411 if (el.equals("framed"))
412 {
413 //TODO **** how best to change to a=p&sa=html&c=collection&url=href
414 // response.setContentType("text/xml");
415 //response.sendRedirect("http://localhost:8383/greenstone3/gs3library?a=p&sa=html&c=external&url="+href);
416 }
417 else
418 {
419 // el = '' or direct
420 //the web page is re-directed to the external URL (&el=&rl=0&href="http://...")
421 response.setContentType("text/xml");
422 response.sendRedirect(href);
423 }
424 }
425 }
426
427 // Nested Diagnostic Configurator to identify the client for
428 HttpSession session = request.getSession(true);
429 session.setMaxInactiveInterval(session_expiration);
430 String uid = (String) session.getAttribute(GSXML.USER_ID_ATT);
431 if (uid == null)
432 {
433 uid = "" + getNextUserId();
434 session.setAttribute(GSXML.USER_ID_ATT, uid);
435 }
436
437 request.setCharacterEncoding("UTF-8");
438 response.setContentType("text/html;charset=UTF-8");
439 PrintWriter out = response.getWriter();
440
441 String lang = request.getParameter(GSParams.LANGUAGE);
442 if (lang == null || lang.equals(""))
443 {
444 // try the session cached lang
445 lang = (String) session.getAttribute(GSParams.LANGUAGE);
446 if (lang == null || lang.equals(""))
447 {
448 // still not set, use the default
449 lang = this.default_lang;
450 }
451 }
452 UserContext userContext = new UserContext();
453 userContext.setLanguage(lang);
454 userContext.setUserID(uid);
455
456 // set the lang in the session
457 session.setAttribute(GSParams.LANGUAGE, lang);
458
459 String output = request.getParameter(GSParams.OUTPUT);
460 if (output == null || output.equals(""))
461 {
462 output = "html"; // uses html by default
463 }
464
465 // If server output, force a switch to traditional interface
466 //output = (output.equals("server")) ? "html" : output;
467
468 // Force change the output mode if client-side XSLT is supported - server vs. client
469 // BUT only if the library allows client-side transforms
470 if (supports_client_xslt)
471 {
472 // MUST be done before the xml_message is built
473 Cookie[] cookies = request.getCookies();
474 Cookie xsltCookie = null;
475
476 // The client has cookies enabled and a value set - use it!
477 if (cookies != null)
478 {
479 for (Cookie c : cookies)
480 {
481 if (c.getName().equals("supportsXSLT"))
482 {
483 xsltCookie = c;
484 break;
485 }
486 }
487 output = (xsltCookie != null && xsltCookie.getValue().equals("true") && output.equals("html")) ? "xsltclient" : output;
488 }
489 }
490
491 // the request to the receptionist
492 Element xml_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
493 Element xml_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
494 xml_request.setAttribute(GSXML.OUTPUT_ATT, output);
495
496 xml_message.appendChild(xml_request);
497
498 String action = request.getParameter(GSParams.ACTION);
499 String subaction = request.getParameter(GSParams.SUBACTION);
500 String collection = request.getParameter(GSParams.COLLECTION);
501 String document = request.getParameter(GSParams.DOCUMENT);
502 String service = request.getParameter(GSParams.SERVICE);
503
504 // We clean up the cache session_ids_table if system
505 // commands are issued (and also don't need to do caching for this request)
506 boolean should_cache = true;
507 if (action != null && action.equals(GSParams.SYSTEM_ACTION))
508 {
509 should_cache = false;
510
511 // we may want to remove all collection cache info, or just a specific collection
512 boolean clean_all = true;
513 String clean_collection = null;
514 // system commands are to activate/deactivate stuff
515 // collection param is in the sc parameter.
516 // don't like the fact that it is hard coded here
517 String coll = request.getParameter(GSParams.SYSTEM_CLUSTER);
518 if (coll != null && !coll.equals(""))
519 {
520 clean_all = false;
521 clean_collection = coll;
522 }
523 else
524 {
525 // check other system types
526 if (subaction.equals("a") || subaction.equals("d"))
527 {
528 String module_name = request.getParameter("sn");
529 if (module_name != null && !module_name.equals(""))
530 {
531 clean_all = false;
532 clean_collection = module_name;
533 }
534 }
535 }
536 if (clean_all)
537 {
538 session_ids_table = new Hashtable<String, UserSessionCache>();
539 session.removeAttribute(GSXML.USER_SESSION_CACHE_ATT);
540 }
541 else
542 {
543 // just clean up info for clean_collection
544 ArrayList<UserSessionCache> cache_list = new ArrayList<UserSessionCache>(session_ids_table.values());
545 for (int i = 0; i < cache_list.size(); i++)
546 {
547 UserSessionCache cache = cache_list.get(i);
548 cache.cleanupCache(clean_collection);
549 }
550
551 }
552 }
553
554 // cache_key is the collection name, or service name
555 String cache_key = collection;
556 if (cache_key == null || cache_key.equals(""))
557 {
558 cache_key = service;
559 }
560
561 // logger.info("should_cache= " + should_cache);
562
563 //clear the collection-specific cache in the session, since we have no way to know whether this session is
564 //about the same collection as the last session or not.
565 Enumeration attributeNames = session.getAttributeNames();
566 while (attributeNames.hasMoreElements())
567 {
568 String name = (String) attributeNames.nextElement();
569 if (!name.equals(GSXML.USER_SESSION_CACHE_ATT) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT))
570 {
571 session.removeAttribute(name);
572 }
573 }
574
575 UserSessionCache session_cache = null;
576 Hashtable<String, Hashtable<String, String>> param_table = null;
577 Hashtable<String, String> table = null;
578 String sid = session.getId();
579 if (should_cache == true && cache_key != null && !cache_key.equals(""))
580 {
581 if (session_ids_table.containsKey(sid))
582 {
583 session_cache = session_ids_table.get(sid);
584 param_table = session_cache.getParamsTable();
585 logger.info("collections in table: " + tableToString(param_table));
586 if (param_table.containsKey(cache_key))
587 {
588 //logger.info("existing table: " + collection);
589 table = param_table.get(cache_key);
590 }
591 else
592 {
593 table = new Hashtable<String, String>();
594 param_table.put(cache_key, table);
595 //logger.info("new table: " + collection);
596 }
597 }
598 else
599 {
600 param_table = new Hashtable<String, Hashtable<String, String>>();
601 table = new Hashtable<String, String>();
602 param_table.put(cache_key, table);
603 session_cache = new UserSessionCache(sid, param_table);
604 session_ids_table.put(sid, session_cache);
605 session.setAttribute(GSXML.USER_SESSION_CACHE_ATT, session_cache);
606 //logger.info("new session id");
607 }
608 }
609
610 if (action == null || action.equals(""))
611 {
612 // should we do all the following stuff if using default page?
613 // display the home page - the default page
614 xml_request.setAttribute(GSXML.ACTION_ATT, "p");
615 xml_request.setAttribute(GSXML.SUBACTION_ATT, PageAction.HOME_PAGE);
616 }
617 else
618 {
619 xml_request.setAttribute(GSXML.ACTION_ATT, action);
620 if (subaction != null)
621 {
622 xml_request.setAttribute(GSXML.SUBACTION_ATT, subaction);
623 }
624
625 // create the param list for the greenstone request - includes
626 // the params from the current request and any others from the saved session
627 Element xml_param_list = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
628 xml_request.appendChild(xml_param_list);
629
630 for (String name : queryMap.keySet())
631 {
632 if (!name.equals(GSParams.ACTION) && !name.equals(GSParams.SUBACTION) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSParams.OUTPUT))
633 {// we have already dealt with these
634
635 String value = "";
636 String[] values = request.getParameterValues(name);
637 value = values[0];
638 if (values.length > 1)
639 {
640 for (int i = 1; i < values.length; i++)
641 {
642 value += "," + values[i];
643 }
644 }
645 // either add it to the param list straight away, or save it to the session and add it later
646 if (this.params.shouldSave(name) && table != null)
647 {
648 table.put(name, value);
649 }
650 else
651 {
652 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
653 param.setAttribute(GSXML.NAME_ATT, name);
654 param.setAttribute(GSXML.VALUE_ATT, GSXML.xmlSafe(value));
655 xml_param_list.appendChild(param);
656 }
657 }
658 }
659 //put everything in the table into the session
660 // do we need to do this? why not just put from table into param list
661 if (table != null)
662 {
663 Enumeration<String> keys = table.keys();
664 while (keys.hasMoreElements())
665 {
666 String name = keys.nextElement();
667 session.setAttribute(name, table.get(name));
668 }
669 }
670
671 // put in all the params from the session cache
672 Enumeration params = session.getAttributeNames();
673 while (params.hasMoreElements())
674 {
675 String name = (String) params.nextElement();
676
677 if (!name.equals(GSXML.USER_SESSION_CACHE_ATT) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT))
678 {
679
680 // lang and uid are stored but we dont want it in the param list cos its already in the request
681 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
682 param.setAttribute(GSXML.NAME_ATT, name);
683 String value = GSXML.xmlSafe((String) session.getAttribute(name));
684
685 // ugly hack to undo : escaping
686 value = StringUtils.replace(value, "%3A", "\\:");
687 param.setAttribute(GSXML.VALUE_ATT, value);
688 xml_param_list.appendChild(param);
689 }
690 }
691 }
692
693 if (output.equals("json")) {
694 response.setContentType("application/json");
695 }
696 else if (!output.equals("html") && !output.equals("server") && !output.equals("xsltclient"))
697 {
698 response.setContentType("text/xml"); // for now use text
699 }
700
701 //Add custom HTTP headers if requested
702 String httpHeadersParam = request.getParameter(GSParams.HTTP_HEADER_FIELDS);
703 if (httpHeadersParam != null && httpHeadersParam.length() > 0)
704 {
705 Gson gson = new Gson();
706 Type type = new TypeToken<List<Map<String, String>>>()
707 {
708 }.getType();
709 List<Map<String, String>> httpHeaders = gson.fromJson(httpHeadersParam, type);
710 if (httpHeaders != null && httpHeaders.size() > 0)
711 {
712
713 for (int j = 0; j < httpHeaders.size(); j++)
714 {
715 Map nameValueMap = httpHeaders.get(j);
716 String name = (String) nameValueMap.get("name");
717 String value = (String) nameValueMap.get("value");
718
719 if (name != null && value != null)
720 {
721 response.setHeader(name, value);
722 }
723 }
724 }
725 }
726
727 String requestedURL = request.getRequestURL().toString();
728 String baseURL = "";
729 if (requestedURL.indexOf(this.getServletName()) != -1)
730 {
731 baseURL = requestedURL.substring(0, requestedURL.indexOf(this.getServletName()));
732 xml_request.setAttribute("baseURL", baseURL);
733 }
734
735 String fullURL;
736 if (request.getQueryString() != null)
737 {
738 fullURL = requestedURL + "?" + request.getQueryString();
739 }
740 else
741 {
742 fullURL = requestedURL;
743 }
744
745 xml_request.setAttribute("remoteAddress", request.getRemoteAddr());
746 xml_request.setAttribute("fullURL", fullURL.replace("&", "&amp;"));
747
748 if (!runSecurityChecks(request, xml_request, userContext, out, baseURL, collection, document))
749 {
750 return;
751 }
752
753 Node xml_result = this.recept.process(xml_message);
754 encodeURLs(xml_result, response);
755
756 String xml_string = this.converter.getPrettyString(xml_result);
757
758 if (output.equals("json")) {
759 try {
760 JSONObject json_obj = org.json.XML.toJSONObject(xml_string);
761
762 out.println(json_obj.toString());
763 }
764 catch (Exception e) {
765 e.printStackTrace();
766 out.println("Error: failed to convert output XML to JSON format");
767 }
768 }
769 else {
770 out.println(xml_string);
771 }
772
773 displaySize(session_ids_table);
774
775 } //end of doGet(HttpServletRequest, HttpServletResponse)
776
777 private boolean runSecurityChecks(HttpServletRequest request, Element xml_request, UserContext userContext, PrintWriter out, String baseURL, String collection, String document) throws ServletException
778 {
779 //Check if we need to login or logout
780 Map<String, String[]> params = request.getParameterMap();
781 String[] username = params.get("username");
782 String[] password = params.get("password");
783 String[] logout = params.get("logout");
784
785 if (logout != null)
786 {
787 request.logout();
788 }
789
790 if (username != null && password != null)
791 {
792 //We are changing to another user, so log out first
793 if (request.getAuthType() != null)
794 {
795 request.logout();
796 }
797
798 try
799 {
800 password[0] = Authentication.hashPassword(password[0]);
801 request.login(username[0], password[0]);
802 }
803 catch (Exception ex)
804 {
805 //The user entered in either the wrong username or the wrong password
806 Element loginPageMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
807 Element loginPageRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
808 loginPageRequest.setAttribute(GSXML.ACTION_ATT, "p");
809 loginPageRequest.setAttribute(GSXML.SUBACTION_ATT, "login");
810 loginPageRequest.setAttribute(GSXML.OUTPUT_ATT, "html");
811 loginPageRequest.setAttribute(GSXML.BASE_URL, baseURL);
812 loginPageMessage.appendChild(loginPageRequest);
813
814 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
815 loginPageRequest.appendChild(paramList);
816
817 Element messageParam = this.doc.createElement(GSXML.PARAM_ELEM);
818 messageParam.setAttribute(GSXML.NAME_ATT, "loginMessage");
819 messageParam.setAttribute(GSXML.VALUE_ATT, "Either your username or password was incorrect, please try again.");
820 paramList.appendChild(messageParam);
821
822 Element urlParam = this.doc.createElement(GSXML.PARAM_ELEM);
823 urlParam.setAttribute(GSXML.NAME_ATT, "redirectURL");
824 String queryString = "";
825 if (request.getQueryString() != null)
826 {
827 queryString = "?" + request.getQueryString().replace("&", "&amp;");
828 }
829 urlParam.setAttribute(GSXML.VALUE_ATT, this.getServletName() + queryString);
830 paramList.appendChild(urlParam);
831
832 Node loginPageResponse = this.recept.process(loginPageMessage);
833 out.println(this.converter.getPrettyString(loginPageResponse));
834
835 return false;
836 }
837 }
838
839 //If a user is logged in
840 if (request.getAuthType() != null)
841 {
842 Element userInformation = this.doc.createElement(GSXML.USER_INFORMATION_ELEM);
843 userInformation.setAttribute("username", request.getUserPrincipal().getName());
844
845 Element userInfoMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
846 Element userInfoRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_SECURITY, "GetUserInformation", userContext);
847 userInfoMessage.appendChild(userInfoRequest);
848
849 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
850 userInfoRequest.appendChild(paramList);
851
852 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
853 param.setAttribute(GSXML.NAME_ATT, GSXML.USERNAME_ATT);
854 param.setAttribute(GSXML.VALUE_ATT, request.getUserPrincipal().getName());
855 paramList.appendChild(param);
856
857 Element userInformationResponse = (Element) GSXML.getChildByTagName(this.recept.process(userInfoMessage), GSXML.RESPONSE_ELEM);
858 Element responseParamList = (Element) GSXML.getChildByTagName(userInformationResponse, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
859 if (responseParamList == null)
860 {
861 logger.error("Can't get the groups for user " + request.getUserPrincipal().getName());
862 }
863 else
864 {
865 HashMap<String, Serializable> responseParams = GSXML.extractParams(responseParamList, true);
866 String groups = (String) responseParams.get(GSXML.GROUPS_ATT);
867
868 userInformation.setAttribute(GSXML.GROUPS_ATT, groups);
869 xml_request.appendChild(userInformation);
870 }
871 }
872
873 //If we are in a collection-related page then make sure this user is allowed to access it
874 if (collection != null && !collection.equals(""))
875 {
876 //Get the security info for this collection
877 Element securityMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
878 Element securityRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_SECURITY, collection, userContext);
879 securityMessage.appendChild(securityRequest);
880 if (document != null && !document.equals(""))
881 {
882 securityRequest.setAttribute(GSXML.NODE_OID, document);
883 }
884
885 Element securityResponse = (Element) GSXML.getChildByTagName(this.recept.process(securityMessage), GSXML.RESPONSE_ELEM);
886 if (securityResponse == null)
887 {
888 return false;
889 }
890
891 ArrayList<String> groups = GSXML.getGroupsFromSecurityResponse(securityResponse);
892
893 //If guests are not allowed to access this page then check to see if the user is in a group that is allowed to access the page
894 if (!groups.contains(""))
895 {
896 boolean found = false;
897 for (String group : groups)
898 {
899 if (request.isUserInRole(group))
900 {
901 found = true;
902 break;
903 }
904 }
905
906 //The current user is not allowed to access the page so produce a login page
907 if (!found)
908 {
909 Element loginPageMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
910 Element loginPageRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
911 loginPageRequest.setAttribute(GSXML.ACTION_ATT, "p");
912 loginPageRequest.setAttribute(GSXML.SUBACTION_ATT, "login");
913 loginPageRequest.setAttribute(GSXML.OUTPUT_ATT, "html");
914 loginPageRequest.setAttribute(GSXML.BASE_URL, baseURL);
915 loginPageMessage.appendChild(loginPageRequest);
916
917 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
918 loginPageRequest.appendChild(paramList);
919
920 Element messageParam = this.doc.createElement(GSXML.PARAM_ELEM);
921 messageParam.setAttribute(GSXML.NAME_ATT, "loginMessage");
922 if (request.getAuthType() == null)
923 {
924 messageParam.setAttribute(GSXML.VALUE_ATT, "Please log in to view this page");
925 }
926 else
927 {
928 messageParam.setAttribute(GSXML.VALUE_ATT, "You are not in the correct group to view this page, would you like to log in as a different user?");
929 }
930 paramList.appendChild(messageParam);
931
932 Element urlParam = this.doc.createElement(GSXML.PARAM_ELEM);
933 urlParam.setAttribute(GSXML.NAME_ATT, "redirectURL");
934 if (request.getQueryString() != null && request.getQueryString().length() > 0)
935 {
936 urlParam.setAttribute(GSXML.VALUE_ATT, request.getRequestURL() + "?" + request.getQueryString().replace("&", "&amp;"));
937 }
938 else
939 {
940 urlParam.setAttribute(GSXML.VALUE_ATT, request.getRequestURL().toString());
941 }
942 paramList.appendChild(urlParam);
943
944 Node loginPageResponse = this.recept.process(loginPageMessage);
945 out.println(this.converter.getPrettyString(loginPageResponse));
946
947 return false;
948 }
949 }
950 }
951 return true;
952 }
953
954 //a debugging method
955 private void displaySize(Hashtable<String, UserSessionCache> table)
956 {
957 if (table == null)
958 {
959 logger.info("cached table is null");
960 return;
961 }
962 if (table.size() == 0)
963 {
964 logger.info("cached table size is zero");
965 return;
966 }
967 int num_cached_coll = 0;
968 ArrayList<UserSessionCache> cache_list = new ArrayList<UserSessionCache>(table.values());
969 for (int i = 0; i < cache_list.size(); i++)
970 {
971 num_cached_coll += cache_list.get(i).tableSize();
972 }
973 logger.info("Number of sessions : total number of cached collection info = " + table.size() + " : " + num_cached_coll);
974 }
975
976 /** merely a debugging method! */
977 private String tableToString(Hashtable<String, Hashtable<String, String>> table)
978 {
979 String str = "";
980 Enumeration<String> keys = table.keys();
981 while (keys.hasMoreElements())
982 {
983 String name = keys.nextElement();
984 str += name + ", ";
985 }
986 return str;
987 }
988
989 /**
990 * this goes through each URL and adds in a session id if needed-- its
991 * needed if the browser doesn't accept cookies also escapes things if
992 * needed
993 */
994 protected void encodeURLs(Node dataNode, HttpServletResponse response)
995 {
996
997 if (dataNode == null)
998 {
999 return;
1000 }
1001
1002 Element data = null;
1003
1004 short nodeType = dataNode.getNodeType();
1005 if (nodeType == Node.DOCUMENT_NODE)
1006 {
1007 Document docNode = (Document) dataNode;
1008 data = docNode.getDocumentElement();
1009 }
1010 else
1011 {
1012 data = (Element) dataNode;
1013 }
1014
1015 if (data != null)
1016 {
1017
1018 // get all the <a> elements
1019 NodeList hrefs = data.getElementsByTagName("a");
1020 // Instead of calculating each iteration...
1021 int hrefscount = hrefs.getLength();
1022
1023 for (int i = 0; hrefs != null && i < hrefscount; i++)
1024 {
1025 Element a = (Element) hrefs.item(i);
1026 // ugly hack to get rid of : in the args - interferes with session handling
1027 String href = a.getAttribute("href");
1028 if (!href.equals(""))
1029 {
1030 if (href.indexOf("?") != -1)
1031 {
1032 String[] parts = StringUtils.split(href, "\\?", -1);
1033 if (parts.length == 1)
1034 {
1035 parts[0] = StringUtils.replace(parts[0], ":", "%3A");
1036 href = "?" + parts[0];
1037 }
1038 else
1039 {
1040 parts[1] = StringUtils.replace(parts[1], ":", "%3A");
1041 href = parts[0] + "?" + parts[1];
1042 }
1043
1044 }
1045 a.setAttribute("href", response.encodeURL(href));
1046 }
1047 }
1048
1049 // now find any submit bits - get all the <form> elements
1050 NodeList forms = data.getElementsByTagName("form");
1051 int formscount = forms.getLength();
1052 for (int i = 0; forms != null && i < formscount; i++)
1053 {
1054 Element form = (Element) forms.item(i);
1055 form.setAttribute("action", response.encodeURL(form.getAttribute("action")));
1056 }
1057 // are these the only cases where URLs occur??
1058 // we should only do this for greenstone urls?
1059 }
1060
1061 }
1062
1063 synchronized protected int getNextUserId()
1064 {
1065 next_user_id++;
1066 return next_user_id;
1067 }
1068
1069 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
1070 {
1071 doGet(request, response);
1072 }
1073}
Note: See TracBrowser for help on using the repository browser.