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

Last change on this file since 29831 was 29831, checked in by ak19, 9 years ago

Dr Bainbridge fixed the bug in a solr collection where upon rebuilding a solr collection, the 2nd search results page is empty, but this does not happen if the server had merely been restarted. What was happening, was that the user session table was being cleared as a side-effect on the pings issued by activate.pl when activating and deactivating a rebuilt solr collection.

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