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

Last change on this file since 33241 was 33175, checked in by kjdon, 5 years ago

the servlet context is one per tomcat install, not one per servlet. ie shared across servlets. So can't set library name there as it gets overwritten when next servlet is initialized. Because we want to get MR from the context, we store as librarynameRouter, one per servlet.

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