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

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

looking up default param values when start a new session to see if any have been set by Recept or MR. to set, add <format><paramDefault name='x' value='v'/> into interfaceConfig or siteConfig

  • Property svn:keywords set to Author Date Id Revision
File size: 40.0 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("GSRouter", 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 // we may want to remove all collection cache info, or just a specific collection
554 boolean clean_all = true;
555 String clean_collection = null;
556 // system commands are to activate/deactivate stuff
557 // collection param is in the sc parameter.
558 // don't like the fact that it is hard coded here
559 String coll = getFirstParam(GSParams.SYSTEM_CLUSTER, queryMap);
560 if (coll != null && !coll.equals(""))
561 {
562 clean_all = false;
563 clean_collection = coll;
564 }
565 else
566 {
567 // check other system types
568 if (subaction.equals("a") || subaction.equals("d"))
569 {
570 String module_name = getFirstParam("sn", queryMap);
571 if (module_name != null && !module_name.equals(""))
572 {
573 clean_all = false;
574 clean_collection = module_name;
575 }
576 }
577 }
578 if (clean_all)
579 {
580 // TODO
581 session_ids_table = new Hashtable<String, UserSessionCache>();
582 session.removeAttribute(GSXML.USER_SESSION_CACHE_ATT); // triggers valueUnbound(), which removes the session id from the session_ids_table
583 }
584 else
585 {
586 // just clean up info for clean_collection
587 ArrayList<UserSessionCache> cache_list = new ArrayList<UserSessionCache>(session_ids_table.values());
588 for (int i = 0; i < cache_list.size(); i++)
589 {
590 UserSessionCache cache = cache_list.get(i);
591 cache.cleanupCache(clean_collection);
592 }
593
594 }
595 }
596
597 // cache_key is the collection name, or service name
598 String cache_key = specified_cache_key;
599 if (cache_key == null || cache_key.equals(""))
600 {
601 cache_key = collection;
602 }
603 if (cache_key == null || cache_key.equals(""))
604 {
605 cache_key = service;
606 }
607
608 // logger.info("should_cache= " + should_cache);
609
610 //clear the collection-specific cache in the session, since we have no way to know whether this session is
611 //about the same collection as the last session or not.
612 Enumeration attributeNames = session.getAttributeNames();
613 while (attributeNames.hasMoreElements())
614 {
615 String name = (String) attributeNames.nextElement();
616 if (!name.equals(GSXML.USER_SESSION_CACHE_ATT) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT))
617 {
618 session.removeAttribute(name);
619 }
620 }
621
622 UserSessionCache session_cache = null;
623 Hashtable<String, Hashtable<String, String>> param_table = null;
624 Hashtable<String, String> table = null;
625 String sid = session.getId();
626 if (should_cache == true && cache_key != null && !cache_key.equals(""))
627 {
628 if (session_ids_table.containsKey(sid))
629 {
630 session_cache = session_ids_table.get(sid);
631 param_table = session_cache.getParamsTable();
632 if (param_table.containsKey(cache_key))
633 {
634 //logger.info("existing table: " + collection);
635 table = param_table.get(cache_key);
636 }
637 else
638 {
639 table = new Hashtable<String, String>();
640 param_table.put(cache_key, table);
641 //logger.info("new table: " + collection);
642 }
643 }
644 else
645 {
646 param_table = new Hashtable<String, Hashtable<String, String>>();
647 table = new Hashtable<String, String>();
648 param_table.put(cache_key, table);
649 session_cache = new UserSessionCache(sid, param_table);
650 session_ids_table.put(sid, session_cache);
651 session.setAttribute(GSXML.USER_SESSION_CACHE_ATT, session_cache);
652
653 // here we add in default params?
654 ArrayList<String> defp = this.gs_params.getParamsWithDefaults();
655 Iterator i = this.gs_params.getParamsWithDefaults().iterator();
656 while (i.hasNext()) {
657 String p = (String)i.next();
658 String v = this.gs_params.getParamDefault(p);
659 if (!p.equals(GSParams.ACTION) && !p.equals(GSParams.SUBACTION) && !p.equals(GSParams.LANGUAGE) && !p.equals(GSParams.OUTPUT)) {
660 table.put(p,v);
661 }
662 }
663
664 }
665 }
666
667 if (action == null || action.equals(""))
668 {
669 // should we do all the following stuff if using default page?
670 // display the home page - the default page
671 xml_request.setAttribute(GSXML.ACTION_ATT, "p");
672 xml_request.setAttribute(GSXML.SUBACTION_ATT, PageAction.HOME_PAGE);
673 }
674 else
675 {
676 xml_request.setAttribute(GSXML.ACTION_ATT, action);
677 if (subaction != null)
678 {
679 xml_request.setAttribute(GSXML.SUBACTION_ATT, subaction);
680 }
681
682 // create the param list for the greenstone request - includes
683 // the params from the current request and any others from the saved session
684 Element xml_param_list = msg_doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
685 xml_request.appendChild(xml_param_list);
686
687 if (queryMap.containsKey("s1.collection") || queryMap.containsKey("s1.group")){
688 table.remove("s1.collection");
689 table.remove("s1.group");
690 }
691 for (String name : queryMap.keySet())
692 {
693 if (!name.equals(GSParams.ACTION) && !name.equals(GSParams.SUBACTION) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSParams.OUTPUT))
694 {// we have already dealt with these
695
696 String value = "";
697 String[] values = queryMap.get(name);
698 value = values[0];
699 if (values.length > 1)
700 {
701 for (int i = 1; i < values.length; i++)
702 {
703 value += "," + values[i];
704 }
705 }
706 // either add it to the param list straight away, or save it to the session and add it later
707 if (this.gs_params.shouldSave(name) && table != null)
708 {
709 table.put(name, value);
710 }
711 else
712 {
713 Element param = msg_doc.createElement(GSXML.PARAM_ELEM);
714 param.setAttribute(GSXML.NAME_ATT, name);
715 param.setAttribute(GSXML.VALUE_ATT, GSXML.xmlSafe(value));
716 if (this.gs_params.isSensitive(name)) {
717 param.setAttribute(GSXML.SENSITIVE_ATT, "true");
718 }
719 xml_param_list.appendChild(param);
720
721 }
722 }
723 }
724 //put everything in the table into the session
725 // do we need to do this? why not just put from table into param list
726 if (table != null)
727 {
728 Enumeration<String> keys = table.keys();
729 while (keys.hasMoreElements())
730 {
731 String name = keys.nextElement();
732 session.setAttribute(name, table.get(name));
733 }
734 }
735
736 // put in all the params from the session cache
737 Enumeration params = session.getAttributeNames();
738 while (params.hasMoreElements())
739 {
740 String name = (String) params.nextElement();
741
742 if (!name.equals(GSXML.USER_SESSION_CACHE_ATT) && !name.equals(GSParams.LANGUAGE) && !name.equals(GSXML.USER_ID_ATT))
743 {
744
745 // lang and uid are stored but we dont want it in the param list cos its already in the request
746 Element param = msg_doc.createElement(GSXML.PARAM_ELEM);
747 param.setAttribute(GSXML.NAME_ATT, name);
748 String value = GSXML.xmlSafe((String) session.getAttribute(name));
749
750 // ugly hack to undo : escaping
751 value = StringUtils.replace(value, "%3A", "\\:");
752 param.setAttribute(GSXML.VALUE_ATT, value);
753 xml_param_list.appendChild(param);
754 }
755 }
756 }
757
758 if (output.equals("json"))
759 {
760 response.setContentType("application/json");
761 }
762 else if (!output.equals("html") && !output.equals("server") && !output.equals("xsltclient"))
763 {
764 response.setContentType("text/xml"); // for now use text
765 }
766
767 //Add custom HTTP headers if requested
768 String httpHeadersParam = getFirstParam(GSParams.HTTP_HEADER_FIELDS, queryMap);
769 if (httpHeadersParam != null && httpHeadersParam.length() > 0)
770 {
771 Gson gson = new Gson();
772 Type type = new TypeToken<List<Map<String, String>>>()
773 {
774 }.getType();
775 List<Map<String, String>> httpHeaders = gson.fromJson(httpHeadersParam, type);
776 if (httpHeaders != null && httpHeaders.size() > 0)
777 {
778
779 for (int j = 0; j < httpHeaders.size(); j++)
780 {
781 Map nameValueMap = httpHeaders.get(j);
782 String name = (String) nameValueMap.get("name");
783 String value = (String) nameValueMap.get("value");
784
785 if (name != null && value != null)
786 {
787 response.setHeader(name, value);
788 }
789 }
790 }
791 }
792
793 String requestedURL = request.getRequestURL().toString();
794 String baseURL = "";
795 if (requestedURL.indexOf(library_name) != -1)
796 {
797 baseURL = requestedURL.substring(0, requestedURL.indexOf(library_name));
798 xml_request.setAttribute("baseURL", baseURL);
799 }
800 String fullURL;
801 if (request.getQueryString() != null)
802 {
803 fullURL = requestedURL + "?" + request.getQueryString();
804 }
805 else
806 {
807 fullURL = requestedURL;
808 }
809
810 xml_request.setAttribute("remoteAddress", request.getRemoteAddr());
811 xml_request.setAttribute("fullURL", fullURL.replace("&", "&amp;"));
812
813 if (!runSecurityChecks(request, xml_request, userContext, out, baseURL, collection, document, queryMap))
814 {
815 return;
816 }
817
818 Node xml_result = this.recept.process(xml_message);
819 encodeURLs(xml_result, response);
820
821 String xml_string = XMLConverter.getPrettyString(xml_result);
822
823 if (output.equals("json"))
824 {
825 try
826 {
827 JSONObject json_obj = org.json.XML.toJSONObject(xml_string);
828
829 out.println(json_obj.toString());
830 }
831 catch (Exception e)
832 {
833 e.printStackTrace();
834 out.println("Error: failed to convert output XML to JSON format");
835 }
836 }
837 else
838 {
839 out.println(xml_string);
840 }
841
842 displaySize(session_ids_table);
843 }
844
845 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
846 {
847 doGetOrPost(request, response, request.getParameterMap());
848 } //end of doGet(HttpServletRequest, HttpServletResponse)
849
850 private boolean runSecurityChecks(HttpServletRequest request, Element xml_request, UserContext userContext, PrintWriter out, String baseURL, String collection, String document, Map<String, String[]> queryMap) throws ServletException
851 {
852 //Check if we need to login or logout
853 String username = getFirstParam(GSParams.USERNAME, queryMap);
854 String password = getFirstParam(GSParams.PASSWORD, queryMap);
855 String logout = getFirstParam(GSParams.LOGOUT, queryMap);
856
857 if (logout != null)
858 {
859 request.logout();
860 }
861
862 if (username != null && password != null)
863 {
864 //We are changing to another user, so log out first
865 if (request.getAuthType() != null)
866 {
867 request.logout();
868 }
869
870 //This try/catch block catches when the login request fails (e.g. The user enters an incorrect password).
871 try
872 {
873 //Try a global login first
874 password = Authentication.hashPassword(password);
875 request.login(username, password);
876 }
877 catch (Exception ex)
878 {
879 try
880 {
881 //If the global login fails then try a site-level login
882 String siteName = (String) this.recept.getConfigParams().get(GSConstants.SITE_NAME);
883 request.login(siteName + "-" + username, password);
884 }
885 catch (Exception exc)
886 {
887 //The user entered in either the wrong username or the wrong password
888 Document loginPageDoc = XMLConverter.newDOM();
889 Element loginPageMessage = loginPageDoc.createElement(GSXML.MESSAGE_ELEM);
890 Element loginPageRequest = GSXML.createBasicRequest(loginPageDoc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
891 loginPageRequest.setAttribute(GSXML.ACTION_ATT, "p");
892 loginPageRequest.setAttribute(GSXML.SUBACTION_ATT, "login");
893 loginPageRequest.setAttribute(GSXML.OUTPUT_ATT, "html");
894 loginPageRequest.setAttribute(GSXML.BASE_URL, baseURL);
895 loginPageMessage.appendChild(loginPageRequest);
896
897 Element paramList = loginPageDoc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
898 loginPageRequest.appendChild(paramList);
899
900 Element messageParam = loginPageDoc.createElement(GSXML.PARAM_ELEM);
901 messageParam.setAttribute(GSXML.NAME_ATT, "loginMessage");
902 messageParam.setAttribute(GSXML.VALUE_ATT, "Either your username or password was incorrect, please try again.");
903 paramList.appendChild(messageParam);
904
905 Element urlParam = loginPageDoc.createElement(GSXML.PARAM_ELEM);
906 urlParam.setAttribute(GSXML.NAME_ATT, "redirectURL");
907 String queryString = "";
908 if (request.getQueryString() != null)
909 {
910 queryString = "?" + request.getQueryString().replace("&", "&amp;");
911 }
912 urlParam.setAttribute(GSXML.VALUE_ATT, library_name + queryString);
913 paramList.appendChild(urlParam);
914
915 Node loginPageResponse = this.recept.process(loginPageMessage);
916 out.println(XMLConverter.getPrettyString(loginPageResponse));
917
918 return false;
919 }
920 }
921 }
922
923 //If a user is logged in
924 if (request.getAuthType() != null)
925 {
926 Element userInformation = xml_request.getOwnerDocument().createElement(GSXML.USER_INFORMATION_ELEM);
927 userInformation.setAttribute(GSXML.USERNAME_ATT, request.getUserPrincipal().getName());
928
929 Document msg_doc = XMLConverter.newDOM();
930 Element userInfoMessage = msg_doc.createElement(GSXML.MESSAGE_ELEM);
931 Element userInfoRequest = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_SECURITY, "GetUserInformation", userContext);
932 userInfoMessage.appendChild(userInfoRequest);
933
934 Element paramList = msg_doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
935 userInfoRequest.appendChild(paramList);
936
937 Element param = msg_doc.createElement(GSXML.PARAM_ELEM);
938 param.setAttribute(GSXML.NAME_ATT, GSXML.USERNAME_ATT);
939 param.setAttribute(GSXML.VALUE_ATT, request.getUserPrincipal().getName());
940 paramList.appendChild(param);
941
942 Element userInformationResponse = (Element) GSXML.getChildByTagName(this.recept.process(userInfoMessage), GSXML.RESPONSE_ELEM);
943 Element responseParamList = (Element) GSXML.getChildByTagName(userInformationResponse, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
944 if (responseParamList == null)
945 {
946 logger.error("Can't get the groups for user " + request.getUserPrincipal().getName());
947 }
948 else
949 {
950 HashMap<String, Serializable> responseParams = GSXML.extractParams(responseParamList, true);
951 String groups = (String) responseParams.get(GSXML.GROUPS_ATT);
952 String editEnabled = (String) responseParams.get("editEnabled");
953
954 userInformation.setAttribute(GSXML.GROUPS_ATT, groups);
955 userInformation.setAttribute("editEnabled", (editEnabled != null) ? editEnabled : "false");
956 xml_request.appendChild(userInformation);
957 }
958 }
959
960 //If we are in a collection-related page then make sure this user is allowed to access it
961 if (collection != null && !collection.equals(""))
962 {
963 //Get the security info for this collection
964 Document msg_doc = XMLConverter.newDOM();
965 Element securityMessage = msg_doc.createElement(GSXML.MESSAGE_ELEM);
966 Element securityRequest = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_SECURITY, collection, userContext);
967 securityMessage.appendChild(securityRequest);
968 if (document != null && !document.equals(""))
969 {
970 securityRequest.setAttribute(GSXML.NODE_OID, document);
971 }
972
973 Element securityResponse = (Element) GSXML.getChildByTagName(this.recept.process(securityMessage), GSXML.RESPONSE_ELEM);
974 if (securityResponse == null)
975 {
976 return false;
977 }
978
979 ArrayList<String> groups = GSXML.getGroupsFromSecurityResponse(securityResponse);
980
981 //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
982 if (!groups.contains(""))
983 {
984 boolean found = false;
985 for (String group : groups)
986 {
987 if (request.isUserInRole(group))
988 {
989 found = true;
990 break;
991 }
992 }
993
994 //The current user is not allowed to access the page so produce a login page
995 if (!found)
996 {
997 Document loginPageDoc = XMLConverter.newDOM();
998 Element loginPageMessage = loginPageDoc.createElement(GSXML.MESSAGE_ELEM);
999 Element loginPageRequest = GSXML.createBasicRequest(loginPageDoc, GSXML.REQUEST_TYPE_PAGE, "", userContext);
1000 loginPageRequest.setAttribute(GSXML.ACTION_ATT, "p");
1001 loginPageRequest.setAttribute(GSXML.SUBACTION_ATT, "login");
1002 loginPageRequest.setAttribute(GSXML.OUTPUT_ATT, "html");
1003 loginPageRequest.setAttribute(GSXML.BASE_URL, baseURL);
1004 loginPageMessage.appendChild(loginPageRequest);
1005
1006 Element paramList = loginPageDoc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
1007 loginPageRequest.appendChild(paramList);
1008
1009 Element messageParam = loginPageDoc.createElement(GSXML.PARAM_ELEM);
1010 messageParam.setAttribute(GSXML.NAME_ATT, "loginMessage");
1011 if (request.getAuthType() == null)
1012 {
1013 messageParam.setAttribute(GSXML.VALUE_ATT, "Please log in to view this page");
1014 }
1015 else
1016 {
1017 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?");
1018 }
1019 paramList.appendChild(messageParam);
1020
1021 Element urlParam = loginPageDoc.createElement(GSXML.PARAM_ELEM);
1022 urlParam.setAttribute(GSXML.NAME_ATT, "redirectURL");
1023 if (request.getQueryString() != null && request.getQueryString().length() > 0)
1024 {
1025 urlParam.setAttribute(GSXML.VALUE_ATT, request.getRequestURL() + "?" + request.getQueryString().replace("&", "&amp;"));
1026 }
1027 else
1028 {
1029 urlParam.setAttribute(GSXML.VALUE_ATT, request.getRequestURL().toString());
1030 }
1031 paramList.appendChild(urlParam);
1032
1033 Node loginPageResponse = this.recept.process(loginPageMessage);
1034 out.println(XMLConverter.getPrettyString(loginPageResponse));
1035
1036 return false;
1037 }
1038 }
1039 }
1040 return true;
1041 }
1042
1043 //a debugging method
1044 private void displaySize(Hashtable<String, UserSessionCache> table)
1045 {
1046 if (table == null)
1047 {
1048 logger.info("cached table is null");
1049 return;
1050 }
1051 if (table.size() == 0)
1052 {
1053 logger.info("cached table size is zero");
1054 return;
1055 }
1056 int num_cached_coll = 0;
1057 ArrayList<UserSessionCache> cache_list = new ArrayList<UserSessionCache>(table.values());
1058 for (int i = 0; i < cache_list.size(); i++)
1059 {
1060 num_cached_coll += cache_list.get(i).tableSize();
1061 }
1062 logger.info("Number of sessions : total number of cached collection info = " + table.size() + " : " + num_cached_coll);
1063 }
1064
1065 /** merely a debugging method! */
1066 private String tableToString(Hashtable<String, Hashtable<String, String>> table)
1067 {
1068 String str = "";
1069 Enumeration<String> keys = table.keys();
1070 while (keys.hasMoreElements())
1071 {
1072 String name = keys.nextElement();
1073 str += name + ", ";
1074 }
1075 return str;
1076 }
1077
1078 /**
1079 * this goes through each URL and adds in a session id if needed-- its
1080 * needed if the browser doesn't accept cookies also escapes things if
1081 * needed
1082 */
1083 protected void encodeURLs(Node dataNode, HttpServletResponse response)
1084 {
1085 if (dataNode == null)
1086 {
1087 return;
1088 }
1089
1090 Element data = null;
1091
1092 short nodeType = dataNode.getNodeType();
1093 if (nodeType == Node.DOCUMENT_NODE)
1094 {
1095 Document docNode = (Document) dataNode;
1096 data = docNode.getDocumentElement();
1097 }
1098 else
1099 {
1100 data = (Element) dataNode;
1101 }
1102
1103 if (data != null)
1104 {
1105
1106 // get all the <a> elements
1107 NodeList hrefs = data.getElementsByTagName("a");
1108 // Instead of calculating each iteration...
1109 int hrefscount = hrefs.getLength();
1110
1111 for (int i = 0; hrefs != null && i < hrefscount; i++)
1112 {
1113 Element a = (Element) hrefs.item(i);
1114 // ugly hack to get rid of : in the args - interferes with session handling
1115 String href = a.getAttribute("href");
1116 if (!href.equals(""))
1117 {
1118 if (href.indexOf("?") != -1)
1119 {
1120 String[] parts = StringUtils.split(href, "\\?", -1);
1121 if (parts.length == 1)
1122 {
1123 parts[0] = StringUtils.replace(parts[0], ":", "%3A");
1124 href = "?" + parts[0];
1125 }
1126 else
1127 {
1128 parts[1] = StringUtils.replace(parts[1], ":", "%3A");
1129 href = parts[0] + "?" + parts[1];
1130 }
1131
1132 }
1133 a.setAttribute("href", response.encodeURL(href));
1134 }
1135 }
1136
1137 // now find any submit bits - get all the <form> elements
1138 NodeList forms = data.getElementsByTagName("form");
1139 int formscount = forms.getLength();
1140 for (int i = 0; forms != null && i < formscount; i++)
1141 {
1142 Element form = (Element) forms.item(i);
1143 form.setAttribute("action", response.encodeURL(form.getAttribute("action")));
1144 }
1145 // are these the only cases where URLs occur??
1146 // we should only do this for greenstone urls?
1147 }
1148
1149 }
1150
1151 protected String getFirstParam(String name, Map<String, String[]> map)
1152 {
1153 String[] val = map.get(name);
1154 if (val == null || val.length == 0)
1155 {
1156 return null;
1157 }
1158
1159 return val[0];
1160 }
1161
1162 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
1163 {
1164 //Check if we need to process a file upload
1165 if (ServletFileUpload.isMultipartContent(request))
1166 {
1167 DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
1168
1169 int sizeLimit = System.getProperties().containsKey("servlet.upload.filesize.limit") ? Integer.parseInt(System.getProperty("servlet.upload.filesize.limit")) : 100 * 1024 * 1024;
1170
1171 File tempDir = new File(GlobalProperties.getGSDL3Home() + File.separator + "tmp");
1172 if (!tempDir.exists())
1173 {
1174 tempDir.mkdirs();
1175 }
1176
1177 //We want all files to be stored on disk (hence the 0)
1178 fileItemFactory.setSizeThreshold(0);
1179 fileItemFactory.setRepository(tempDir);
1180
1181 ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
1182 uploadHandler.setFileSizeMax(sizeLimit);
1183
1184 HashMap<String, String[]> queryMap = new HashMap<String, String[]>();
1185 try
1186 {
1187 List items = uploadHandler.parseRequest(request);
1188 Iterator iter = items.iterator();
1189 while (iter.hasNext())
1190 {
1191 FileItem current = (FileItem) iter.next();
1192 if (current.isFormField())
1193 {
1194 queryMap.put(current.getFieldName(), new String[] { current.getString() });
1195 }
1196 else if (current.getName() != null && !current.getName().equals(""))
1197 {
1198 File file = new File(tempDir, current.getName());
1199 current.write(file);
1200
1201 queryMap.put("md___ex.Filesize", new String[] { "" + file.length() });
1202 queryMap.put("md___ex.Filename", new String[] { "" + current.getName() });
1203 }
1204 }
1205 }
1206 catch (Exception e)
1207 {
1208 e.printStackTrace();
1209 }
1210
1211 doGetOrPost(request, response, queryMap);
1212 }
1213 else
1214 {
1215 doGetOrPost(request, response, request.getParameterMap());
1216 }
1217 }
1218}
Note: See TracBrowser for help on using the repository browser.