You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cd...@apache.org on 2015/12/20 14:13:52 UTC
[12/51] [partial] flex-blazeds git commit: Removed legacy directories
and made the content of the modules directory the new root - Please use the
maven build for now as the Ant build will no longer work untill it is
adjusted to the new directory structur
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexSession.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/FlexSession.java b/core/src/flex/messaging/FlexSession.java
new file mode 100644
index 0000000..4f34f8a
--- /dev/null
+++ b/core/src/flex/messaging/FlexSession.java
@@ -0,0 +1,1064 @@
+/*
+ * 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.client.FlexClient;
+import flex.messaging.client.FlexClientListener;
+import flex.messaging.log.LogCategories;
+import flex.messaging.messages.Message;
+import flex.messaging.util.TimeoutAbstractObject;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * The base for FlexSession implementations.
+ */
+public abstract class FlexSession extends TimeoutAbstractObject implements FlexClientListener, MessageClientListener
+{
+ //--------------------------------------------------------------------------
+ //
+ // Public Static Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Log category for FlexSession related messages.
+ */
+ public static final String FLEX_SESSION_LOG_CATEGORY = LogCategories.ENDPOINT_FLEXSESSION;
+
+ /**
+ *
+ */
+ public static final int MAX_CONNECTIONS_PER_SESSION_UNLIMITED = -1;
+
+ //--------------------------------------------------------------------------
+ //
+ // Private Static Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The set of session created listeners to notify upon a new session creation.
+ */
+ private static final CopyOnWriteArrayList<FlexSessionListener> createdListeners = new CopyOnWriteArrayList<FlexSessionListener>();
+
+ /**
+ * Error string constants.
+ */
+ private static final int FLEX_SESSION_INVALIDATED = 10019;
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ *
+ * @deprecated Post 2.6.1 releases require use of the constructor that takes an <tt>AbstractFlexSessionProvider</tt> argument.
+ */
+ public FlexSession()
+ {
+ this(null);
+ }
+
+ /**
+ *
+ * Constructs a new FlexSession instance.
+ *
+ * @param sessionProvider The provider that instantiated this instance.
+ */
+ public FlexSession(AbstractFlexSessionProvider sessionProvider)
+ {
+ this.sessionProvider = sessionProvider;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Static Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Adds a session created listener that will be notified when new sessions
+ * are created.
+ *
+ * @see flex.messaging.FlexSessionListener
+ *
+ * @param listener The listener to add.
+ */
+ public static void addSessionCreatedListener(FlexSessionListener listener)
+ {
+ if (listener != null)
+ createdListeners.addIfAbsent(listener);
+ }
+
+ /**
+ * Removes a session created listener.
+ *
+ * @see flex.messaging.FlexSessionListener
+ *
+ * @param listener The listener to remove.
+ */
+ public static void removeSessionCreatedListener(FlexSessionListener listener)
+ {
+ if (listener != null)
+ createdListeners.remove(listener);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Flag used to break cycles during invalidation.
+ */
+ protected boolean invalidating;
+
+ /**
+ * Instance level lock to sync for state changes.
+ */
+ protected final Object lock = new Object();
+
+ /**
+ * Flag indicated whether the session has been invalidated/destroyed.
+ */
+ protected boolean valid = true;
+
+ /**
+ * The attributes associated with this session.
+ */
+ private Map<String, Object> attributes;
+
+ /**
+ * Registered attribute listeners for the session.
+ */
+ private volatile CopyOnWriteArrayList<FlexSessionAttributeListener> attributeListeners;
+
+ /**
+ * Flag indicating whether creation notification has been completed.
+ */
+ private boolean creationNotified;
+
+ /**
+ * The set of session destroy listeners to notify when the session is destroyed.
+ */
+ private volatile CopyOnWriteArrayList<FlexSessionListener> destroyedListeners;
+
+ /**
+ * The associated FlexClients.
+ */
+ private final CopyOnWriteArrayList<FlexClient> flexClients = new CopyOnWriteArrayList<FlexClient>();
+
+ /**
+ * List of associated MessageClients created while this session was active (thread local).
+ */
+ private volatile CopyOnWriteArrayList<MessageClient> messageClients;
+
+ /**
+ * Storage for remote credentials associated with the session; used by the HTTPProxyService
+ * when requests are made to a secured remote endpoint.
+ */
+ private volatile Map remoteCredentials;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // asyncPollMap
+ //----------------------------------
+
+ /**
+ *
+ * Used internally to manage async long-polls; not for public use.
+ *
+ * A map of endpoint to async poll objects that keeps track of what
+ * client is parked on a long-poll with what endpoint.
+ * We only want an endpoint to have a single connection to a client.
+ * Normally, the server leaves an async long-poll in place until
+ * data arrives to push to the client or a timeout is reached.
+ * However, if two or more browser tabs/windows are sharing the same server session and are both attempting
+ * async long-polling, we alternate their parked requests to avoid locking up the browser process by holding too many
+ * Http connections open at once.
+ * This also aids with closing out 'orphaned' long polls following a browser page reload.
+ * Generically typed as <code>Object</code>; using this reference is left up to async poll
+ * implementation code.
+ */
+ public volatile HashMap<String, FlexClient.AsyncPollWithTimeout> asyncPollMap;
+
+ //----------------------------------
+ // flexSessionProvider
+ //----------------------------------
+
+ private final AbstractFlexSessionProvider sessionProvider;
+
+ /**
+ *
+ * Returns the session provider that created this instance.
+ *
+ * @return The session provider that created this instance.
+ */
+ public AbstractFlexSessionProvider getFlexSessionProvider()
+ {
+ return sessionProvider;
+ }
+
+ //----------------------------------
+ // principal
+ //----------------------------------
+
+ /**
+ * The principal associated with the session.
+ */
+ private Principal userPrincipal;
+
+ /**
+ * This method should be called on FlexContext and not on this class. Keeping
+ * this method for backwards compatibility. This method will produce
+ * correct results when perClientAuthentication is false. However, it will
+ * not return correct results when perClientAuthentication is true.
+ *
+ * Returns the principal associated with the session. If the client has not
+ * authenticated the principal will be null.
+ *
+ * @return The principal associated with the session.
+ */
+ public Principal getUserPrincipal()
+ {
+ synchronized (lock)
+ {
+ checkValid();
+ return userPrincipal;
+ }
+ }
+
+ /**
+ * This method should be called on FlexContext and not on this class. Keeping
+ * this method for backwards compatibility. Calling this when perClientAuthentication
+ * is true will not correctly set the UserPrincipal.
+ *
+ * @param userPrincipal The principal to associate with the session.
+ */
+ public void setUserPrincipal(Principal userPrincipal)
+ {
+ synchronized (lock)
+ {
+ checkValid();
+ this.userPrincipal = userPrincipal;
+ }
+ }
+
+ //----------------------------------
+ // canStream
+ //----------------------------------
+
+ /**
+ *
+ * Used internally by streaming endpoints to enforce session level streaming
+ * connection limits; not for public use.
+ * This flag is volatile to allow for consistent reads across thread without
+ * needing to pay the cost for a synchronized lock for each read.
+ */
+ public volatile boolean canStream = true;
+
+ //----------------------------------
+ // maxConnectionsPerSession
+ //----------------------------------
+
+ /**
+ *
+ * Used internally by streaming and long polling endpoints to enforce session
+ * level streaming connection limits; not for public use. Default value is -1
+ * (limitless)
+ */
+ public int maxConnectionsPerSession = MAX_CONNECTIONS_PER_SESSION_UNLIMITED;
+
+ //----------------------------------
+ // streamingClientsCount
+ //----------------------------------
+
+ /**
+ *
+ * Used internally by streaming and long polling endpoints to enforce
+ * session level streaming connection limits; not for public use.
+ *
+ * Some browsers put limits on the number of connections per session. For
+ * example, Firefox has network.http.max-connections-per-server=8 limit which
+ * limits the number of streaming connections per session to 7. Similarly,
+ * IE has a limit of 2 per session.
+ *
+ * This variable is used by streaming and long polling endpoint to keep
+ * track of open connections per session and disallow them when needed.
+ *
+ */
+ public int streamingConnectionsCount;
+
+ //----------------------------------
+ // useSmallMessages
+ //----------------------------------
+
+ /**
+ *
+ */
+ private boolean useSmallMessages;
+
+ /**
+ *
+ * Determines whether the server can attempt to send small messages
+ * for those messages that have a small form. This setting can be overridden
+ * by an endpoint's enableSmallMessages switch which controls whether
+ * small messages should be sent, even if they are supported.
+ *
+ * The default is false.
+ *
+ * @return true if the server can attempt to send small messages.
+ */
+ public boolean useSmallMessages()
+ {
+ return useSmallMessages;
+ }
+
+ /**
+ * @param value true if the server can attempt to send small messages.
+ */
+ public void setUseSmallMessages(boolean value)
+ {
+ useSmallMessages = value;
+ }
+
+ //----------------------------------
+ // waitMonitor
+ //----------------------------------
+
+ /**
+ *
+ * Used internally to manage wait()-based long-polls; not for public use.
+ *
+ * This is the monitor that a request handling thread associated with this
+ * FlexSession is waiting on. Normally, the waiting request handling thread will wait until
+ * a new message arrives that can be returned in a poll response or its wait interval times out.
+ * This also aids with closing out 'orphaned' long polls following a browser page reload.
+ */
+ public volatile HashMap<String, FlexClient.EndpointQueue> waitMonitor;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Adds a session attribute listener that will be notified when an
+ * attribute is added, removed or changed.
+ *
+ * @param listener The listener to add.
+ */
+ public void addSessionAttributeListener(FlexSessionAttributeListener listener)
+ {
+ if (listener != null)
+ {
+ checkValid();
+
+ if (attributeListeners == null)
+ {
+ synchronized (lock)
+ {
+ if (attributeListeners == null)
+ attributeListeners = new CopyOnWriteArrayList<FlexSessionAttributeListener>();
+ }
+ }
+
+ attributeListeners.addIfAbsent(listener);
+ }
+ }
+
+ /**
+ * Adds a session destroy listener that will be notified when the session
+ * is destroyed. Session destroy listeners are notified after all attributes
+ * have been unbound from the session and any FlexSessionBindingListeners
+ * and FlexSessionAttributeListeners have been notified.
+ *
+ * @see flex.messaging.FlexSessionListener
+ *
+ * @param listener The listener to add.
+ */
+ public void addSessionDestroyedListener(FlexSessionListener listener)
+ {
+ if (listener != null)
+ {
+ checkValid();
+
+ if (destroyedListeners == null)
+ {
+ synchronized (lock)
+ {
+ if (destroyedListeners == null)
+ destroyedListeners = new CopyOnWriteArrayList<FlexSessionListener>();
+ }
+ }
+
+ destroyedListeners.addIfAbsent(listener);
+ }
+ }
+
+ /**
+ * 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)
+ {
+ synchronized (lock)
+ {
+ checkValid();
+
+ return (attributes == null) ? null : attributes.get(name);
+ }
+ }
+
+ /**
+ * Returns a snapshot of the names of all attributes bound to the session.
+ *
+ * @return A snapshot of the names of all attributes bound to the session.
+ */
+ public Enumeration<String> getAttributeNames()
+ {
+ synchronized (lock)
+ {
+ checkValid();
+
+ if (attributes == null)
+ return Collections.enumeration(Collections.<String>emptyList());
+
+ // Return a copy so we do not run into concurrent modification problems if
+ // someone adds to the attributes while iterating through the returned enumeration.
+ return Collections.enumeration(new ArrayList<String>(attributes.keySet()));
+ }
+ }
+
+ /**
+ *
+ * Implements MessageClientListener.
+ * Handling created events is a no-op.
+ *
+ * @param messageClient The new MessageClient.
+ */
+ public void messageClientCreated(MessageClient messageClient) {}
+
+ /**
+ *
+ * Implements MessageClientListener.
+ * Notification that an associated MessageClient was destroyed.
+ *
+ * @param messageClient The MessageClient that was destroyed.
+ */
+ public void messageClientDestroyed(MessageClient messageClient)
+ {
+ unregisterMessageClient(messageClient);
+ }
+
+ /**
+ *
+ * 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 abstract boolean isPushSupported();
+
+ /**
+ *
+ * FlexClient invokes this to push a message to a remote client.
+ *
+ * @param message The message to push.
+ */
+ public void push(Message message)
+ {
+ throw new UnsupportedOperationException("Push not supported.");
+ }
+
+ /**
+ * 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)
+ {
+ Object value; // Used for event dispatch after the attribute is removed.
+
+ synchronized (lock)
+ {
+ checkValid(); // Re-enters lock but should be fast because we're already holding it.
+
+ value = (attributes != null) ? attributes.remove(name) : null;
+ }
+
+ // If no value was bound under this name it's a no-op.
+ if (value == null)
+ return;
+
+ notifyAttributeUnbound(name, value);
+ notifyAttributeRemoved(name, value);
+ }
+
+ /**
+ * Removes a session attribute listener.
+ *
+ * @param listener The listener to remove.
+ */
+ public void removeSessionAttributeListener(FlexSessionAttributeListener listener)
+ {
+ // No need to check validity; removing a listener is always ok.
+ if (listener != null && attributeListeners != null)
+ attributeListeners.remove(listener);
+ }
+
+ /**
+ * Removes a session destroy listener.
+ *
+ * @see flex.messaging.FlexSessionListener
+ *
+ * @param listener The listener to remove.
+ */
+ public void removeSessionDestroyedListener(FlexSessionListener listener)
+ {
+ // No need to check validity; removing a listener is always ok.
+ if (listener != null && destroyedListeners != null)
+ destroyedListeners.remove(listener);
+ }
+
+ /**
+ * Binds an attribute value to the session under the specified name.
+ *
+ * @param name The name to bind the attribute under.
+ * @param value The value of the attribute.
+ */
+ public void setAttribute(String name, Object value)
+ {
+ // Null value is the same as removeAttribute().
+ if (value == null)
+ {
+ removeAttribute(name);
+ return;
+ }
+
+ Object oldValue; // Used to determine which events to dispatch after the set is performed.
+
+ // Only synchronize for the attribute mutation; event dispatch doesn't require it.
+ synchronized (lock)
+ {
+ checkValid(); // Re-enters lock but should be fast because we're already holding it.
+
+ if (attributes == null)
+ attributes = new HashMap<String, Object>();
+
+ oldValue = attributes.put(name, value);
+ }
+
+ if (oldValue == null)
+ {
+ notifyAttributeBound(name, value);
+ notifyAttributeAdded(name, value);
+ }
+ else
+ {
+ notifyAttributeUnbound(name, oldValue);
+ notifyAttributeReplaced(name, oldValue);
+ notifyAttributeBound(name, value);
+ }
+ }
+
+ /**
+ * Stores remote credentials in the session for proxied calls to remote systems.
+ *
+ * @param credentials The remote credentials.
+ */
+ public void putRemoteCredentials(FlexRemoteCredentials credentials)
+ {
+ if (credentials != null)
+ {
+ // We only need to hold the lock to lazy-init the remoteCredentials variable.
+ if (remoteCredentials == null)
+ {
+ synchronized (lock)
+ {
+ // Init size to 4 because that's the number of shipping service types
+ // (messaging, remoting, proxy, data management).
+ if (remoteCredentials == null)
+ remoteCredentials = new HashMap(4);
+ }
+ }
+ synchronized (remoteCredentials)
+ {
+ Map serviceMap = (Map)remoteCredentials.get(credentials.getService());
+ if (serviceMap == null)
+ {
+ // Init size to half the normal number of buckets; most services won't have a large
+ // number of destinations with remote credentials.
+ serviceMap = new HashMap(7);
+ remoteCredentials.put(credentials.getService(), serviceMap);
+ }
+ serviceMap.put(credentials.getDestination(), credentials);
+ }
+ }
+ }
+
+ /**
+ * Returns the remote credentials stored in the session for the specified service destination.
+ *
+ * @param serviceId The service id.
+ * @param destinationId The destination id.
+ * @return The stored remote credentials for the specified service destination.
+ */
+ public FlexRemoteCredentials getRemoteCredentials(String serviceId, String destinationId)
+ {
+ if (serviceId != null && destinationId != null)
+ {
+ if (remoteCredentials == null)
+ return null;
+ synchronized (remoteCredentials)
+ {
+ Map serviceMap = (Map)remoteCredentials.get(serviceId);
+ return (serviceMap != null) ? (FlexRemoteCredentials)serviceMap.get(destinationId) : null;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Clears any stored remote credentials from the session for the specified service destination.
+ *
+ * @param serviceId The service Id.
+ * @param destinationId The destination Id.
+ */
+ public void clearRemoteCredentials(String serviceId, String destinationId)
+ {
+ if (serviceId != null && destinationId != null)
+ {
+ if (remoteCredentials == null)
+ return;
+ synchronized (remoteCredentials)
+ {
+ Map serviceMap = (Map)remoteCredentials.get(serviceId);
+ if (serviceMap != null)
+ {
+ serviceMap.put(destinationId, null);
+ }
+ }
+ }
+ }
+
+ /**
+ * Invalidates the FlexSession.
+ */
+ public void invalidate()
+ {
+ synchronized (lock)
+ {
+ if (!valid || invalidating)
+ return; // Already shutting down.
+
+ invalidating = true; // This thread gets to shut the FlexSession down.
+ cancelTimeout();
+ if (sessionProvider != null)
+ sessionProvider.removeFlexSession(this);
+ }
+
+ // Unregister all FlexClients.
+ if (!flexClients.isEmpty())
+ {
+ for (FlexClient flexClient : flexClients)
+ unregisterFlexClient(flexClient);
+ }
+
+ // Invalidate associated MessageClient subscriptions.
+ if (messageClients != null && !messageClients.isEmpty())
+ {
+ for (Iterator<MessageClient> iter = messageClients.iterator(); iter.hasNext();)
+ {
+ MessageClient messageClient = iter.next();
+ messageClient.removeMessageClientDestroyedListener(this);
+ messageClient.invalidate();
+ }
+ messageClients.clear();
+ }
+
+
+ // Notify destroy listeners that we're shutting the FlexSession down.
+ if (destroyedListeners != null && !destroyedListeners.isEmpty())
+ {
+ for (FlexSessionListener destroyListener : destroyedListeners)
+ {
+ destroyListener.sessionDestroyed(this);
+ }
+ destroyedListeners.clear();
+ }
+
+ // Unbind all attributes.
+ if (attributes != null && !attributes.isEmpty())
+ {
+ Set<String> keySet = attributes.keySet();
+ String[] keys = keySet.toArray(new String[keySet.size()]);
+ for (String key : keys)
+ removeAttribute(key);
+
+ attributes = null;
+ }
+
+ internalInvalidate();
+
+ synchronized (lock)
+ {
+ valid = false;
+ invalidating = false;
+ }
+
+ // Notify any waiting threads.
+ if (waitMonitor != null)
+ {
+ for (FlexClient.EndpointQueue endpointQueue : waitMonitor.values())
+ {
+ synchronized (endpointQueue)
+ {
+ endpointQueue.notifyAll();
+ }
+ }
+ }
+ }
+
+ /**
+ * Hook for subclasses to perform any custom shutdown.
+ * Invoked after the FlexSession has performed generic shutdown but right before the session's valid
+ * property flips to false.
+ */
+ protected void internalInvalidate() {}
+
+ /**
+ * Returns a snapshot of the FlexClients associated with the FlexSession
+ * when this method is invoked.
+ * This list is not guaranteed to remain consistent with the actual list
+ * of active FlexClients associated with the FlexSession over time.
+ *
+ * @return A snapshot of the current list of FlexSessions associated with the FlexClient.
+ */
+ public List<FlexClient> getFlexClients()
+ {
+ List<FlexClient> currentFlexClients = null;
+ synchronized (lock)
+ {
+ checkValid(); // Re-enters lock but should be fast because we're already holding it.
+
+ currentFlexClients = new ArrayList<FlexClient>(flexClients); // Make a copy of the current list to return.
+ }
+ return currentFlexClients;
+ }
+
+ /**
+ * Returns a snapshot of the MessageClients (subscriptions) associated with the FlexSession
+ * when this method is invoked.
+ * This list is not guaranteed to remain consistent with the actual list
+ * of active MessageClients associated with the FlexSession over time.
+ *
+ * @return A snapshot of the current list of MessageClients associated with the FlexSession.
+ */
+ public List<MessageClient> getMessageClients()
+ {
+ List<MessageClient> currentMessageClients = null;
+ synchronized (lock)
+ {
+ checkValid(); // Re-enters lock but should be fast because we're already holding it.
+
+ currentMessageClients = (messageClients != null) ? new ArrayList<MessageClient>(messageClients) // Make a copy of the current list to return.
+ : new ArrayList<MessageClient>(); // Return an empty list.
+ }
+ return currentMessageClients;
+ }
+
+ /**
+ * Returns the Id for the session.
+ *
+ * @return The Id for the session.
+ */
+ public abstract String getId();
+
+ /**
+ * Returns whether the current user is in the specified role.
+ *
+ * @param role The role to test.
+ * @return true if the user is in the role; otherwise false.
+ */
+ public boolean isUserInRole(String role)
+ {
+ ArrayList list = new ArrayList();
+ list.add(role);
+ return FlexContext.getMessageBroker().getLoginManager().checkRoles(userPrincipal, list);
+ }
+
+ /**
+ * Returns whether the session is valid.
+ *
+ * @return true if the session is valid; otherwise false.
+ */
+ public boolean isValid()
+ {
+ synchronized (lock)
+ {
+ return valid;
+ }
+ }
+
+ /**
+ *
+ * Implements FlexClientListener interface.
+ * Notification that a FlexClient was created.
+ * This is a no-op because the FlexSession is never added as a static FlexClient created listener
+ * but this method is required by the interface. We only listen for the destroyed event from
+ * associated FlexClients.
+ *
+ * @param flexClient The FlexClient that was created.
+ */
+ public void clientCreated(FlexClient flexClient) {}
+
+ /**
+ *
+ * Implements FlexClientListener interface.
+ * Notification that an associated FlexClient was destroyed.
+ *
+ * @param flexClient The FlexClient that was destroyed.
+ */
+ public void clientDestroyed(FlexClient flexClient)
+ {
+ unregisterFlexClient(flexClient);
+ }
+
+ /**
+ *
+ * Used internally to associate a FlexClient with the FlexSession.
+ *
+ * @param flexClient The FlexClient to assocaite with the session.
+ */
+ public void registerFlexClient(FlexClient flexClient)
+ {
+ if (flexClients.addIfAbsent(flexClient))
+ {
+ flexClient.addClientDestroyedListener(this);
+ flexClient.registerFlexSession(this);
+ }
+ }
+
+ /**
+ *
+ * Used internally to disassociate a FlexClient from the FlexSession.
+ *
+ * @param flexClient The FlexClient to disassociate from the session.
+ */
+ public void unregisterFlexClient(FlexClient flexClient)
+ {
+ if (flexClients.remove(flexClient))
+ {
+ flexClient.removeClientDestroyedListener(this);
+ flexClient.unregisterFlexSession(this);
+ }
+ }
+
+ /**
+ *
+ * Used internally to associate a MessagClient (subscription) with the FlexSession.
+ *
+ * @param messageClient The MessageClient to associate with the session.
+ */
+ public void registerMessageClient(MessageClient messageClient)
+ {
+ if (messageClients == null)
+ {
+ synchronized (lock)
+ {
+ if (messageClients == null)
+ messageClients = new CopyOnWriteArrayList<MessageClient>();
+ }
+ }
+
+ if (messageClients.addIfAbsent(messageClient))
+ messageClient.addMessageClientDestroyedListener(this);
+ }
+
+ /**
+ *
+ * Used internally to disassociate a MessageClient (subscription) from a FlexSession.
+ *
+ * @param messageClient The MessageClient to disassociate from the session.
+ */
+ public void unregisterMessageClient(MessageClient messageClient)
+ {
+ if (messageClients != null && messageClients.remove(messageClient))
+ messageClient.removeMessageClientDestroyedListener(this);
+ }
+
+ /**
+ * Default implementation invokes <code>invalidate()</code> upon timeout.
+ *
+ * @see flex.messaging.util.TimeoutCapable#timeout()
+ */
+ public void timeout()
+ {
+ invalidate();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Protected Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Ensures that the session has not been invalidated.
+ */
+ protected void checkValid()
+ {
+ synchronized (lock)
+ {
+ if (!valid)
+ {
+ LocalizedException e = new LocalizedException();
+ e.setMessage(FLEX_SESSION_INVALIDATED);
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Notify attribute listeners that an attribute has been added.
+ *
+ * @param name The name of the attribute.
+ * @param value The new value of the attribute.
+ */
+ protected void notifyAttributeAdded(String name, Object value)
+ {
+ if (attributeListeners != null && !attributeListeners.isEmpty())
+ {
+ FlexSessionBindingEvent event = new FlexSessionBindingEvent(this, name, value);
+ // CopyOnWriteArrayList is iteration-safe from ConcurrentModificationExceptions.
+ for (FlexSessionAttributeListener attribListener : attributeListeners)
+ attribListener.attributeAdded(event);
+ }
+ }
+
+ /**
+ * Notify binding listener that it has been bound to the session.
+ *
+ * @param name The attribute name.
+ * @param value The attribute that has been bound.
+ */
+ protected void notifyAttributeBound(String name, Object value)
+ {
+ if ((value != null) && (value instanceof FlexSessionBindingListener))
+ {
+ FlexSessionBindingEvent bindingEvent = new FlexSessionBindingEvent(this, name);
+ ((FlexSessionBindingListener)value).valueBound(bindingEvent);
+ }
+ }
+
+ /**
+ * Notify attribute listeners that an attribute has been removed.
+ *
+ * @param name The name of the attribute.
+ * @param value The previous value of the attribute.
+ */
+ protected void notifyAttributeRemoved(String name, Object value)
+ {
+ if (attributeListeners != null && !attributeListeners.isEmpty())
+ {
+ FlexSessionBindingEvent event = new FlexSessionBindingEvent(this, name, value);
+ // CopyOnWriteArrayList is iteration-safe from ConcurrentModificationExceptions.
+ for (FlexSessionAttributeListener attribListener : attributeListeners)
+ attribListener.attributeRemoved(event);
+ }
+ }
+
+ /**
+ * Notify attribute listeners that an attribute has been replaced.
+ *
+ * @param name The name of the attribute.
+ * @param value The previous value of the attribute.
+ */
+ protected void notifyAttributeReplaced(String name, Object value)
+ {
+ if (attributeListeners != null && !attributeListeners.isEmpty())
+ {
+ FlexSessionBindingEvent event = new FlexSessionBindingEvent(this, name, value);
+ // CopyOnWriteArrayList is iteration-safe from ConcurrentModificationExceptions.
+ for (FlexSessionAttributeListener attribListener : attributeListeners)
+ attribListener.attributeReplaced(event);
+ }
+ }
+
+ /**
+ * Notify binding listener that it has been unbound from the session.
+ *
+ * @param name The attribute name.
+ * @param value The attribute that has been unbound.
+ */
+ protected void notifyAttributeUnbound(String name, Object value)
+ {
+ if ((value != null) && (value instanceof FlexSessionBindingListener))
+ {
+ FlexSessionBindingEvent bindingEvent = new FlexSessionBindingEvent(this, name);
+ ((FlexSessionBindingListener)value).valueUnbound(bindingEvent);
+ }
+ }
+
+ /**
+ * Invoked by subclass upon session creation to notify all registered
+ * session create listeners of the event.
+ * This method must be invoked in the subclass constructor.
+ */
+ protected void notifyCreated()
+ {
+ // This guard is here only to prevent duplicate notifications if there's a coding error
+ // in the subclass. Not likely..
+ synchronized (lock)
+ {
+ if (creationNotified)
+ return;
+
+ creationNotified = true;
+ }
+
+ if (!createdListeners.isEmpty())
+ {
+ // CopyOnWriteArrayList is iteration-safe from ConcurrentModificationExceptions.
+ for (Iterator<FlexSessionListener> iter = createdListeners.iterator(); iter.hasNext();)
+ iter.next().sessionCreated(this);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexSessionAttributeListener.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/FlexSessionAttributeListener.java b/core/src/flex/messaging/FlexSessionAttributeListener.java
new file mode 100644
index 0000000..feba243
--- /dev/null
+++ b/core/src/flex/messaging/FlexSessionAttributeListener.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+/**
+ * Interface for Flex session attribute listeners.
+ */
+public interface FlexSessionAttributeListener
+{
+ /**
+ * Callback invoked after an attribute is added to the session.
+ *
+ * @param event The event containing the associated session and attribute
+ * information.
+ */
+ void attributeAdded(FlexSessionBindingEvent event);
+
+ /**
+ * Callback invoked after an attribute is removed from the session.
+ *
+ * @param event The event containing the associated session and attribute
+ * information.
+ */
+ void attributeRemoved(FlexSessionBindingEvent event);
+
+ /**
+ * Callback invoked after an attribute has been replaced with a new value.
+ *
+ * @param event The event containing the associated session and attribute
+ * information.
+ */
+ void attributeReplaced(FlexSessionBindingEvent event);
+}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexSessionBindingEvent.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/FlexSessionBindingEvent.java b/core/src/flex/messaging/FlexSessionBindingEvent.java
new file mode 100644
index 0000000..512c7a9
--- /dev/null
+++ b/core/src/flex/messaging/FlexSessionBindingEvent.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+/**
+ * Event used to notify FlexSessionAttributeListeners of changes to session
+ * attributes.
+ */
+public class FlexSessionBindingEvent
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructs an event for an attribute that is bound or unbound from a session.
+ *
+ * @param session The associated session.
+ * @param name The attribute name.
+ */
+ public FlexSessionBindingEvent(FlexSession session, String name)
+ {
+ this.session = session;
+ this.name = name;
+ }
+
+ /**
+ * Constructs an event for an attribute that is added to a session or
+ * replaced by a new value.
+ *
+ * @param session The associated session.
+ * @param name The attribute name.
+ * @param value The attribute value.
+ */
+ public FlexSessionBindingEvent(FlexSession session, String name, Object value)
+ {
+ this.session = session;
+ this.name = name;
+ this.value = value;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The session that generated the event.
+ */
+ private FlexSession session;
+
+ /**
+ * The name of the attribute associated with the event.
+ */
+ private String name;
+
+ /**
+ * The value of the attribute associated with the event.
+ */
+ private Object value;
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Returns the Flex session that generated the event.
+ *
+ * @return The Flex session that generated the event.
+ */
+ public FlexSession getSession()
+ {
+ return session;
+ }
+
+ /**
+ * Returns the name of the attribute associated with the event.
+ *
+ * @return The name of the attribute associated with the event.
+ */
+ public String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Returns the value of the attribute associated with the event.
+ *
+ * @return The value of the attribute associated with the event.
+ */
+ public Object getValue()
+ {
+ return value;
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexSessionBindingListener.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/FlexSessionBindingListener.java b/core/src/flex/messaging/FlexSessionBindingListener.java
new file mode 100644
index 0000000..3c9b98e
--- /dev/null
+++ b/core/src/flex/messaging/FlexSessionBindingListener.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+/**
+ * Interface to be notified when the object is bound or unbound from the Flex
+ * session.
+ */
+public interface FlexSessionBindingListener
+{
+ /**
+ * Callback invoked when the object is bound to a Flex session.
+ *
+ * @param event The event containing the associated session and attribute
+ * information.
+ */
+ void valueBound(FlexSessionBindingEvent event);
+
+ /**
+ * Callback invoked when the object is unbound from a Flex session.
+ *
+ * @param event The event containing the associated session and attribute
+ * information.
+ */
+ void valueUnbound(FlexSessionBindingEvent event);
+}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexSessionConnectivityEvent.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/FlexSessionConnectivityEvent.java b/core/src/flex/messaging/FlexSessionConnectivityEvent.java
new file mode 100644
index 0000000..4f1e9bd
--- /dev/null
+++ b/core/src/flex/messaging/FlexSessionConnectivityEvent.java
@@ -0,0 +1,50 @@
+/*
+ * 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 java.util.EventObject;
+
+/**
+ * An event dispatched when the connection state for a session changes.
+ */
+public class FlexSessionConnectivityEvent extends EventObject
+{
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8622680412552475829L;
+
+ /**
+ * Constructs a new <tt>FlexSessionConnectivityEvent</tt> using the supplied source <tt>ConnectionAwareSession</tt>.
+ *
+ * @param session The session whose connection state has changed.
+ */
+ public FlexSessionConnectivityEvent(ConnectionAwareSession session)
+ {
+ super(session);
+ }
+
+ /**
+ * Returns the session whose connection state has changed.
+ *
+ * @return The session whose connection state has changed.
+ */
+ public ConnectionAwareSession getFlexSession()
+ {
+ return (ConnectionAwareSession)getSource();
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexSessionConnectivityListener.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/FlexSessionConnectivityListener.java b/core/src/flex/messaging/FlexSessionConnectivityListener.java
new file mode 100644
index 0000000..2fc1137
--- /dev/null
+++ b/core/src/flex/messaging/FlexSessionConnectivityListener.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * The listener interface for receiving FlexSession connectivity events.
+ */
+
+public interface FlexSessionConnectivityListener
+{
+ /**
+ * Invoked when the session has connected to the remote host.
+ *
+ * @param event The <tt>FlexSessionConnectivityEvent</tt> for the connect event.
+ */
+ void sessionConnected(FlexSessionConnectivityEvent event);
+
+ /**
+ * Invoked when the session has disconnected from or lost connectivity to the remote host.
+ *
+ * @param event The <tt>FlexSessionConnectivityEvent</tt> for the disconnect event.
+ */
+ void sessionDisconnected(FlexSessionConnectivityEvent event);
+}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexSessionListener.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/FlexSessionListener.java b/core/src/flex/messaging/FlexSessionListener.java
new file mode 100644
index 0000000..b9058d5
--- /dev/null
+++ b/core/src/flex/messaging/FlexSessionListener.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+/**
+ * Interface to be notified when a FlexSession is created or destroyed. Implementations of this interface
+ * may add themselves as session created listeners statically via <code>FlexSession.addSessionCreatedListener()</code>.
+ * To listen for FlexSession destruction, the implementation class instance must add itself as a listener to
+ * a specific FlexSession instance via the <code>addSessionDestroyedListener()</code> method.
+ */
+public interface FlexSessionListener
+{
+ /**
+ * Notification that a FlexSession was created.
+ *
+ * @param session The FlexSession that was created.
+ */
+ void sessionCreated(FlexSession session);
+
+ /**
+ * Notification that a FlexSession is about to be destroyed.
+ *
+ * @param session The FlexSession that will be destroyed.
+ */
+ void sessionDestroyed(FlexSession session);
+}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/FlexSessionManager.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/FlexSessionManager.java b/core/src/flex/messaging/FlexSessionManager.java
new file mode 100644
index 0000000..bec0352
--- /dev/null
+++ b/core/src/flex/messaging/FlexSessionManager.java
@@ -0,0 +1,299 @@
+/*
+ * 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.management.ManageableComponent;
+import flex.messaging.log.LogCategories;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Manages FlexSession instances for a MessageBroker.
+ */
+public class FlexSessionManager extends ManageableComponent
+{
+ public static final String TYPE = "FlexSessionManager";
+
+ private static final long MILLIS_IN_HOUR = 3600000;
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructors
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ *
+ * Constructs a <tt>FlexSessionManager</tt> for the passed <tt>MessageBroker</tt>.
+ *
+ * @param broker The root <tt>MessageBroker</tt> using this <tt>FlexSessionManager</tt>.
+ */
+ public FlexSessionManager(MessageBroker broker)
+ {
+ this(false, broker);
+ }
+
+ /**
+ *
+ * Constructs a <tt>FlexSessionManager</tt> for the passed <tt>MessageBroker</tt> and optionally enables management.
+ *
+ * @param enableManagement <code>true</code> if the <tt>FlexSessionManager</tt>
+ * is manageable; otherwise <code>false</code>.
+ * @param broker the message broker
+ */
+ public FlexSessionManager(boolean enableManagement, MessageBroker broker)
+ {
+ super(enableManagement);
+
+ super.setId(TYPE);
+
+ this.broker = broker;
+
+ this.setParent(broker);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Instance-level lock.
+ */
+ private final Object lock = new Object();
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // logCategory
+ //----------------------------------
+
+ /**
+ * Returns the log category for this component.
+ *
+ * @return The log category for this component.
+ */
+ @Override
+ protected String getLogCategory()
+ {
+ return LogCategories.ENDPOINT_FLEXSESSION;
+ }
+
+ //----------------------------------
+ // flexSessionCount
+ //----------------------------------
+
+ private int flexSessionCount;
+
+ /**
+ * Returns the total count of active FlexSessions.
+ *
+ * @return The total count of active FlexSessions.
+ */
+ public int getFlexSessionCount()
+ {
+ synchronized (lock)
+ {
+ return flexSessionCount;
+ }
+ }
+
+ //----------------------------------
+ // flexSessionProviders
+ //----------------------------------
+
+ private final ConcurrentHashMap<Class<? extends FlexSession>, AbstractFlexSessionProvider> providers = new ConcurrentHashMap<Class<? extends FlexSession>, AbstractFlexSessionProvider>();
+
+ /**
+ * Returns the registered <tt>FlexSessionProvider</tt> implementation for the specified <tt>FlexSession</tt> type.
+ *
+ * @param sessionClass The specific <tt>FlexSession</tt> type to get a provider for.
+ * @return The registered <tt>FlexSessionProvider</tt> or <code>null</code> if no provider is registered.
+ */
+ public AbstractFlexSessionProvider getFlexSessionProvider(Class<? extends FlexSession> sessionClass)
+ {
+ return providers.get(sessionClass);
+ }
+
+ /**
+ * Registers a <tt>FlexSessionProvider</tt> implementation for a specified <tt>FlexSession</tt> type.
+ *
+ * @param sessionClass The specific <tt>FlexSession</tt> type to register a provider for.
+ * @param provider The corresponding <tt>FlexSessionProvider</tt> to register.
+ * @return The previously registered provider, or <code>null</code> if no provider was registered for this session type.
+ */
+ public AbstractFlexSessionProvider registerFlexSessionProvider(Class<? extends FlexSession> sessionClass, AbstractFlexSessionProvider provider)
+ {
+ provider.setFlexSessionManager(this);
+ AbstractFlexSessionProvider previousProvider = providers.putIfAbsent(sessionClass, provider);
+
+ if (previousProvider != null)
+ {
+ previousProvider.stop();
+ previousProvider.setFlexSessionManager(null);
+ }
+
+ if (isStarted())
+ provider.start();
+
+ return previousProvider;
+ }
+
+ /**
+ * Unregisters a <tt>FlexSessionProvider</tt> implementation for a specified <tt>FlexSession</tt> type.
+ *
+ * @param sessionClass The specific <tt>FlexSession</tt> type to unregister a provider for.
+ */
+ public void unregisterFlexSessionProvider(Class<? extends FlexSession> sessionClass)
+ {
+ AbstractFlexSessionProvider provider = providers.remove(sessionClass);
+ if (provider != null)
+ {
+ provider.stop();
+ provider.setFlexSessionManager(null);
+ }
+ }
+
+ //----------------------------------
+ // flexSessions
+ //----------------------------------
+
+ /**
+ * Registers a new <tt>FlexSession</tt> with the <tt>FlexSessionManager</tt>.
+ *
+ * @param session The new <tt>FlexSession</tt>.
+ */
+ public void registerFlexSession(FlexSession session)
+ {
+ synchronized (lock)
+ {
+ ++flexSessionCount;
+ resetMaxFlexSessionsInCurrentHour(flexSessionCount);
+ }
+ }
+
+ /**
+ * Unregisters an invalidated <tt>FlexSession</tt> from the <tt>FlexSessionManager</tt>.
+ *
+ * @param session The invalidated <tt>FlexSession</tt>.
+ */
+ public void unregisterFlexSession(FlexSession session)
+ {
+ synchronized (lock)
+ {
+ --flexSessionCount;
+ resetMaxFlexSessionsInCurrentHour(flexSessionCount);
+ }
+ }
+
+ //----------------------------------
+ // maxFlexSessionsInCurrentHour
+ //----------------------------------
+
+ private int maxSessionCountInCurrentHour;
+ private long currentHourStartTimestamp = System.currentTimeMillis();
+
+ public int getMaxFlexSessionsInCurrentHour()
+ {
+ synchronized (lock)
+ {
+ // Make sure we report the correct value if the system has been idle across an hour transition.
+ resetMaxFlexSessionsInCurrentHour(flexSessionCount);
+
+ return maxSessionCountInCurrentHour;
+ }
+ }
+
+ /* Must be called within a synchronized block. */
+ private void resetMaxFlexSessionsInCurrentHour(int currentCount)
+ {
+ long offset = (System.currentTimeMillis() - currentHourStartTimestamp) / MILLIS_IN_HOUR;
+ if (offset > 0) // Shift to the current hour and reset to the current session count.
+ {
+ currentHourStartTimestamp += (MILLIS_IN_HOUR * offset);
+ maxSessionCountInCurrentHour = currentCount;
+ }
+ else if (maxSessionCountInCurrentHour < currentCount)
+ {
+ maxSessionCountInCurrentHour = currentCount;
+ }
+ }
+
+ //----------------------------------
+ // messageBroker
+ //----------------------------------
+
+ private final MessageBroker broker;
+
+ /**
+ * Returns the <tt>MessageBroker</tt> instance that owns this <tt>FlexSessionManager</tt>.
+ *
+ * @return The parent <tt>MessageBroker</tt> instance.
+ */
+ public MessageBroker getMessageBroker()
+ {
+ return broker;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Public Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Starts the <tt>FlexSessionManager</tt>.
+ * Any registered <tt>FlexSession</tt>s providers are also started.
+ */
+ @Override
+ public void start()
+ {
+ if (isStarted())
+ return;
+
+ for (AbstractFlexSessionProvider provider : providers.values())
+ {
+ if (!provider.isStarted())
+ provider.start();
+ }
+
+ super.start();
+ }
+
+ /**
+ * Stops the <tt>FlexSessionManager</tt>.
+ * Any registered <tt>FlexSession</tt> providers are stopped and unregistered.
+ */
+ @Override
+ public void stop()
+ {
+ if (!isStarted())
+ return;
+
+ super.stop();
+
+ for (Class<? extends FlexSession> sessionClass : providers.keySet())
+ {
+ unregisterFlexSessionProvider(sessionClass);
+ }
+ providers.clear();
+ }
+}
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/bf2e1dc9/core/src/flex/messaging/HttpFlexSession.java
----------------------------------------------------------------------
diff --git a/core/src/flex/messaging/HttpFlexSession.java b/core/src/flex/messaging/HttpFlexSession.java
new file mode 100644
index 0000000..3bf626a
--- /dev/null
+++ b/core/src/flex/messaging/HttpFlexSession.java
@@ -0,0 +1,668 @@
+/*
+ * 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.
+ */
+public class HttpFlexSession extends FlexSession
+ implements HttpSessionBindingListener, HttpSessionListener, HttpSessionAttributeListener, Serializable
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ *
+ * 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()
+ {}
+
+ /**
+ *
+ * Not for public use. Constructs new instances that effectively wrap pre-existing JEE HttpSession instances.
+ *
+ * @param provider HttpFlexSessionProvider object
+ */
+ 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;
+
+ /**
+ *
+ * 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);
+ }
+
+ /**
+ *
+ * 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.
+ *
+ * @param recreate true if the http session should be recreated.
+ */
+ 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();
+ }
+
+ /**
+ *
+ * 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);
+ }
+ }
+
+ /**
+ *
+ * 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();
+ }
+ }
+
+}