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

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

Some fixes for LibraryServlet

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