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

Last change on this file since 25717 was 25717, checked in by sjm84, 12 years ago

Added a BaseGreenstoneServlet servlet that the other servlets now inherit from so that we can be sure that GlobalProperties is properly initialised. There is also some reformatting and import cleaning

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