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

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

Various improvements and fixes mostly to do with adding depositor functionality

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