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

Last change on this file since 33612 was 33612, checked in by kjdon, 4 years ago

work to do with params. add in default values to params if they are not already defined in the session/table. global params (as determined by gs_params.isGlobal()) are kept in the session, not stored in the table. home page now gets stuff from session too. - all this done to make the favouritebasket param work properly, from setting default value in config file, to changing the value on home/collection prefs page

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