001: /*
002: * $Id: SessionManager.java,v 1.37 2007/09/18 08:45:08 agoubard Exp $
003: *
004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
005: * See the COPYRIGHT file for redistribution and use restrictions.
006: */
007: package org.xins.server.frontend;
008:
009: import java.util.ArrayList;
010: import java.util.Enumeration;
011: import java.util.HashSet;
012: import java.util.Iterator;
013: import java.util.Map;
014: import java.util.Set;
015: import java.util.StringTokenizer;
016: import javax.servlet.http.Cookie;
017: import javax.servlet.http.HttpServletRequest;
018: import javax.servlet.http.HttpSession;
019: import org.xins.common.MandatoryArgumentChecker;
020: import org.xins.common.Utils;
021: import org.xins.common.collections.ChainedMap;
022: import org.xins.common.collections.InvalidPropertyValueException;
023: import org.xins.common.collections.MissingRequiredPropertyException;
024: import org.xins.common.collections.PropertyReader;
025: import org.xins.common.manageable.BootstrapException;
026: import org.xins.common.manageable.Manageable;
027: import org.xins.common.spec.FunctionSpec;
028: import org.xins.common.text.TextUtils;
029: import org.xins.server.API;
030: import org.xins.server.Log;
031:
032: /**
033: * Manager for the sessions and session properties for the XINS front-end framework.
034: *
035: * @version $Revision: 1.37 $ $Date: 2007/09/18 08:45:08 $
036: * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a>
037: *
038: * @since XINS 1.5.0.
039: */
040: public class SessionManager extends Manageable {
041:
042: /**
043: * The API, never <code>null</code>.
044: */
045: private API _api;
046:
047: /**
048: * The HTTP session of the current running Thread, never <code>null</code>.
049: */
050: private ThreadLocal _currentSession = new ThreadLocal();
051:
052: /**
053: * The list of pages that doesn't need to be logged in, cannot be <code>null</code>.
054: */
055: private ArrayList _unrestrictedPages = new ArrayList();
056:
057: /**
058: * The default page, cannot be <code>null</code>.
059: */
060: private String _defaultCommand;
061:
062: /**
063: * Creates the session manager.
064: *
065: * @param api
066: * the API.
067: */
068: public SessionManager(API api) {
069: _api = api;
070: }
071:
072: protected void bootstrapImpl(PropertyReader bootstrapProperties)
073: throws MissingRequiredPropertyException,
074: InvalidPropertyValueException, BootstrapException {
075: _defaultCommand = bootstrapProperties
076: .get("xinsff.default.command");
077: if (_defaultCommand == null) {
078: _defaultCommand = "DefaultCommand";
079: }
080: String loginPage = bootstrapProperties.get("xinsff.login.page");
081: if (loginPage != null) {
082: _unrestrictedPages.add(loginPage);
083: _unrestrictedPages.add("Control");
084: _unrestrictedPages.add("Logout");
085: String unrestrictedPages = bootstrapProperties
086: .get("xinsff.unrestricted.pages");
087: if (unrestrictedPages != null
088: && !unrestrictedPages.equals("")) {
089: StringTokenizer stUnrestricted = new StringTokenizer(
090: unrestrictedPages, ",", false);
091: while (stUnrestricted.hasMoreTokens()) {
092: String nextPage = stUnrestricted.nextToken();
093: _unrestrictedPages.add(nextPage);
094: }
095: }
096: } else {
097: _unrestrictedPages.add("*");
098: }
099: }
100:
101: /**
102: * Method called when the request is received.
103: *
104: * This method will take care of creating a sessionId if needed and
105: * putting the input parameters in the session.
106: *
107: * @param request
108: * the HTTP request, cannot be <code>null</code>.
109: */
110: protected void request(HttpServletRequest request) {
111:
112: // Find the session ID in the cookies
113: String sessionId = null;
114: Cookie[] cookies = request.getCookies();
115: int cookieCount = (cookies == null) ? 0 : cookies.length;
116: for (int i = 0; i < cookieCount && sessionId == null; i++) {
117: Cookie cookie = cookies[i];
118: String name = cookie.getName();
119: if ("SessionID".equals(name)) {
120: sessionId = cookie.getValue();
121: }
122: }
123:
124: HttpSession session = request.getSession(true);
125: _currentSession.set(session);
126:
127: // If the session ID is not found in the cookies, create a new one
128: if (sessionId == null || sessionId.equals("")
129: || sessionId.equals("null")) {
130:
131: sessionId = session.getId();
132: setProperty(sessionId, Boolean.FALSE);
133: }
134:
135: // Fill the input parameters
136: Map inputParameters = new ChainedMap();
137: Enumeration params = request.getParameterNames();
138: while (params.hasMoreElements()) {
139: String name = (String) params.nextElement();
140: String value = request.getParameter(name);
141: if ("".equals(value) || name.equals(getSessionId())) {
142: value = null;
143: }
144: inputParameters.put(name, value);
145: }
146: setProperty("_inputs", inputParameters);
147: setProperty("_remoteIP", request.getRemoteAddr());
148: setProperty("_propertiesSet", new HashSet());
149: setProperty("_userAgent", request.getHeader("User-Agent"));
150: }
151:
152: /**
153: * Sets the input parameters in the session is the execution of the function is successful.
154: *
155: * @param successful
156: * <code>true</code> if the function is successful, <code>false</code> otherwise.
157: */
158: protected void result(boolean successful) {
159: if (successful) {
160: Map inputParameters = (Map) getProperty("_inputs");
161: Set propertiesSet = (Set) getProperty("_propertiesSet");
162: if (propertiesSet.contains("*")) {
163: return;
164: }
165:
166: // Only valid inputs of an existing function will be added.
167: String command = (String) inputParameters.get("command");
168: String action = (String) inputParameters.get("action");
169: String functionName = command;
170: if (action != null && !action.equals("")
171: && !action.equalsIgnoreCase("show")) {
172: functionName += TextUtils.firstCharUpper(action);
173: }
174: try {
175: Map specInputParameters = _api.getAPISpecification()
176: .getFunction(functionName).getInputParameters();
177: Map clonedInputParameters = new ChainedMap();
178: clonedInputParameters.putAll(inputParameters);
179: Iterator itInputParameters = clonedInputParameters
180: .entrySet().iterator();
181: while (itInputParameters.hasNext()) {
182: Map.Entry nextInput = (Map.Entry) itInputParameters
183: .next();
184: String parameterName = (String) nextInput.getKey();
185: parameterName = getRealParameter(parameterName,
186: functionName);
187: if (specInputParameters.containsKey(parameterName)
188: && !propertiesSet.contains(parameterName)
189: && !propertiesSet.contains(parameterName
190: .toLowerCase())) {
191: String value = (String) nextInput.getValue();
192: if ("".equals(value)
193: || parameterName.equals(getSessionId())) {
194: value = null;
195: }
196: setProperty(parameterName.toLowerCase(), value);
197: }
198: }
199: } catch (Exception ex) {
200: // Ignore
201: Utils.logIgnoredException(ex);
202: }
203: }
204: }
205:
206: /**
207: * Returns <code>true</code> if the user needs to log in to access the page.
208: *
209: * @return
210: * whether the user should log in.
211: **/
212: public boolean shouldLogIn() {
213: // Check if the page requires a login
214: Map inputParameters = (Map) getProperty("_inputs");
215: String command = (String) inputParameters.get("command");
216: if (command == null || command.equals("")) {
217: command = _defaultCommand;
218: }
219: if (_unrestrictedPages.contains("*")
220: || _unrestrictedPages.contains(command)
221: || (command != null && command.startsWith("_"))) {
222: return false;
223: }
224:
225: // Check if the user is logged in
226: boolean shouldLogIn = !getBoolProperty(getSessionId());
227: return shouldLogIn;
228: }
229:
230: /**
231: * Gets the session id.
232: *
233: * @return
234: * the session ID, can be <code>null</code>.
235: */
236: public String getSessionId() {
237: HttpSession session = (HttpSession) _currentSession.get();
238: if (session == null) {
239: return null;
240: }
241: String sessionId = session.getId();
242: return sessionId;
243: }
244:
245: /**
246: * Gets the session properties.
247: *
248: * @return
249: * a map where the key is the property name and the value is the session
250: * property value.
251: */
252: public Map getProperties() {
253: HttpSession session = (HttpSession) _currentSession.get();
254: if (session == null) {
255: return new ChainedMap();
256: }
257: Map properties = new ChainedMap();
258: Enumeration enuAttributes = session.getAttributeNames();
259: while (enuAttributes.hasMoreElements()) {
260: String nextAttribute = (String) enuAttributes.nextElement();
261: Object value = session.getAttribute(nextAttribute);
262: properties.put(nextAttribute, value);
263: }
264: return properties;
265: }
266:
267: /**
268: * Adds a new session property. Any previous property is replaced.
269: * If the value is <code>null</code>, the property is removed.
270: *
271: * @param name
272: * the name of the session property, cannot be <code>null</code>.
273: *
274: * @param value
275: * the value of the session property, can be <code>null</code>.
276: *
277: * @throws IllegalArgumentException
278: * if <code>name == null</code>.
279: */
280: public void setProperty(String name, Object value)
281: throws IllegalArgumentException {
282: MandatoryArgumentChecker.check("name", name);
283: HttpSession session = (HttpSession) _currentSession.get();
284: if (session != null) {
285: if (value == null) {
286: removeProperty(name);
287: } else {
288: try {
289: session.setAttribute(name, value);
290: } catch (Throwable t) {
291:
292: // Should never happen as the session is valid
293: Utils.logProgrammingError(t);
294: }
295: }
296: }
297: if (!name.startsWith("_")) {
298: registerProperty(name);
299: }
300: }
301:
302: /**
303: * Adds or sets a new session property.
304: *
305: * @param name
306: * the name of the session property, cannot be <code>null</code>.
307: *
308: * @param value
309: * the value of the session property.
310: *
311: * @throws IllegalArgumentException
312: * if <code>name == null</code>.
313: */
314: public void setProperty(String name, boolean value)
315: throws IllegalArgumentException {
316: MandatoryArgumentChecker.check("name", name);
317: setProperty(name, value ? Boolean.TRUE : Boolean.FALSE);
318: }
319:
320: /**
321: * Gets the value of a session property.
322: *
323: * @param name
324: * the name of the session property, cannot be <code>null</code>.
325: *
326: * @return
327: * the property value or <code>null</code> if the property does not exist.
328: *
329: * @throws IllegalArgumentException
330: * if <code>name == null</code>.
331: */
332: public Object getProperty(String name)
333: throws IllegalArgumentException {
334: MandatoryArgumentChecker.check("name", name);
335: HttpSession session = (HttpSession) _currentSession.get();
336: if (session == null) {
337: return null;
338: }
339: Object propertyValue = session.getAttribute(name);
340: return propertyValue;
341: }
342:
343: /**
344: * Gets the value of a boolean session property.
345: *
346: * @param name
347: * the name of the session property, cannot be <code>null</code>.
348: *
349: * @return
350: * <code>true</code> if the value of the property is "true" or Boolean.TRUE,
351: * <code>false</code> otherwise.
352: *
353: * @throws IllegalArgumentException
354: * if <code>name == null</code>.
355: */
356: public boolean getBoolProperty(String name)
357: throws IllegalArgumentException {
358: MandatoryArgumentChecker.check("name", name);
359: HttpSession session = (HttpSession) _currentSession.get();
360: if (session == null) {
361: return false;
362: }
363: Object value = session.getAttribute(name);
364: boolean isTrue = "true".equals(value)
365: || Boolean.TRUE.equals(value);
366: return isTrue;
367: }
368:
369: /**
370: * Removes a session property.
371: *
372: * @param name
373: * the name of the session property, cannot be <code>null</code>.
374: *
375: * @throws IllegalArgumentException
376: * if <code>name == null</code>.
377: */
378: public void removeProperty(String name)
379: throws IllegalArgumentException {
380: MandatoryArgumentChecker.check("name", name);
381: HttpSession session = (HttpSession) _currentSession.get();
382: if (session != null) {
383: session.removeAttribute(name);
384:
385: // Also remove it from the input parameter list.
386: Map inputParameters = (Map) session.getAttribute("_inputs");
387: if (inputParameters != null) {
388: inputParameters.remove(name);
389: }
390: registerProperty(name);
391: }
392: }
393:
394: /**
395: * Removes all session properties for the customer.
396: */
397: public void removeProperties() {
398: HttpSession session = (HttpSession) _currentSession.get();
399: if (session != null) {
400:
401: // Removing the attributes directly throws a ConcurentModificationException in Tomcat
402: ArrayList attributeNames = new ArrayList();
403: Enumeration enuAttributes = session.getAttributeNames();
404: while (enuAttributes.hasMoreElements()) {
405: String nextAttribute = (String) enuAttributes
406: .nextElement();
407: if (!nextAttribute.startsWith("_")) {
408: attributeNames.add(nextAttribute);
409: }
410: }
411: Iterator itAttributes = attributeNames.iterator();
412: while (itAttributes.hasNext()) {
413: String nextAttribute = (String) itAttributes.next();
414: session.removeAttribute(nextAttribute);
415: }
416: registerProperty("*");
417: }
418: }
419:
420: /**
421: * Registers a property as manually set by the user. The property will then
422: * not be overwritten by the input parameter.
423: *
424: * @param name
425: * the name of the property set or remove in the function implementation, cannot be <code>null</code>.
426: */
427: private void registerProperty(String name) {
428: Set propertiesSet = (Set) getProperty("_propertiesSet");
429: if (propertiesSet != null) {
430: propertiesSet.add(name);
431: } else {
432: propertiesSet = new HashSet();
433: propertiesSet.add(name);
434: setProperty("_propertiesSet", propertiesSet);
435: }
436: }
437:
438: /**
439: * Gets the real parameter name.
440: *
441: * @param receivedParameter
442: * the name of the parameter as received.
443: *
444: * @param functionName
445: * the name of the function.
446: *
447: * @return
448: * the name of the parameter as specified in the function.
449: *
450: * @deprecated
451: * no mapping should be needed and the forms should send directly the correct parameters.
452: */
453: private String getRealParameter(String receivedParameter,
454: String functionName) {
455: String flatParameter = receivedParameter;
456: if (receivedParameter.indexOf("_") != -1) {
457: flatParameter = TextUtils.removeCharacter('_',
458: receivedParameter);
459: }
460: try {
461: FunctionSpec function = _api.getAPISpecification()
462: .getFunction(functionName);
463: Set parametersSet = function.getInputParameters().keySet();
464: if (parametersSet.contains(receivedParameter)) {
465: return receivedParameter;
466: }
467: Iterator itParameters = parametersSet.iterator();
468: while (itParameters.hasNext()) {
469: String nextParameterName = (String) itParameters.next();
470: if (nextParameterName.equalsIgnoreCase(flatParameter)) {
471: return nextParameterName;
472: }
473: }
474: } catch (Exception ex) {
475: Log.log_3705(ex.getMessage());
476: }
477: return receivedParameter;
478: }
479: }
|