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

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

starting to put some of the strings into a dictionary - using ServiceRack.properties for now. Should rename this?? String.join is Java 8, but release kits use Java 7? so changing to StringUtils.join. I am still working on this file, so debugging messages have been left in for now

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