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

Last change on this file since 27805 was 27805, checked in by sjm84, 11 years ago

Removing some unnecessary imports

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