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

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

additional debug statements which need removing later. PLus, changed when we add defaault params to the table. not only do it for a new session id, but need to do it for each new table. otherwise only the first collection will get the default parameter.

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