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

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

fixed up processRedirectRequest method. for some reason parts had been commented out - just my testing?? - so put that back. And implemented el=framed portion

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