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

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

Having an error in the collectionConfig.xml file of a collection was causing a login screen to be displayed which was confusing. It will now produce a blank screen instead. It is not the ideal solution but it is much better than a confusing login screen

  • Property svn:keywords set to Author Date Id Revision
File size: 33.7 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 public void destroy()
365 {
366 recept.cleanUp();
367 }
368
369 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
370 {
371 logUsageInfo(request);
372
373 Map<String, String[]> queryMap = request.getParameterMap();
374 if (queryMap != null)
375 {
376 Iterator<String> queryIter = queryMap.keySet().iterator();
377 boolean redirect = false;
378 String href = null;
379 String rl = null;
380 String el = null;
381 while (queryIter.hasNext())
382 {
383 String q = queryIter.next();
384 if (q.equals(GSParams.EXTERNAL_LINK_TYPE))
385 {
386 el = queryMap.get(q)[0];
387 }
388 else if (q.equals(GSParams.HREF))
389 {
390 href = queryMap.get(q)[0];
391 href = StringUtils.replace(href, "%2f", "/");
392 href = StringUtils.replace(href, "%7e", "~");
393 href = StringUtils.replace(href, "%3f", "?");
394 href = StringUtils.replace(href, "%3A", "\\:");
395 }
396 else if (q.equals(GSParams.RELATIVE_LINK))
397 {
398 rl = queryMap.get(q)[0];
399 }
400 }
401
402 //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
403 //"rl=0" this is an external link
404 //"rl=1" this is an internal link
405 if ((href != null) && (rl.equals("0")))
406 {// This is an external link,
407
408 if (el.equals("framed"))
409 {
410 //TODO **** how best to change to a=p&sa=html&c=collection&url=href
411 // response.setContentType("text/xml");
412 //response.sendRedirect("http://localhost:8383/greenstone3/gs3library?a=p&sa=html&c=external&url="+href);
413 }
414 else
415 {
416 // el = '' or direct
417 //the web page is re-directed to the external URL (&el=&rl=0&href="http://...")
418 response.setContentType("text/xml");
419 response.sendRedirect(href);
420 }
421 }
422 }
423
424 // Nested Diagnostic Configurator to identify the client for
425 HttpSession session = request.getSession(true);
426 session.setMaxInactiveInterval(session_expiration);
427 String uid = (String) session.getAttribute(GSXML.USER_ID_ATT);
428 if (uid == null)
429 {
430 uid = "" + getNextUserId();
431 session.setAttribute(GSXML.USER_ID_ATT, uid);
432 }
433
434 request.setCharacterEncoding("UTF-8");
435 response.setContentType("text/html;charset=UTF-8");
436 PrintWriter out = response.getWriter();
437
438 String lang = request.getParameter(GSParams.LANGUAGE);
439 if (lang == null || lang.equals(""))
440 {
441 // try the session cached lang
442 lang = (String) session.getAttribute(GSParams.LANGUAGE);
443 if (lang == null || lang.equals(""))
444 {
445 // still not set, use the default
446 lang = this.default_lang;
447 }
448 }
449 UserContext userContext = new UserContext();
450 userContext.setLanguage(lang);
451 userContext.setUserID(uid);
452
453 // set the lang in the session
454 session.setAttribute(GSParams.LANGUAGE, lang);
455
456 String output = request.getParameter(GSParams.OUTPUT);
457 if (output == null || output.equals(""))
458 {
459 output = "html"; // uses html by default
460 }
461
462 // If server output, force a switch to traditional interface
463 //output = (output.equals("server")) ? "html" : output;
464
465 // Force change the output mode if client-side XSLT is supported - server vs. client
466 // BUT only if the library allows client-side transforms
467 if (supports_client_xslt)
468 {
469 // MUST be done before the xml_message is built
470 Cookie[] cookies = request.getCookies();
471 Cookie xsltCookie = null;
472
473 // The client has cookies enabled and a value set - use it!
474 if (cookies != null)
475 {
476 for (Cookie c : cookies)
477 {
478 if (c.getName().equals("supportsXSLT"))
479 {
480 xsltCookie = c;
481 break;
482 }
483 }
484 output = (xsltCookie != null && xsltCookie.getValue().equals("true") && output.equals("html")) ? "xsltclient" : output;
485 }
486 }
487
488 // the request to the receptionist
489 Element xml_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
490 Element xml_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
491 xml_request.setAttribute(GSXML.OUTPUT_ATT, output);
492
493 xml_message.appendChild(xml_request);
494
495 String action = request.getParameter(GSParams.ACTION);
496 String subaction = request.getParameter(GSParams.SUBACTION);
497 String collection = request.getParameter(GSParams.COLLECTION);
498 String document = request.getParameter(GSParams.DOCUMENT);
499 String service = request.getParameter(GSParams.SERVICE);
500
501 // We clean up the cache session_ids_table if system
502 // commands are issued (and also don't need to do caching for this request)
503 boolean should_cache = true;
504 if (action != null && action.equals(GSParams.SYSTEM_ACTION))
505 {
506 should_cache = false;
507
508 // we may want to remove all collection cache info, or just a specific collection
509 boolean clean_all = true;
510 String clean_collection = null;
511 // system commands are to activate/deactivate stuff
512 // collection param is in the sc parameter.
513 // don't like the fact that it is hard coded here
514 String coll = request.getParameter(GSParams.SYSTEM_CLUSTER);
515 if (coll != null && !coll.equals(""))
516 {
517 clean_all = false;
518 clean_collection = coll;
519 }
520 else
521 {
522 // check other system types
523 if (subaction.equals("a") || subaction.equals("d"))
524 {
525 String module_name = request.getParameter("sn");
526 if (module_name != null && !module_name.equals(""))
527 {
528 clean_all = false;
529 clean_collection = module_name;
530 }
531 }
532 }
533 if (clean_all)
534 {
535 session_ids_table = new Hashtable<String, UserSessionCache>();
536 session.removeAttribute(GSXML.USER_SESSION_CACHE_ATT);
537 }
538 else
539 {
540 // just clean up info for clean_collection
541 ArrayList<UserSessionCache> cache_list = new ArrayList<UserSessionCache>(session_ids_table.values());
542 for (int i = 0; i < cache_list.size(); i++)
543 {
544 UserSessionCache cache = cache_list.get(i);
545 cache.cleanupCache(clean_collection);
546 }
547
548 }
549 }
550
551 // cache_key is the collection name, or service name
552 String cache_key = collection;
553 if (cache_key == null || cache_key.equals(""))
554 {
555 cache_key = service;
556 }
557
558 // logger.info("should_cache= " + should_cache);
559
560 //clear the collection-specific cache in the session, since we have no way to know whether this session is
561 //about the same collection as the last session or not.
562 Enumeration attributeNames = session.getAttributeNames();
563 while (attributeNames.hasMoreElements())
564 {
565 String name = (String) attributeNames.nextElement();
566 if (!name.equals(GSXML.USER_SESSION_CACHE_ATT) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT))
567 {
568 session.removeAttribute(name);
569 }
570 }
571
572 UserSessionCache session_cache = null;
573 Hashtable<String, Hashtable<String, String>> param_table = null;
574 Hashtable<String, String> table = null;
575 String sid = session.getId();
576 if (should_cache == true && cache_key != null && !cache_key.equals(""))
577 {
578 if (session_ids_table.containsKey(sid))
579 {
580 session_cache = session_ids_table.get(sid);
581 param_table = session_cache.getParamsTable();
582 logger.info("collections in table: " + tableToString(param_table));
583 if (param_table.containsKey(cache_key))
584 {
585 //logger.info("existing table: " + collection);
586 table = param_table.get(cache_key);
587 }
588 else
589 {
590 table = new Hashtable<String, String>();
591 param_table.put(cache_key, table);
592 //logger.info("new table: " + collection);
593 }
594 }
595 else
596 {
597 param_table = new Hashtable<String, Hashtable<String, String>>();
598 table = new Hashtable<String, String>();
599 param_table.put(cache_key, table);
600 session_cache = new UserSessionCache(sid, param_table);
601 session_ids_table.put(sid, session_cache);
602 session.setAttribute(GSXML.USER_SESSION_CACHE_ATT, session_cache);
603 //logger.info("new session id");
604 }
605 }
606
607 if (action == null || action.equals(""))
608 {
609 // should we do all the following stuff if using default page?
610 // display the home page - the default page
611 xml_request.setAttribute(GSXML.ACTION_ATT, "p");
612 xml_request.setAttribute(GSXML.SUBACTION_ATT, PageAction.HOME_PAGE);
613 }
614 else
615 {
616 xml_request.setAttribute(GSXML.ACTION_ATT, action);
617 if (subaction != null)
618 {
619 xml_request.setAttribute(GSXML.SUBACTION_ATT, subaction);
620 }
621
622 // create the param list for the greenstone request - includes
623 // the params from the current request and any others from the saved session
624 Element xml_param_list = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
625 xml_request.appendChild(xml_param_list);
626
627 for (String name : queryMap.keySet())
628 {
629 if (!name.equals(GSParams.ACTION) && !name.equals(GSParams.SUBACTION) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSParams.OUTPUT))
630 {// we have already dealt with these
631
632 String value = "";
633 String[] values = request.getParameterValues(name);
634 value = values[0];
635 if (values.length > 1)
636 {
637 for (int i = 1; i < values.length; i++)
638 {
639 value += "," + values[i];
640 }
641 }
642 // either add it to the param list straight away, or save it to the session and add it later
643 if (this.params.shouldSave(name) && table != null)
644 {
645 table.put(name, value);
646 }
647 else
648 {
649 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
650 param.setAttribute(GSXML.NAME_ATT, name);
651 param.setAttribute(GSXML.VALUE_ATT, GSXML.xmlSafe(value));
652 xml_param_list.appendChild(param);
653 }
654 }
655 }
656 //put everything in the table into the session
657 // do we need to do this? why not just put from table into param list
658 if (table != null)
659 {
660 Enumeration<String> keys = table.keys();
661 while (keys.hasMoreElements())
662 {
663 String name = keys.nextElement();
664 session.setAttribute(name, table.get(name));
665 }
666 }
667
668 // put in all the params from the session cache
669 Enumeration params = session.getAttributeNames();
670 while (params.hasMoreElements())
671 {
672 String name = (String) params.nextElement();
673
674 if (!name.equals(GSXML.USER_SESSION_CACHE_ATT) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT))
675 {
676
677 // lang and uid are stored but we dont want it in the param list cos its already in the request
678 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
679 param.setAttribute(GSXML.NAME_ATT, name);
680 String value = GSXML.xmlSafe((String) session.getAttribute(name));
681
682 // ugly hack to undo : escaping
683 value = StringUtils.replace(value, "%3A", "\\:");
684 param.setAttribute(GSXML.VALUE_ATT, value);
685 xml_param_list.appendChild(param);
686 }
687 }
688 }
689
690 if (!output.equals("html") && !output.equals("server") && !output.equals("xsltclient"))
691 {
692 response.setContentType("text/xml"); // for now use text
693 }
694
695 //Add custom HTTP headers if requested
696 String httpHeadersParam = request.getParameter(GSParams.HTTP_HEADER_FIELDS);
697 if (httpHeadersParam != null && httpHeadersParam.length() > 0)
698 {
699 Gson gson = new Gson();
700 Type type = new TypeToken<List<Map<String, String>>>()
701 {
702 }.getType();
703 List<Map<String, String>> httpHeaders = gson.fromJson(httpHeadersParam, type);
704 if (httpHeaders != null && httpHeaders.size() > 0)
705 {
706
707 for (int j = 0; j < httpHeaders.size(); j++)
708 {
709 Map nameValueMap = httpHeaders.get(j);
710 String name = (String) nameValueMap.get("name");
711 String value = (String) nameValueMap.get("value");
712
713 if (name != null && value != null)
714 {
715 response.setHeader(name, value);
716 }
717 }
718 }
719 }
720
721 String requestedURL = request.getRequestURL().toString();
722 String baseURL = "";
723 if (requestedURL.indexOf(this.getServletName()) != -1)
724 {
725 baseURL = requestedURL.substring(0, requestedURL.indexOf(this.getServletName()));
726 xml_request.setAttribute("baseURL", baseURL);
727 }
728
729 String fullURL;
730 if (request.getQueryString() != null)
731 {
732 fullURL = requestedURL + "?" + request.getQueryString();
733 }
734 else
735 {
736 fullURL = requestedURL;
737 }
738
739 xml_request.setAttribute("remoteAddress", request.getRemoteAddr());
740 xml_request.setAttribute("fullURL", fullURL.replace("&", "&amp;"));
741
742 if (!runSecurityChecks(request, xml_request, userContext, out, baseURL, collection, document))
743 {
744 return;
745 }
746
747 Node xml_result = this.recept.process(xml_message);
748 encodeURLs(xml_result, response);
749 out.println(this.converter.getPrettyString(xml_result));
750
751 displaySize(session_ids_table);
752
753 } //end of doGet(HttpServletRequest, HttpServletResponse)
754
755 private boolean runSecurityChecks(HttpServletRequest request, Element xml_request, UserContext userContext, PrintWriter out, String baseURL, String collection, String document) throws ServletException
756 {
757 //Check if we need to login or logout
758 Map<String, String[]> params = request.getParameterMap();
759 String[] username = params.get("username");
760 String[] password = params.get("password");
761 String[] logout = params.get("logout");
762
763 if (logout != null)
764 {
765 request.logout();
766 }
767
768 if (username != null && password != null)
769 {
770 //We are changing to another user, so log out first
771 if (request.getAuthType() != null)
772 {
773 request.logout();
774 }
775
776 try
777 {
778 password[0] = Authentication.hashPassword(password[0]);
779 request.login(username[0], password[0]);
780 }
781 catch (Exception ex)
782 {
783 //The user entered in either the wrong username or the wrong password
784 Element loginPageMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
785 Element loginPageRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
786 loginPageRequest.setAttribute(GSXML.ACTION_ATT, "p");
787 loginPageRequest.setAttribute(GSXML.SUBACTION_ATT, "login");
788 loginPageRequest.setAttribute(GSXML.OUTPUT_ATT, "html");
789 loginPageRequest.setAttribute(GSXML.BASE_URL, baseURL);
790 loginPageMessage.appendChild(loginPageRequest);
791
792 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
793 loginPageRequest.appendChild(paramList);
794
795 Element messageParam = this.doc.createElement(GSXML.PARAM_ELEM);
796 messageParam.setAttribute(GSXML.NAME_ATT, "loginMessage");
797 messageParam.setAttribute(GSXML.VALUE_ATT, "Either your username or password was incorrect, please try again.");
798 paramList.appendChild(messageParam);
799
800 Element urlParam = this.doc.createElement(GSXML.PARAM_ELEM);
801 urlParam.setAttribute(GSXML.NAME_ATT, "redirectURL");
802 String queryString = "";
803 if (request.getQueryString() != null)
804 {
805 queryString = "?" + request.getQueryString().replace("&", "&amp;");
806 }
807 urlParam.setAttribute(GSXML.VALUE_ATT, this.getServletName() + queryString);
808 paramList.appendChild(urlParam);
809
810 Node loginPageResponse = this.recept.process(loginPageMessage);
811 out.println(this.converter.getPrettyString(loginPageResponse));
812
813 return false;
814 }
815 }
816
817 //If a user is logged in
818 if (request.getAuthType() != null)
819 {
820 Element userInformation = this.doc.createElement(GSXML.USER_INFORMATION_ELEM);
821 userInformation.setAttribute("username", request.getUserPrincipal().getName());
822
823 Element userInfoMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
824 Element userInfoRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_SECURITY, "GetUserInformation", userContext);
825 userInfoMessage.appendChild(userInfoRequest);
826
827 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
828 userInfoRequest.appendChild(paramList);
829
830 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
831 param.setAttribute(GSXML.NAME_ATT, GSXML.USERNAME_ATT);
832 param.setAttribute(GSXML.VALUE_ATT, request.getUserPrincipal().getName());
833 paramList.appendChild(param);
834
835 Element userInformationResponse = (Element) GSXML.getChildByTagName(this.recept.process(userInfoMessage), GSXML.RESPONSE_ELEM);
836 Element responseParamList = (Element) GSXML.getChildByTagName(userInformationResponse, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
837 if (responseParamList == null)
838 {
839 logger.error("Can't get the groups for user " + request.getUserPrincipal().getName());
840 }
841 else
842 {
843 HashMap<String, Serializable> responseParams = GSXML.extractParams(responseParamList, true);
844 String groups = (String) responseParams.get(GSXML.GROUPS_ATT);
845
846 userInformation.setAttribute(GSXML.GROUPS_ATT, groups);
847 xml_request.appendChild(userInformation);
848 }
849 }
850
851 //If we are in a collection-related page then make sure this user is allowed to access it
852 if (collection != null && !collection.equals(""))
853 {
854 //Get the security info for this collection
855 Element securityMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
856 Element securityRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_SECURITY, collection, userContext);
857 securityMessage.appendChild(securityRequest);
858 if (document != null && !document.equals(""))
859 {
860 securityRequest.setAttribute(GSXML.NODE_OID, document);
861 }
862
863 Element securityResponse = (Element) GSXML.getChildByTagName(this.recept.process(securityMessage), GSXML.RESPONSE_ELEM);
864 if (securityResponse == null)
865 {
866 return false;
867 }
868
869 ArrayList<String> groups = GSXML.getGroupsFromSecurityResponse(securityResponse);
870
871 //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
872 if (!groups.contains(""))
873 {
874 boolean found = false;
875 for (String group : groups)
876 {
877 if (request.isUserInRole(group))
878 {
879 found = true;
880 break;
881 }
882 }
883
884 //The current user is not allowed to access the page so produce a login page
885 if (!found)
886 {
887 Element loginPageMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
888 Element loginPageRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
889 loginPageRequest.setAttribute(GSXML.ACTION_ATT, "p");
890 loginPageRequest.setAttribute(GSXML.SUBACTION_ATT, "login");
891 loginPageRequest.setAttribute(GSXML.OUTPUT_ATT, "html");
892 loginPageRequest.setAttribute(GSXML.BASE_URL, baseURL);
893 loginPageMessage.appendChild(loginPageRequest);
894
895 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
896 loginPageRequest.appendChild(paramList);
897
898 Element messageParam = this.doc.createElement(GSXML.PARAM_ELEM);
899 messageParam.setAttribute(GSXML.NAME_ATT, "loginMessage");
900 if (request.getAuthType() == null)
901 {
902 messageParam.setAttribute(GSXML.VALUE_ATT, "Please log in to view this page");
903 }
904 else
905 {
906 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?");
907 }
908 paramList.appendChild(messageParam);
909
910 Element urlParam = this.doc.createElement(GSXML.PARAM_ELEM);
911 urlParam.setAttribute(GSXML.NAME_ATT, "redirectURL");
912 if (request.getQueryString() != null && request.getQueryString().length() > 0)
913 {
914 urlParam.setAttribute(GSXML.VALUE_ATT, request.getRequestURL() + "?" + request.getQueryString().replace("&", "&amp;"));
915 }
916 else
917 {
918 urlParam.setAttribute(GSXML.VALUE_ATT, request.getRequestURL().toString());
919 }
920 paramList.appendChild(urlParam);
921
922 Node loginPageResponse = this.recept.process(loginPageMessage);
923 out.println(this.converter.getPrettyString(loginPageResponse));
924
925 return false;
926 }
927 }
928 }
929 return true;
930 }
931
932 //a debugging method
933 private void displaySize(Hashtable<String, UserSessionCache> table)
934 {
935 if (table == null)
936 {
937 logger.info("cached table is null");
938 return;
939 }
940 if (table.size() == 0)
941 {
942 logger.info("cached table size is zero");
943 return;
944 }
945 int num_cached_coll = 0;
946 ArrayList<UserSessionCache> cache_list = new ArrayList<UserSessionCache>(table.values());
947 for (int i = 0; i < cache_list.size(); i++)
948 {
949 num_cached_coll += cache_list.get(i).tableSize();
950 }
951 logger.info("Number of sessions : total number of cached collection info = " + table.size() + " : " + num_cached_coll);
952 }
953
954 /** merely a debugging method! */
955 private String tableToString(Hashtable<String, Hashtable<String, String>> table)
956 {
957 String str = "";
958 Enumeration<String> keys = table.keys();
959 while (keys.hasMoreElements())
960 {
961 String name = keys.nextElement();
962 str += name + ", ";
963 }
964 return str;
965 }
966
967 /**
968 * this goes through each URL and adds in a session id if needed-- its
969 * needed if the browser doesn't accept cookies also escapes things if
970 * needed
971 */
972 protected void encodeURLs(Node dataNode, HttpServletResponse response)
973 {
974
975 if (dataNode == null)
976 {
977 return;
978 }
979
980 Element data = null;
981
982 short nodeType = dataNode.getNodeType();
983 if (nodeType == Node.DOCUMENT_NODE)
984 {
985 Document docNode = (Document) dataNode;
986 data = docNode.getDocumentElement();
987 }
988 else
989 {
990 data = (Element) dataNode;
991 }
992
993 if (data != null)
994 {
995
996 // get all the <a> elements
997 NodeList hrefs = data.getElementsByTagName("a");
998 // Instead of calculating each iteration...
999 int hrefscount = hrefs.getLength();
1000
1001 for (int i = 0; hrefs != null && i < hrefscount; i++)
1002 {
1003 Element a = (Element) hrefs.item(i);
1004 // ugly hack to get rid of : in the args - interferes with session handling
1005 String href = a.getAttribute("href");
1006 if (!href.equals(""))
1007 {
1008 if (href.indexOf("?") != -1)
1009 {
1010 String[] parts = StringUtils.split(href, "\\?", -1);
1011 if (parts.length == 1)
1012 {
1013 parts[0] = StringUtils.replace(parts[0], ":", "%3A");
1014 href = "?" + parts[0];
1015 }
1016 else
1017 {
1018 parts[1] = StringUtils.replace(parts[1], ":", "%3A");
1019 href = parts[0] + "?" + parts[1];
1020 }
1021
1022 }
1023 a.setAttribute("href", response.encodeURL(href));
1024 }
1025 }
1026
1027 // now find any submit bits - get all the <form> elements
1028 NodeList forms = data.getElementsByTagName("form");
1029 int formscount = forms.getLength();
1030 for (int i = 0; forms != null && i < formscount; i++)
1031 {
1032 Element form = (Element) forms.item(i);
1033 form.setAttribute("action", response.encodeURL(form.getAttribute("action")));
1034 }
1035 // are these the only cases where URLs occur??
1036 // we should only do this for greenstone urls?
1037 }
1038
1039 }
1040
1041 synchronized protected int getNextUserId()
1042 {
1043 next_user_id++;
1044 return next_user_id;
1045 }
1046
1047 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
1048 {
1049 doGet(request, response);
1050 }
1051}
Note: See TracBrowser for help on using the repository browser.