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

Last change on this file since 32327 was 32327, checked in by kjdon, 6 years ago

changed the way we read in servlet init params - now loop through them all so that we can add any new ones into config_params. then they will eventually make their way to xslt params for the transformation - now can add new ones without having to modify java code.

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