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

Last change on this file since 32063 was 31185, checked in by Georgiy Litvinov, 7 years ago

Remove both s1.collection s1.group from cache in case either of them in query

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