/* * Copyright (C) 2000 - 2012 TagServlet Ltd * * This file is part of Open BlueDragon (OpenBD) CFML Server Engine. * * OpenBD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * Free Software Foundation,version 3. * * OpenBD is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenBD. If not, see http://www.gnu.org/licenses/ * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining * it with any of the JARS listed in the README.txt (or a modified version of * (that library), containing parts covered by the terms of that JAR, the * licensors of this Program grant you additional permission to convey the * resulting work. * README.txt @ http://www.openbluedragon.org/license/README.txt * * http://www.openbluedragon.org/ * $Id: $ */ package com.naryx.tagfusion.cfm.application; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import com.naryx.tagfusion.cfm.engine.cfComponentData; import com.naryx.tagfusion.cfm.engine.cfData; import com.naryx.tagfusion.cfm.engine.cfEngine; import com.naryx.tagfusion.cfm.engine.cfSession; import com.naryx.tagfusion.cfm.engine.cfStringData; import com.naryx.tagfusion.cfm.engine.cfcMethodData; import com.naryx.tagfusion.cfm.engine.cfmAbortException; import com.naryx.tagfusion.cfm.engine.cfmRunTimeException; import com.naryx.tagfusion.cfm.engine.variableStore; import com.naryx.tagfusion.cfm.file.cfFile; import com.naryx.tagfusion.util.dummyServletRequest; import com.naryx.tagfusion.util.dummyServletResponse; /** * This class handles the [session] scope. It has been classed out, incase we * need to do anything special with this data that sets it aside from a normal * structure. */ public class cfSessionData extends cfStructExpireData implements java.io.Serializable { static final long serialVersionUID = 1; private static final String BD_ADMIN_APPNAME = "BLUEDRAGONADMIN"; public static final String ON_SESSION_END = "onSessionEnd"; private int defaultElements = 3; private long timeout; transient private String md5Digest = null; transient private String storageid = null; public cfSessionData(String appName) { super(); if ((appName != null) && (appName.toUpperCase().equals(BD_ADMIN_APPNAME))) { isBDAdminStruct = true; } } /** * This constructor is for subclasses that want to override the private * hashdata attribute to use an alternate data store (see the comment labeled * "SUBCLASSES" in cfStructData). */ protected cfSessionData(Map<String, cfData> hashdata) { super(hashdata); } public String getStorageID(){ return storageid; } public void setSessionID(String appName, String CFID, String CFTOKEN) { setData("cfid", new cfStringData(CFID)); setData("cftoken", new cfStringData(CFTOKEN)); setData("urltoken", new cfStringData("CFID=" + CFID + "&CFTOKEN=" + CFTOKEN)); setData("sessionid", new cfStringData(appName.toUpperCase() + "_" + CFID + "_" + CFTOKEN)); storageid = CFID + ":" + CFTOKEN; defaultElements = 4; } public void setSessionID(String jsessionid) { setData("sessionid", new cfStringData(jsessionid)); defaultElements = 1; } /* * This method allows us to determine if this is an empty session; one that * has had no values stored in it. This is performed by looking at the number * of elements it is holding. We use the 'defaultElements' variable to aid in * this since a JSESSION has only 2 elements, where as a CFML session has 3 * elements. */ public boolean isEmpty() { return (size() == defaultElements); } /** * Invoke onSessionEnd() for any cfSessionData instance within the * HttpSession. */ public static void onSessionEnd(HttpSession httpSession) { ServletContext servletContext = httpSession.getServletContext(); boolean containsSessionId = false; boolean containsUrlToken = false; Enumeration<String> attrNames = httpSession.getAttributeNames(); while (attrNames.hasMoreElements()) { String key = attrNames.nextElement(); if (key.equals("sessionid")) { containsSessionId = true; } else if (key.equals("urltoken")) { containsUrlToken = true; } else { Object sessionAttr = httpSession.getAttribute(key); if (sessionAttr instanceof cfSessionData) { Object appAttr = servletContext.getAttribute(key); if (appAttr instanceof cfApplicationData) { ((cfSessionData) sessionAttr).onSessionEnd((cfApplicationData) appAttr); } } } } // check for unnamed cfJ2EESessionData if (containsSessionId && containsUrlToken) { cfSessionData session = new cfJ2EESessionData(httpSession); session.onSessionEnd(new cfJ2EEApplicationData(servletContext)); } } /** * Invoked the onSessionEnd() method of the Application.cfc * * If this method is not available (not provided) then it returns false * * @param appData * @return */ public boolean onSessionEnd(cfApplicationData appData) { String applicationCfcPath = appData.getApplicationCfcPath(); if (applicationCfcPath == null) { return false; } cfSession session = new cfSession(new dummyServletRequest(appData.getWebroot()), new dummyServletResponse(), cfEngine.thisServletContext); cfComponentData applicationCfc = null; try { cfFile applicationFile = session.getRealFile(applicationCfcPath); applicationFile.setComponentName("Application"); applicationCfc = new cfComponentData(session, applicationFile, false); // false = don't allow abstract if ( !applicationCfc.isMethodAvailable(ON_SESSION_END) ) return false; // Set the application/session scope for this one session.setQualifiedData( variableStore.APPLICATION_SCOPE, appData ); session.setQualifiedData( variableStore.SESSION_SCOPE, this ); List<cfStructExpireData> args = new ArrayList<cfStructExpireData>(); args.add(this); // SessionScope args.add(appData); // ApplicationScope cfcMethodData methodData = new cfcMethodData(session, ON_SESSION_END, args); applicationCfc.invokeApplicationFunction(session, methodData); } catch (cfmAbortException ignore) { // do nothing, we're finished anyway (catch here so it's not caught as Throwable below) } catch (cfmRunTimeException e) { try { session.invokeOnError(applicationCfc, e, ON_SESSION_END); } catch (cfmRunTimeException ie) { cfEngine.log("onSessionEnd: " + applicationCfcPath + "; " + ie.getMessage() ); ie.handleException(session); } } catch (Throwable t) { com.nary.Debug.printStackTrace(t); new cfmRunTimeException(session, t).handleException(session); } finally { // Make sure per request connections are closed (bug #3174) session.sessionEnd(); } return true; } public void setTimeOut(long sessionTimeOut) { timeout = sessionTimeOut; } public long getTimeOut(){ return timeout; } public void setMD5(String digest) { md5Digest = digest; } public String getMD5(){ return md5Digest; } }