You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2014/04/25 07:34:06 UTC

[08/51] [partial] BlazeDS Donation from Adobe Systems Inc

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/7a58369c/modules/core/src/flex/messaging/HttpFlexSession.java
----------------------------------------------------------------------
diff --git a/modules/core/src/flex/messaging/HttpFlexSession.java b/modules/core/src/flex/messaging/HttpFlexSession.java
new file mode 100755
index 0000000..f305fb9
--- /dev/null
+++ b/modules/core/src/flex/messaging/HttpFlexSession.java
@@ -0,0 +1,666 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package flex.messaging;
+
+import flex.messaging.log.Log;
+import flex.messaging.log.LogCategories;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * FlexSession implementation for use with HTTP-based channels.
+ *
+ * @author shodgson
+ */
+public class HttpFlexSession extends FlexSession
+    implements HttpSessionBindingListener, HttpSessionListener, HttpSessionAttributeListener, Serializable
+{
+    //--------------------------------------------------------------------------
+    //
+    // Constructor
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * @exclude
+     * Not for public use. This constructor is used to create an instance of this class that
+     * will operate as a javax.servlet.http.HttpSessionListener registered in web.xml.
+     */
+    public HttpFlexSession()
+    {}
+
+    /**
+     * @exclude
+     * Not for public use. Constructs new instances that effectively wrap pre-existing JEE HttpSession instances.
+     */
+    public HttpFlexSession(HttpFlexSessionProvider provider) 
+    {
+        super(provider);
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Constants
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Serializable version uid.
+     */
+    private static final long serialVersionUID = -1260409488935306147L;
+
+    /**
+     * Attribute name that HttpFlexSession is stored under in the HttpSession.
+     */
+    /* package-private */ static final String SESSION_ATTRIBUTE = "__flexSession";
+
+    /**
+     * This attribute is set on the request associated with a Flex Session when
+     * a logout command is being processed.  The reason that this is necessary is
+     * that a single HttpServletRequest may contain more than one Flex command/message.
+     * In this case, every message following a "logout" command should behave as if the
+     * user has logged out.  However, since in getUserPrincipal, we check the request
+     * object if the Session has no principal, if the current request object
+     * has a principal object associated with it (as it does on Tomcat/JBoss),
+     * messages following a "logout" will use this principal.  We thus need to
+     * invalidate the user principal in the request on logout.  Since the field
+     * is read-only we do so using this attribute.
+     */
+    private static final String INVALIDATED_REQUEST = "__flexInvalidatedRequest";
+
+    public static final String SESSION_MAP = "LCDS_HTTP_TO_FLEX_SESSION_MAP";
+
+    /**
+     * Internal flag indicating whether we are a registered listener in web.xml.
+     */
+    /* package-private */ static volatile boolean isHttpSessionListener;
+
+    /**
+     * Flag to indicate whether we've logged a warning if we weren't registered in web.xml and
+     * can't redispatch attribute and binding events to Flex listeners.
+     */
+    /* package-private */ static volatile boolean warnedNoEventRedispatch;
+
+    /**
+     * The log category to send the warning for no event redispatch to.
+     */
+    /* package-private */  static String WARN_LOG_CATEGORY = LogCategories.CONFIGURATION;
+
+    //--------------------------------------------------------------------------
+    //
+    // Variables
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Reference to the HttpSession allows us to invalidate it and use it for attribute management.
+     */
+    /* package-private */ HttpSession httpSession;
+
+    /**
+     * @exclude
+     * Static lock for creating httpSessionToFlexSession map
+     */
+    public static final Object mapLock = new Object();
+
+
+    //--------------------------------------------------------------------------
+    //
+    // Public Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * HttpSessionAttributeListener callback; processes the addition of an attribute to an HttpSession.
+     *
+     * NOTE: Callback is not made against an HttpFlexSession associated with a request
+     * handling thread.
+     * @param event the HttpSessionBindingEvent
+     */
+    public void attributeAdded(HttpSessionBindingEvent event)
+    {
+        if (!event.getName().equals(SESSION_ATTRIBUTE))
+        {
+            // Accessing flexSession via map because it may have already been unbound from httpSession.
+            Map httpSessionToFlexSessionMap = getHttpSessionToFlexSessionMap(event.getSession());
+            HttpFlexSession flexSession = (HttpFlexSession)httpSessionToFlexSessionMap.get(event.getSession().getId());
+            if (flexSession != null)
+            {
+                String name = event.getName();
+                Object value = event.getValue();
+                flexSession.notifyAttributeBound(name, value);
+                flexSession.notifyAttributeAdded(name, value);
+            }
+        }
+    }
+
+    /**
+     * HttpSessionAttributeListener callback; processes the removal of an attribute from an HttpSession.
+     *
+     * NOTE: Callback is not made against an HttpFlexSession associated with a request
+     * handling thread.
+     * @param event the HttpSessionBindingEvent
+     */
+    public void attributeRemoved(HttpSessionBindingEvent event)
+    {
+        if (!event.getName().equals(SESSION_ATTRIBUTE))
+        {
+            // Accessing flexSession via map because it may have already been unbound from httpSession.
+            Map httpSessionToFlexSessionMap = getHttpSessionToFlexSessionMap(event.getSession());
+            HttpFlexSession flexSession = (HttpFlexSession)httpSessionToFlexSessionMap.get(event.getSession().getId());
+            if (flexSession != null)
+            {
+                String name = event.getName();
+                Object value = event.getValue();
+                flexSession.notifyAttributeUnbound(name, value);
+                flexSession.notifyAttributeRemoved(name, value);
+            }
+        }
+    }
+
+    /**
+     * HttpSessionAttributeListener callback; processes the replacement of an attribute in an HttpSession.
+     *
+     * NOTE: Callback is not made against an HttpFlexSession associated with a request
+     * handling thread.
+     * @param event the HttpSessionBindingEvent
+     */
+    public void attributeReplaced(HttpSessionBindingEvent event)
+    {
+        if (!event.getName().equals(SESSION_ATTRIBUTE))
+        {
+            // Accessing flexSession via map because it may have already been unbound from httpSession.
+            Map httpSessionToFlexSessionMap = getHttpSessionToFlexSessionMap(event.getSession());
+            HttpFlexSession flexSession = (HttpFlexSession)httpSessionToFlexSessionMap.get(event.getSession().getId());
+            if (flexSession != null)
+            {
+                String name = event.getName();
+                Object value = event.getValue();
+                Object newValue = flexSession.getAttribute(name);
+                flexSession.notifyAttributeUnbound(name, value);
+                flexSession.notifyAttributeReplaced(name, value);
+                flexSession.notifyAttributeBound(name, newValue);
+            }
+        }
+    }
+
+    /**
+     * Creates or retrieves a FlexSession for the current Http request.
+     * The HttpFlexSession wraps the underlying J2EE HttpSession.
+     * Not intended for public use.
+     *
+     * @param req The Http request.
+     *
+     * @return The HttpFlexSession.
+     * 
+     * @deprecated This method has been deprecated in favor of session providers registered with a <tt>MessageBroker</tt>.
+     * @see flex.messaging.FlexSessionManager
+     * @see flex.messaging.HttpFlexSessionProvider
+     */
+    public static HttpFlexSession getFlexSession(HttpServletRequest req)
+    {
+        HttpFlexSession flexSession;
+        HttpSession httpSession = req.getSession(true);
+
+        if (!isHttpSessionListener && !warnedNoEventRedispatch)
+        {
+            warnedNoEventRedispatch = true;
+            if (Log.isWarn())
+                Log.getLogger(WARN_LOG_CATEGORY).warn("HttpFlexSession has not been registered as a listener in web.xml for this application so no events will be dispatched to FlexSessionAttributeListeners or FlexSessionBindingListeners. To correct this, register flex.messaging.HttpFlexSession as a listener in web.xml.");
+        }
+
+        boolean isNew = false;
+        synchronized (httpSession)
+        {
+            flexSession = (HttpFlexSession)httpSession.getAttribute(HttpFlexSession.SESSION_ATTRIBUTE);
+            if (flexSession == null)
+            {
+                flexSession = new HttpFlexSession();
+                // Correlate this FlexSession to the HttpSession before triggering any listeners.
+                FlexContext.setThreadLocalSession(flexSession);
+                httpSession.setAttribute(SESSION_ATTRIBUTE, flexSession);
+                flexSession.setHttpSession(httpSession);
+                isNew = true;
+            }
+            else
+            {
+                FlexContext.setThreadLocalSession(flexSession);
+                if (flexSession.httpSession == null)
+                {
+                    // httpSession is null if the instance is new or is from
+                    // serialization.
+                    flexSession.setHttpSession(httpSession);
+                    isNew = true;
+                }
+            }
+        }
+
+        if (isNew)
+        {
+            flexSession.notifyCreated();
+
+            if (Log.isDebug())
+                Log.getLogger(FLEX_SESSION_LOG_CATEGORY).debug("FlexSession created with id '" + flexSession.getId() + "' for an Http-based client connection.");
+        }
+
+        return flexSession;
+    }    
+
+    /**
+     * Returns the user principal associated with the session. This will
+     * be null if the user has not authenticated.
+     *
+     * @return The Principal associated with the session.
+     */
+    public Principal getUserPrincipal()
+    {
+        Principal p = super.getUserPrincipal();
+        if (p == null)
+        {
+            HttpServletRequest req = FlexContext.getHttpRequest();
+            if (req != null && req.getAttribute(INVALIDATED_REQUEST) == null)
+                p = req.getUserPrincipal();
+        }
+        return p;
+    }
+
+    /**
+     * Invalidates the session.
+     */
+    public void invalidate()
+    {
+        // If the HttpFlexSession is the current active FlexSession for the thread
+        // we'll invalidate it but we need to recreate a new HttpFlexSession because
+        // the client's HttpSession is still active.
+        boolean recreate = FlexContext.getFlexSession() == this;
+        invalidate(recreate);
+    }
+
+    /**
+     * @exclude
+     * Used by Http endpoints when they receive notification from a client that it has
+     * disconnected its channel.
+     * Supports invalidating the HttpFlexSession and underlying JEE HttpSession without
+     * triggering session recreation.
+     */
+    public void invalidate(boolean recreate)
+    {
+        synchronized (httpSession)
+        {
+            try
+            {
+                // Invalidating the HttpSession will trigger invalidation of the HttpFlexSession
+                // either via the sessionDestroyed() event if registration as an HttpSession listener worked
+                // or via the valueUnbound() event if it didn't.
+                httpSession.invalidate();
+            }
+            catch (IllegalStateException e)
+            {
+                // Make sure any related mapping is removed.
+                try
+                {
+                    Map httpSessionToFlexSessionMap = getHttpSessionToFlexSessionMap(httpSession);
+                    httpSessionToFlexSessionMap.remove(httpSession.getId());
+                }
+                catch (Exception ignore)
+                {
+                    // NOWARN
+                }
+
+                // And invalidate this FlexSession.
+                super.invalidate();
+            }
+        }
+        if (recreate)
+        {
+            HttpServletRequest req = FlexContext.getHttpRequest();
+
+            if (req != null)
+            {
+                // Set an attribute on the request denoting that the userPrincipal in the request
+                // is now invalid.
+                req.setAttribute(INVALIDATED_REQUEST, "true");
+
+                AbstractFlexSessionProvider sessionProvider = getFlexSessionProvider();
+                
+                // BLZ-531: When using spring integration getting a null pointer exception when calling invalidate 
+                // on a FlexSession twice
+                // If originally the HttpFlexSession was created using the deprecated HttpFlexSession.getFlexSession(request) API, 
+                // it does not have an associated AbstractFlexSessionProvider. Invoking invalidate(true) on such a session 
+                // results in the "recreated" FlexSession being NULL. To prevent this from happening, in case session provider 
+                // is NULL, we create the session using the deprecated HttpFlexSession.getFlexSession(request) API.
+                FlexSession session = sessionProvider == null ? 
+                        getFlexSession(req) : ((HttpFlexSessionProvider)sessionProvider).getOrCreateSession(req);
+
+                FlexContext.setThreadLocalObjects(FlexContext.getFlexClient(),
+                        session, FlexContext.getMessageBroker(), req,
+                        FlexContext.getHttpResponse(), FlexContext.getServletConfig());
+            }
+            // else, the session was invalidated outside of a request being processed.
+        }
+    }
+
+    /**
+     * Returns the attribute bound to the specified name in the session, or null
+     * if no attribute is bound under the name.
+     *
+     * @param name The name the target attribute is bound to.
+     * @return The attribute bound to the specified name.
+     */
+    public Object getAttribute(String name)
+    {
+        return httpSession.getAttribute(name);
+    }
+
+    /**
+     * Returns the names of all attributes bound to the session.
+     *
+     * @return The names of all attributes bound to the session.
+     */
+    public Enumeration getAttributeNames()
+    {
+        return httpSession.getAttributeNames();
+    }
+
+    /**
+     * Returns the Id for the session.
+     *
+     * @return The Id for the session.
+     */
+    public String getId()
+    {
+        return httpSession.getId();
+    }
+
+    /**
+     * @exclude
+     * FlexClient invokes this to determine whether the session can be used to push messages
+     * to the client.
+     *
+     * @return true if the FlexSession supports direct push; otherwise false (polling is assumed).
+     */
+    public boolean isPushSupported()
+    {
+        return false;
+    }
+
+    /**
+     * Removes the attribute bound to the specified name in the session.
+     *
+     * @param name The name of the attribute to remove.
+     */
+    public void removeAttribute(String name)
+    {
+        httpSession.removeAttribute(name);
+    }
+
+    /**
+     * Implements HttpSessionListener.
+     * HttpSession created events are handled by setting an internal flag indicating that registration
+     * as an HttpSession listener was successful and we will be notified of session attribute changes and
+     * session destruction.
+     * NOTE: This method is not invoked against an HttpFlexSession associated with a request
+     * handling thread.
+     * @param event the HttpSessionEvent
+     */
+    public void sessionCreated(HttpSessionEvent event)
+    {
+        isHttpSessionListener = true;
+    }
+
+    /**
+     * Implements HttpSessionListener.
+     * When an HttpSession is destroyed, the associated HttpFlexSession is also destroyed.
+     * NOTE: This method is not invoked against an HttpFlexSession associated with a request
+     * handling thread.
+     * @param event the HttpSessionEvent
+     */
+    public void sessionDestroyed(HttpSessionEvent event)
+    {
+        HttpSession session = event.getSession();
+        Map httpSessionToFlexSessionMap = getHttpSessionToFlexSessionMap(session);
+        HttpFlexSession flexSession = (HttpFlexSession)httpSessionToFlexSessionMap.remove(session.getId());
+        if (flexSession != null)
+        {
+            // invalidate the flex session
+            flexSession.superInvalidate();
+
+            // Send notifications to attribute listeners if needed.
+            // This may send extra notifications if attributeRemoved is called first by the server,
+            // but Java servlet 2.4 says session destroy is first, then attributes.
+            // Guard against pre-2.4 containers that dispatch events in an incorrect order, 
+            // meaning skip attribute processing here if the underlying session state is no longer valid.
+            try
+            {
+                for (Enumeration e = session.getAttributeNames(); e.hasMoreElements(); )
+                {
+                    String name = (String) e.nextElement();
+                    if (name.equals(SESSION_ATTRIBUTE))
+                        continue;
+                    Object value = session.getAttribute(name);
+                    if (value != null)
+                    {
+                        flexSession.notifyAttributeUnbound(name, value);
+                        flexSession.notifyAttributeRemoved(name, value);
+                    }
+                }
+            }
+            catch (IllegalStateException ignore)
+            {
+                // NOWARN
+                // Old servlet container that dispatches events out of order.
+            }
+        }
+    }
+
+    /**
+     * Binds an attribute to the session under the specified name.
+     *
+     * @param name The name to bind the attribute under.
+     *
+     * @param value The attribute value.
+     */
+    public void setAttribute(String name, Object value)
+    {
+        httpSession.setAttribute(name, value);
+    }
+
+    /**
+     * Implements HttpSessionBindingListener.
+     * This is a no-op.
+     * NOTE: This method is not invoked against an HttpFlexSession associated with a request
+     * handling thread.
+     * @param event the HttpSessionBindingEvent
+     */
+    public void valueBound(HttpSessionBindingEvent event)
+    {
+        // No-op.
+    }
+
+    /**
+     * Implements HttpSessionBindingListener.
+     * This callback will destroy the HttpFlexSession upon being unbound, only in the
+     * case where we haven't been registered as an HttpSessionListener in web.xml and
+     * can't shut down based on the HttpSession being invalidated.
+     * NOTE: This method is not invoked against an HttpFlexSession associated with a request
+     * handling thread.
+     * @param event the HttpSessionBindingEvent
+     */
+    public void valueUnbound(HttpSessionBindingEvent event)
+    {
+        if (!isHttpSessionListener)
+        {
+            Map httpSessionToFlexSessionMap = getHttpSessionToFlexSessionMap(event.getSession());
+            HttpFlexSession flexSession = (HttpFlexSession)httpSessionToFlexSessionMap.remove(event.getSession().getId());
+            if (flexSession != null)
+                flexSession.superInvalidate();
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Protected Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * We don't need to do anything here other than log out some info about the session that's shutting down.
+     */
+    protected void internalInvalidate()
+    {
+        if (Log.isDebug())
+            Log.getLogger(FLEX_SESSION_LOG_CATEGORY).debug("FlexSession with id '" + getId() + "' for an Http-based client connection has been invalidated.");
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Private Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Associates a HttpSession with the FlexSession.
+     *
+     * @param httpSession The HttpSession to associate with the FlexSession.
+     */
+    /* package-private */ void setHttpSession(HttpSession httpSession)
+    {
+        synchronized (lock)
+        {
+            this.httpSession = httpSession;
+            // Update lookup table for event redispatch.
+            Map httpSessionToFlexSessionMap = getHttpSessionToFlexSessionMap(httpSession);
+            httpSessionToFlexSessionMap.put(httpSession.getId(), this);
+        }
+    }
+
+    /**
+     * @exclude
+     * Invoked by HttpSessionListener or binding listener on HttpSession invalidation to invalidate the wrapping
+     * FlexSession.
+     */
+    private void superInvalidate()
+    {
+        super.invalidate();
+    }
+
+    /**
+     * Implements Serializable; only the Principal needs to be serialized as all
+     * attribute storage is delegated to the associated HttpSession.
+     *
+     * @param stream The stream to read instance state from.
+     */
+    private void writeObject(ObjectOutputStream stream)
+    {
+        try
+        {
+            Principal principal = super.getUserPrincipal();
+            if (principal != null && principal instanceof Serializable)
+                stream.writeObject(principal);
+        }
+        catch (IOException e)
+        {
+            // Principal was Serializable and non-null; if this happens there's nothing we can do.
+            // The user will need to reauthenticate if necessary.
+        }
+        catch (LocalizedException ignore)
+        {
+            // This catch block added for bug 194144.
+            // On BEA WebLogic, writeObject() is sometimes invoked on invalidated session instances
+            // and in this case the checkValid() invocation in super.getUserPrincipal() throws.
+            // Ignore this exception.
+        }
+    }
+
+    /**
+     * Implements Serializable; only the Principal needs to be serialized as all
+     * attribute storage is delegated to the associated HttpSession.
+     *
+     * @param stream The stream to write instance state to.
+     */
+    private void readObject(ObjectInputStream stream)
+    {
+        try
+        {
+            setUserPrincipal((Principal)stream.readObject());
+        }
+        catch (Exception e)
+        {
+            // Principal was not serialized or failed to serialize; ignore.
+            // The user will need to reauthenticate if necessary.
+        }
+    }
+
+    /**
+     * Map of HttpSession Ids to FlexSessions. We need this when registered as a listener
+     * in web.xml in order to trigger the destruction of a FlexSession when its associated HttpSession
+     * is invalidated/destroyed. The Servlet spec prior to version 2.4 defined the session destruction event
+     * to be dispatched after attributes are unbound from the session so when we receive notification that
+     * an HttpSession is destroyed there's no way to get to the associated FlexSession attribute because it
+     * has already been unbound... Additionally, we need it to handle attribute removal events that happen
+     * during HttpSession destruction because the FlexSession can be unbound from the session before the
+     * other attributes we receive notification for.
+     *
+     * Because of this, it's simplest to just maintain this lookup table and use it for all HttpSession
+     * related event handling.
+     *
+     * The table is maintained on the servlet context instead of statically in order to prevent collisions
+     * across web-apps.
+     */
+    private Map getHttpSessionToFlexSessionMap(HttpSession session)
+    {
+        try
+        {
+            ServletContext context = session.getServletContext();
+            Map map = (Map)context.getAttribute(SESSION_MAP);
+
+            if(map==null){
+                // map should never be null here as it is created during MessageBrokerServlet start-up
+                if (Log.isError())
+                    Log.getLogger(FLEX_SESSION_LOG_CATEGORY).error("HttpSession to FlexSession map not created in message broker for "
+                            + session.getId());
+                MessageException me = new MessageException();
+                me.setMessage(10032, new Object[] {session.getId()});
+                throw me;
+            }
+            return map;
+        }
+        catch(Exception e)
+        {
+            if (Log.isDebug())
+                Log.getLogger(FLEX_SESSION_LOG_CATEGORY).debug("Unable to get HttpSession to FlexSession map for "
+                        + session.getId() + " " + e.toString());
+            return new ConcurrentHashMap();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/7a58369c/modules/core/src/flex/messaging/HttpFlexSessionProvider.java
----------------------------------------------------------------------
diff --git a/modules/core/src/flex/messaging/HttpFlexSessionProvider.java b/modules/core/src/flex/messaging/HttpFlexSessionProvider.java
new file mode 100755
index 0000000..9a077b9
--- /dev/null
+++ b/modules/core/src/flex/messaging/HttpFlexSessionProvider.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package flex.messaging;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import flex.messaging.log.Log;
+
+/**
+ * Provider implementation for <code>HttpFlexSession</code>s.
+ * Not intended for public use.
+ */
+public class HttpFlexSessionProvider extends AbstractFlexSessionProvider
+{
+    //--------------------------------------------------------------------------
+    //
+    // Public Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Factory method to get an existing <tt>HttpFlexSession</tt> for the current request,
+     * or create and return a new <code>HttpFlexSession</code> if necessary.
+     * The <code>HttpFlexSession</code> wraps the underlying J2EE <code>HttpSession</code>.
+     * Not intended for public use.
+     * 
+     * @param request The current <tt>HttpServletRequest</tt>.
+     * @return A <tt>HttpFlexSession</tt>.
+     */
+    public HttpFlexSession getOrCreateSession(HttpServletRequest request)
+    {
+        HttpFlexSession flexSession;
+        HttpSession httpSession = request.getSession(true);
+
+        if (!HttpFlexSession.isHttpSessionListener && !HttpFlexSession.warnedNoEventRedispatch)
+        {
+            HttpFlexSession.warnedNoEventRedispatch = true;
+            if (Log.isWarn())
+                Log.getLogger(HttpFlexSession.WARN_LOG_CATEGORY).warn("HttpFlexSession has not been registered as a listener in web.xml for this application so no events will be dispatched to FlexSessionAttributeListeners or FlexSessionBindingListeners. To correct this, register flex.messaging.HttpFlexSession as a listener in web.xml.");
+        }
+
+        boolean isNew = false;
+        synchronized (httpSession)
+        {
+            flexSession = (HttpFlexSession)httpSession.getAttribute(HttpFlexSession.SESSION_ATTRIBUTE);
+            if (flexSession == null)
+            {
+                flexSession = new HttpFlexSession(this);
+                // Correlate this FlexSession to the HttpSession before triggering any listeners.
+                FlexContext.setThreadLocalSession(flexSession);
+                httpSession.setAttribute(HttpFlexSession.SESSION_ATTRIBUTE, flexSession);
+                flexSession.setHttpSession(httpSession);
+                isNew = true;
+            }
+            else
+            {
+                FlexContext.setThreadLocalSession(flexSession);
+                if (flexSession.httpSession == null)
+                {
+                    // httpSession is null if the instance is new or is from
+                    // serialization.
+                    flexSession.setHttpSession(httpSession);
+                    isNew = true;
+                }
+            }
+        }
+
+        if (isNew)
+        {
+            getFlexSessionManager().registerFlexSession(flexSession);
+            flexSession.notifyCreated();
+
+            if (Log.isDebug())
+                Log.getLogger(HttpFlexSession.FLEX_SESSION_LOG_CATEGORY).debug("FlexSession created with id '" + flexSession.getId() + "' for an Http-based client connection.");
+        }
+
+        return flexSession;
+    }
+    }