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

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

Fixing Greenstone 3's use (or lack thereof) of generics, this was done automatically so we may want to change it over time. This change will also auto-format any files that have not already been formatted.

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