flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cd...@apache.org
Subject [10/51] [partial] FLEX-34306 - [BlazeDS] Make the BlazeDS build run on Windows machines - Added some mkdir commands to the ANT Build.java - Did some fine-tuning to resolve some compile errors
Date Mon, 05 May 2014 20:08:24 GMT
http://git-wip-us.apache.org/repos/asf/flex-blazeds/blob/4f6a3052/modules/core/src/flex/messaging/endpoints/BaseHTTPEndpoint.java
----------------------------------------------------------------------
diff --git a/modules/core/src/flex/messaging/endpoints/BaseHTTPEndpoint.java b/modules/core/src/flex/messaging/endpoints/BaseHTTPEndpoint.java
old mode 100755
new mode 100644
index 71fb829..5dbf48f
--- a/modules/core/src/flex/messaging/endpoints/BaseHTTPEndpoint.java
+++ b/modules/core/src/flex/messaging/endpoints/BaseHTTPEndpoint.java
@@ -1,636 +1,636 @@
-/*
- * 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.endpoints;
-
-import flex.management.runtime.messaging.endpoints.EndpointControl;
-import flex.messaging.FlexContext;
-import flex.messaging.FlexSession;
-import flex.messaging.HttpFlexSession;
-import flex.messaging.MessageClient;
-import flex.messaging.client.FlexClient;
-import flex.messaging.config.ConfigMap;
-import flex.messaging.config.ConfigurationConstants;
-import flex.messaging.endpoints.amf.AMFFilter;
-import flex.messaging.io.MessageIOConstants;
-import flex.messaging.io.amf.ActionContext;
-import flex.messaging.log.HTTPRequestLog;
-import flex.messaging.messages.CommandMessage;
-import flex.messaging.messages.Message;
-import flex.messaging.util.SettingsReplaceUtil;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Abstract base class for all the HTTP-based endpoints.
- */
-public abstract class BaseHTTPEndpoint extends AbstractEndpoint
-{
-    //--------------------------------------------------------------------------
-    //
-    // Public Static Constants
-    //
-    //--------------------------------------------------------------------------
-
-    /**
-     * The secure and insecure URL schemes for the HTTP endpoint.
-     */
-    public static final String HTTP_PROTOCOL_SCHEME = "http";
-    public static final String HTTPS_PROTOCOL_SCHEME = "https";
-
-    //--------------------------------------------------------------------------
-    //
-    // Private Static Constants
-    //
-    //--------------------------------------------------------------------------
-
-    private static final String ADD_NO_CACHE_HEADERS = "add-no-cache-headers";
-    private static final String REDIRECT_URL = "redirect-url";
-    private static final String INVALIDATE_SESSION_ON_DISCONNECT = "invalidate-session-on-disconnect";
-    private static final String HTTP_RESPONSE_HEADERS = "http-response-headers";
-    private static final String HEADER_ATTR = "header";
-
-    private static final String HEADER_NAME_ORIGIN = "Origin";
-    private static final String ACCESS_CONTROL = "Access-Control-";
-    private static final String SESSION_REWRITING_ENABLED = "session-rewriting-enabled";
-
-    private static final int ERR_MSG_DUPLICATE_SESSIONS_DETECTED = 10035;
-    private static final String REQUEST_ATTR_DUPLICATE_SESSION_FLAG = "flex.messaging.request.DuplicateSessionDetected";
-
-    //--------------------------------------------------------------------------
-    //
-    // Constructor
-    //
-    //--------------------------------------------------------------------------
-
-    /**
-     * Constructs an unmanaged <code>BaseHTTPEndpoint</code>.
-     */
-    public BaseHTTPEndpoint()
-    {
-        this(false);
-    }
-
-    /**
-     * Constructs a <code>BaseHTTPEndpoint</code> with the specified management
setting.
-     *
-     * @param enableManagement <code>true</code> if the <code>BaseHTTPEndpoint</code>
-     * is manageable; otherwise <code>false</code>.
-     */
-    public BaseHTTPEndpoint(boolean enableManagement)
-    {
-        super(enableManagement);
-    }
-
-    //--------------------------------------------------------------------------
-    //
-    // Initialize, validate, start, and stop methods.
-    //
-    //--------------------------------------------------------------------------
-
-    /**
-     * Initializes the <code>Endpoint</code> with the properties.
-     * If subclasses override this method, they must call <code>super.initialize()</code>.
-     *
-     * @param id The ID of the <code>Endpoint</code>.
-     * @param properties Properties for the <code>Endpoint</code>.
-     */
-    @Override public void initialize(String id, ConfigMap properties)
-    {
-        super.initialize(id, properties);
-
-        if (properties == null || properties.size() == 0)
-            return;
-
-        // General HTTP props.
-        addNoCacheHeaders = properties.getPropertyAsBoolean(ADD_NO_CACHE_HEADERS, true);
-        redirectURL = properties.getPropertyAsString(REDIRECT_URL, null);
-        invalidateSessionOnDisconnect = properties.getPropertyAsBoolean(INVALIDATE_SESSION_ON_DISCONNECT,
false);
-        loginAfterDisconnect = properties.getPropertyAsBoolean(ConfigurationConstants.LOGIN_AFTER_DISCONNECT_ELEMENT,
false);
-        sessionRewritingEnabled = properties.getPropertyAsBoolean(SESSION_REWRITING_ENABLED,
true);
-        initializeHttpResponseHeaders(properties);
-        validateEndpointProtocol();
-    }
-
-    /**
-     * Starts the <code>Endpoint</code> by creating a filter chain and setting
-     * up serializers and deserializers.
-     */
-    @Override public void start()
-    {
-        if (isStarted())
-            return;
-
-        super.start();
-
-        filterChain = createFilterChain();
-    }
-
-    //--------------------------------------------------------------------------
-    //
-    // Variables
-    //
-    //--------------------------------------------------------------------------
-
-    /**
-     * Controller used to manage this endpoint.
-     */
-    protected EndpointControl controller;
-
-    /**
-     * AMF processing filter chain used by this endpoint.
-     */
-    protected AMFFilter filterChain;
-
-    /**
-     * Headers to add to the HTTP response.
-     */
-    protected List<HttpHeader> httpResponseHeaders;
-
-    //--------------------------------------------------------------------------
-    //
-    // Properties
-    //
-    //--------------------------------------------------------------------------
-
-    //----------------------------------
-    //  addNoCacheHeaders
-    //----------------------------------
-
-    protected boolean addNoCacheHeaders = true;
-
-    /**
-     * Retrieves the <code>add-no-cache-headers</code> property.
-     *
-     * @return <code>true</code> if <code>add-no-cache-headers</code>
is enabled;
-     * <code>false</code> otherwise.
-     */
-    public boolean isAddNoCacheHeaders()
-    {
-        return addNoCacheHeaders;
-    }
-
-    /**
-     * Sets the <code>add-no-cache-headers</code> property.
-     *
-     * @param addNoCacheHeaders The <code>add-no-cache-headers</code> property.
-     */
-    public void setAddNoCacheHeaders(boolean addNoCacheHeaders)
-    {
-        this.addNoCacheHeaders = addNoCacheHeaders;
-    }
-
-    //----------------------------------
-    //  loginAfterDisconnect
-    //----------------------------------
-
-    /**
-     * @exclude
-     * This is a property used on the client.
-     */
-    protected boolean loginAfterDisconnect;
-
-    //----------------------------------
-    //  invalidateSessionOnDisconnect
-    //----------------------------------
-
-    protected boolean invalidateSessionOnDisconnect;
-
-    /**
-     * Indicates whether the server session will be invalidated
-     * when a client channel disconnects.
-     * The default is <code>false</code>.
-     *
-     * @return <code>true</code> if the server session will be invalidated
-     *         when a client channel disconnects, <code>false</code> otherwise.
-     */
-    public boolean isInvalidateSessionOnDisconnect()
-    {
-        return invalidateSessionOnDisconnect;
-    }
-
-    /**
-     * Determines whether to invalidate the server session for a client
-     * that disconnects its channel.
-     * The default is <code>false</code>.
-     *
-     * @param value <code>true</code> to invalidate the server session for a
client
-     *              that disconnects its channel, <code>false</code> otherwise.
-     */
-    public void setInvalidateSessionOnDisconnect(boolean value)
-    {
-        invalidateSessionOnDisconnect = value;
-    }
-
-    //----------------------------------
-    //  redirectURL
-    //----------------------------------
-
-    protected String redirectURL;
-
-    /**
-     * Retrieves the <code>redirect-url</code> property.
-     *
-     * @return The <code>redirect-url</code> property.
-     */
-    public String getRedirectURL()
-    {
-        return redirectURL;
-    }
-
-    /**
-     * Sets the <code>redirect-url</code> property.
-     *
-     * @param redirectURL The <code>redirect-url</code> property.
-     */
-    public void setRedirectURL(String redirectURL)
-    {
-        this.redirectURL = redirectURL;
-    }
-
-    //----------------------------------
-    //  sessionRewritingEnabled
-    //----------------------------------
-
-    protected boolean sessionRewritingEnabled = true;
-
-    /**
-     * Indicates whether the server will fall back on rewriting URLs to include
-     * session identifiers in the URL when HTTP session cookies are not allowed
-     * on the client. The default is <code>true</code>.
-     *
-     * @return <code>true</code> if the session rewriting is enabled.
-     */
-    public boolean isSessionRewritingEnabled()
-    {
-        return sessionRewritingEnabled;
-    }
-
-    /**
-     * Sets whether the session rewriting is enabled.
-     *
-     * @param value The session writing enabled value.
-     */
-    public void setSessionRewritingEnabled(boolean value)
-    {
-        sessionRewritingEnabled = value;
-    }
-
-    //--------------------------------------------------------------------------
-    //
-    // Public Methods
-    //
-    //--------------------------------------------------------------------------
-
-    /**
-     * Handle AMF/AMFX encoded messages sent over HTTP.
-     *
-     * @param req The original servlet request.
-     * @param res The active servlet response.
-     */
-    @Override
-    public void service(HttpServletRequest req, HttpServletResponse res)
-    {
-        super.service(req, res);
-
-        try
-        {
-            // Setup serialization and type marshalling contexts
-            setThreadLocals();
-
-            // Create a context for this request
-            ActionContext context = new ActionContext();
-
-            // Pass endpoint's mpi settings to the context so that it knows what level of
-            // performance metrics should be gathered during serialization/deserialization
-            context.setRecordMessageSizes(isRecordMessageSizes());
-            context.setRecordMessageTimes(isRecordMessageTimes());
-
-            // Send invocation through filter chain, which ends at the MessageBroker
-            filterChain.invoke(context);
-
-            // After serialization completes, increment endpoint byte counters,
-            // if the endpoint is managed
-            if (isManaged())
-            {
-                controller.addToBytesDeserialized(context.getDeserializedBytes());
-                controller.addToBytesSerialized(context.getSerializedBytes());
-            }
-
-            if (context.getStatus() != MessageIOConstants.STATUS_NOTAMF)
-            {
-                if (addNoCacheHeaders)
-                    addNoCacheHeaders(req, res);
-
-                addHeadersToResponse(req, res);
-
-                ByteArrayOutputStream outBuffer = context.getResponseOutput();
-
-                res.setContentType(getResponseContentType());
-
-                res.setContentLength(outBuffer.size());
-                outBuffer.writeTo(res.getOutputStream());
-                res.flushBuffer();
-            }
-            else
-            {
-                // Not an AMF request, probably viewed in a browser
-                if (redirectURL != null)
-                {
-                    try
-                    {
-                        //Check for redirect URL context-root token
-                        redirectURL = SettingsReplaceUtil.replaceContextPath(redirectURL,
req.getContextPath());
-                        res.sendRedirect(redirectURL);
-                    }
-                    catch (IllegalStateException alreadyFlushed)
-                    {
-                        // ignore
-                    }
-                }
-            }
-        }
-        catch (IOException ioe)
-        {
-            // This happens when client closes the connection, log it at info level
-            log.info(ioe.getMessage());
-            // Store exception information for latter logging
-            req.setAttribute(HTTPRequestLog.HTTP_ERROR_INFO, ioe.toString());
-        }
-        catch (Throwable t)
-        {
-            log.error(t.getMessage(), t);
-            // Store exception information for latter logging
-            req.setAttribute(HTTPRequestLog.HTTP_ERROR_INFO, t.toString());
-        }
-        finally
-        {
-            clearThreadLocals();
-        }
-    }
-
-
-    /**
-     * @exclude
-     * Returns a <code>ConfigMap</code> of endpoint properties that the client
-     * needs. This includes properties from <code>super.describeEndpoint</code>
-     * and additional <code>BaseHTTPEndpoint</code> specific properties under
-     * "properties" key.
-     */
-    @Override
-    public ConfigMap describeEndpoint()
-    {
-        ConfigMap endpointConfig = super.describeEndpoint();
-
-        if (loginAfterDisconnect)
-        {
-            ConfigMap loginAfterDisconnect = new ConfigMap();
-            // Adding as a value rather than attribute to the parent
-            loginAfterDisconnect.addProperty(EMPTY_STRING, TRUE_STRING);
-
-            ConfigMap properties = endpointConfig.getPropertyAsMap(PROPERTIES_ELEMENT, null);
-            if (properties == null)
-            {
-                properties = new ConfigMap();
-                endpointConfig.addProperty(PROPERTIES_ELEMENT, properties);
-            }
-            properties.addProperty(ConfigurationConstants.LOGIN_AFTER_DISCONNECT_ELEMENT,
loginAfterDisconnect);
-        }
-
-        return endpointConfig;
-    }
-
-    /**
-     * Overrides to guard against duplicate HTTP-based sessions for the same FlexClient
-     * which will occur if the remote host has disabled session cookies.
-     *
-     * @see AbstractEndpoint#setupFlexClient(String)
-     */
-    @Override
-    public FlexClient setupFlexClient(String id)
-    {
-        FlexClient flexClient = super.setupFlexClient(id);
-
-        // Scan for duplicate HTTP-sessions and if found, invalidate them and throw a MessageException.
-        // A request attribute is used to deal with batched AMF messages that arrive in a
single request by trigger multiple passes through this method.
-        boolean duplicateSessionDetected = (FlexContext.getHttpRequest().getAttribute(REQUEST_ATTR_DUPLICATE_SESSION_FLAG)
!= null);
-
-        List<FlexSession> sessions = null;
-        if (!duplicateSessionDetected)
-        {
-            sessions = flexClient.getFlexSessions();
-            int n = sessions.size();
-            if (n > 1)
-            {
-                List<HttpFlexSession> httpFlexSessions = new ArrayList<HttpFlexSession>();
-                for (int i = 0; i < n; i++)
-                {
-                    FlexSession currentSession = sessions.get(i);
-                    if (currentSession instanceof HttpFlexSession)
-                        httpFlexSessions.add((HttpFlexSession)currentSession);
-                    if (httpFlexSessions.size() > 1)
-                    {
-                        FlexContext.getHttpRequest().setAttribute(REQUEST_ATTR_DUPLICATE_SESSION_FLAG,
httpFlexSessions);
-                        duplicateSessionDetected = true;
-                        break;
-                    }
-                }
-            }
-        }
-
-        // If more than one was found, remote host isn't using session cookies. Kill all
duplicate sessions and return an error.
-        // Simplest to just re-scan the list given that it will be very short, but use an
iterator for concurrent modification.
-        if (duplicateSessionDetected)
-        {
-            Object attributeValue = FlexContext.getHttpRequest().getAttribute(REQUEST_ATTR_DUPLICATE_SESSION_FLAG);
-            String newSessionId = null;
-            String oldSessionId = null;
-            if (attributeValue != null)
-            {
-                @SuppressWarnings("unchecked")
-                List<HttpFlexSession> httpFlexSessions = (List<HttpFlexSession>)attributeValue;
-                oldSessionId = httpFlexSessions.get(0).getId();
-                newSessionId = httpFlexSessions.get(1).getId();
-            }
-
-            if (sessions != null)
-            {
-                for (FlexSession session : sessions)
-                {
-                    if (session instanceof HttpFlexSession)
-                    {
-                        session.invalidate();
-                    }
-                }
-            }
-
-            // Return an error to the client.
-
-            DuplicateSessionException e = new DuplicateSessionException();
-            // Duplicate HTTP-based FlexSession error: A request for FlexClient ''{0}'' arrived
over a new FlexSession ''{1}'', but FlexClient is already associated with FlexSession ''{2}'',
therefore it cannot be associated with the new session.
-            e.setMessage(ERR_MSG_DUPLICATE_SESSIONS_DETECTED, new Object[]{flexClient.getId(),
newSessionId, oldSessionId});
-            throw e;
-        }
-
-        return flexClient;
-    }
-
-    //--------------------------------------------------------------------------
-    //
-    // Protected Methods
-    //
-    //--------------------------------------------------------------------------
-
-    /**
-     * Adds custom headers specified in the config to the HTTP response. The only
-     * exception is that access control headers (Access-Control-*) are sent only
-     * if there is an Origin header in the request.
-     *
-     * @param request The HTTP request.
-     * @param response The HTTP response.
-     */
-    protected void addHeadersToResponse(HttpServletRequest request, HttpServletResponse response)
-    {
-        if (httpResponseHeaders == null || httpResponseHeaders.isEmpty())
-            return;
-
-        String origin = request.getHeader(HEADER_NAME_ORIGIN);
-        boolean originHeaderExists = origin != null && origin.length() != 0;
-
-        for (HttpHeader header : httpResponseHeaders)
-        {
-            if (header.name.startsWith(ACCESS_CONTROL) && !originHeaderExists)
-                continue;
-
-            response.addHeader(header.name, header.value);
-        }
-    }
-
-    /**
-     * Create the gateway filters that transform action requests
-     * and responses.
-     */
-    protected abstract AMFFilter createFilterChain();
-
-    /**
-     * Returns the content type used by the connection handler to set on the
-     * HTTP response. Subclasses should either return MessageIOConstants.AMF_CONTENT_TYPE
-     * or MessageIOConstants.XML_CONTENT_TYPE.
-     */
-    protected abstract String getResponseContentType();
-
-    /**
-     * Returns https which is the secure protocol scheme for the endpoint.
-     *
-     * @return https.
-     */
-    @Override protected String getSecureProtocolScheme()
-    {
-        return HTTPS_PROTOCOL_SCHEME;
-    }
-
-    /**
-     * Returns http which is the insecure protocol scheme for the endpoint.
-     *
-     * @return http.
-     */
-    @Override protected String getInsecureProtocolScheme()
-    {
-        return HTTP_PROTOCOL_SCHEME;
-    }
-
-    /**
-     * @see flex.messaging.endpoints.AbstractEndpoint#handleChannelDisconnect(CommandMessage)
-     */
-    @Override protected Message handleChannelDisconnect(CommandMessage disconnectCommand)
-    {
-        HttpFlexSession session = (HttpFlexSession)FlexContext.getFlexSession();
-        FlexClient flexClient = FlexContext.getFlexClient();
-
-        // Shut down any subscriptions established over this channel/endpoint
-        // for this specific FlexClient.
-        if (flexClient.isValid())
-        {
-            String endpointId = getId();
-            List<MessageClient> messageClients = flexClient.getMessageClients();
-            for (MessageClient messageClient : messageClients)
-            {
-                if (messageClient.getEndpointId().equals(endpointId))
-                {
-                    messageClient.setClientChannelDisconnected(true);
-                    messageClient.invalidate();
-                }
-            }
-        }
-
-        // And optionally invalidate the session.
-        if (session.isValid() && isInvalidateSessionOnDisconnect())
-            session.invalidate(false /* don't recreate */);
-
-        return super.handleChannelDisconnect(disconnectCommand);
-    }
-
-    protected void initializeHttpResponseHeaders(ConfigMap properties)
-    {
-        if (!properties.containsKey(HTTP_RESPONSE_HEADERS))
-            return;
-
-        ConfigMap httpResponseHeaders = properties.getPropertyAsMap(HTTP_RESPONSE_HEADERS,
null);
-        if (httpResponseHeaders == null)
-            return;
-
-        @SuppressWarnings("unchecked")
-        List<String> headers = httpResponseHeaders.getPropertyAsList(HEADER_ATTR, null);
-        if (headers == null || headers.isEmpty())
-            return;
-
-        if (this.httpResponseHeaders == null)
-            this.httpResponseHeaders = new ArrayList<HttpHeader>();
-
-        for (String header : headers)
-        {
-            int colonIndex = header.indexOf(":");
-            String name = header.substring(0, colonIndex).trim();
-            String value = header.substring(colonIndex + 1).trim();
-            this.httpResponseHeaders.add(new HttpHeader(name, value));
-        }
-    }
-
-    //--------------------------------------------------------------------------
-    //
-    // Nested Classes
-    //
-    //--------------------------------------------------------------------------
-
-    /**
-     * Helper class used for headers in the HTTP request/response.
-     */
-    static class HttpHeader
-    {
-        public HttpHeader(String name, String value)
-        {
-            this.name = name;
-            this.value = value;
-        }
-        public final String name;
-        public final String value;
-    }
+/*
+ * 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.endpoints;
+
+import flex.management.runtime.messaging.endpoints.EndpointControl;
+import flex.messaging.FlexContext;
+import flex.messaging.FlexSession;
+import flex.messaging.HttpFlexSession;
+import flex.messaging.MessageClient;
+import flex.messaging.client.FlexClient;
+import flex.messaging.config.ConfigMap;
+import flex.messaging.config.ConfigurationConstants;
+import flex.messaging.endpoints.amf.AMFFilter;
+import flex.messaging.io.MessageIOConstants;
+import flex.messaging.io.amf.ActionContext;
+import flex.messaging.log.HTTPRequestLog;
+import flex.messaging.messages.CommandMessage;
+import flex.messaging.messages.Message;
+import flex.messaging.util.SettingsReplaceUtil;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Abstract base class for all the HTTP-based endpoints.
+ */
+public abstract class BaseHTTPEndpoint extends AbstractEndpoint
+{
+    //--------------------------------------------------------------------------
+    //
+    // Public Static Constants
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * The secure and insecure URL schemes for the HTTP endpoint.
+     */
+    public static final String HTTP_PROTOCOL_SCHEME = "http";
+    public static final String HTTPS_PROTOCOL_SCHEME = "https";
+
+    //--------------------------------------------------------------------------
+    //
+    // Private Static Constants
+    //
+    //--------------------------------------------------------------------------
+
+    private static final String ADD_NO_CACHE_HEADERS = "add-no-cache-headers";
+    private static final String REDIRECT_URL = "redirect-url";
+    private static final String INVALIDATE_SESSION_ON_DISCONNECT = "invalidate-session-on-disconnect";
+    private static final String HTTP_RESPONSE_HEADERS = "http-response-headers";
+    private static final String HEADER_ATTR = "header";
+
+    private static final String HEADER_NAME_ORIGIN = "Origin";
+    private static final String ACCESS_CONTROL = "Access-Control-";
+    private static final String SESSION_REWRITING_ENABLED = "session-rewriting-enabled";
+
+    private static final int ERR_MSG_DUPLICATE_SESSIONS_DETECTED = 10035;
+    private static final String REQUEST_ATTR_DUPLICATE_SESSION_FLAG = "flex.messaging.request.DuplicateSessionDetected";
+
+    //--------------------------------------------------------------------------
+    //
+    // Constructor
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Constructs an unmanaged <code>BaseHTTPEndpoint</code>.
+     */
+    public BaseHTTPEndpoint()
+    {
+        this(false);
+    }
+
+    /**
+     * Constructs a <code>BaseHTTPEndpoint</code> with the specified management
setting.
+     *
+     * @param enableManagement <code>true</code> if the <code>BaseHTTPEndpoint</code>
+     * is manageable; otherwise <code>false</code>.
+     */
+    public BaseHTTPEndpoint(boolean enableManagement)
+    {
+        super(enableManagement);
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Initialize, validate, start, and stop methods.
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Initializes the <code>Endpoint</code> with the properties.
+     * If subclasses override this method, they must call <code>super.initialize()</code>.
+     *
+     * @param id The ID of the <code>Endpoint</code>.
+     * @param properties Properties for the <code>Endpoint</code>.
+     */
+    @Override public void initialize(String id, ConfigMap properties)
+    {
+        super.initialize(id, properties);
+
+        if (properties == null || properties.size() == 0)
+            return;
+
+        // General HTTP props.
+        addNoCacheHeaders = properties.getPropertyAsBoolean(ADD_NO_CACHE_HEADERS, true);
+        redirectURL = properties.getPropertyAsString(REDIRECT_URL, null);
+        invalidateSessionOnDisconnect = properties.getPropertyAsBoolean(INVALIDATE_SESSION_ON_DISCONNECT,
false);
+        loginAfterDisconnect = properties.getPropertyAsBoolean(ConfigurationConstants.LOGIN_AFTER_DISCONNECT_ELEMENT,
false);
+        sessionRewritingEnabled = properties.getPropertyAsBoolean(SESSION_REWRITING_ENABLED,
true);
+        initializeHttpResponseHeaders(properties);
+        validateEndpointProtocol();
+    }
+
+    /**
+     * Starts the <code>Endpoint</code> by creating a filter chain and setting
+     * up serializers and deserializers.
+     */
+    @Override public void start()
+    {
+        if (isStarted())
+            return;
+
+        super.start();
+
+        filterChain = createFilterChain();
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Variables
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Controller used to manage this endpoint.
+     */
+    protected EndpointControl controller;
+
+    /**
+     * AMF processing filter chain used by this endpoint.
+     */
+    protected AMFFilter filterChain;
+
+    /**
+     * Headers to add to the HTTP response.
+     */
+    protected List<HttpHeader> httpResponseHeaders;
+
+    //--------------------------------------------------------------------------
+    //
+    // Properties
+    //
+    //--------------------------------------------------------------------------
+
+    //----------------------------------
+    //  addNoCacheHeaders
+    //----------------------------------
+
+    protected boolean addNoCacheHeaders = true;
+
+    /**
+     * Retrieves the <code>add-no-cache-headers</code> property.
+     *
+     * @return <code>true</code> if <code>add-no-cache-headers</code>
is enabled;
+     * <code>false</code> otherwise.
+     */
+    public boolean isAddNoCacheHeaders()
+    {
+        return addNoCacheHeaders;
+    }
+
+    /**
+     * Sets the <code>add-no-cache-headers</code> property.
+     *
+     * @param addNoCacheHeaders The <code>add-no-cache-headers</code> property.
+     */
+    public void setAddNoCacheHeaders(boolean addNoCacheHeaders)
+    {
+        this.addNoCacheHeaders = addNoCacheHeaders;
+    }
+
+    //----------------------------------
+    //  loginAfterDisconnect
+    //----------------------------------
+
+    /**
+     * @exclude
+     * This is a property used on the client.
+     */
+    protected boolean loginAfterDisconnect;
+
+    //----------------------------------
+    //  invalidateSessionOnDisconnect
+    //----------------------------------
+
+    protected boolean invalidateSessionOnDisconnect;
+
+    /**
+     * Indicates whether the server session will be invalidated
+     * when a client channel disconnects.
+     * The default is <code>false</code>.
+     *
+     * @return <code>true</code> if the server session will be invalidated
+     *         when a client channel disconnects, <code>false</code> otherwise.
+     */
+    public boolean isInvalidateSessionOnDisconnect()
+    {
+        return invalidateSessionOnDisconnect;
+    }
+
+    /**
+     * Determines whether to invalidate the server session for a client
+     * that disconnects its channel.
+     * The default is <code>false</code>.
+     *
+     * @param value <code>true</code> to invalidate the server session for a
client
+     *              that disconnects its channel, <code>false</code> otherwise.
+     */
+    public void setInvalidateSessionOnDisconnect(boolean value)
+    {
+        invalidateSessionOnDisconnect = value;
+    }
+
+    //----------------------------------
+    //  redirectURL
+    //----------------------------------
+
+    protected String redirectURL;
+
+    /**
+     * Retrieves the <code>redirect-url</code> property.
+     *
+     * @return The <code>redirect-url</code> property.
+     */
+    public String getRedirectURL()
+    {
+        return redirectURL;
+    }
+
+    /**
+     * Sets the <code>redirect-url</code> property.
+     *
+     * @param redirectURL The <code>redirect-url</code> property.
+     */
+    public void setRedirectURL(String redirectURL)
+    {
+        this.redirectURL = redirectURL;
+    }
+
+    //----------------------------------
+    //  sessionRewritingEnabled
+    //----------------------------------
+
+    protected boolean sessionRewritingEnabled = true;
+
+    /**
+     * Indicates whether the server will fall back on rewriting URLs to include
+     * session identifiers in the URL when HTTP session cookies are not allowed
+     * on the client. The default is <code>true</code>.
+     *
+     * @return <code>true</code> if the session rewriting is enabled.
+     */
+    public boolean isSessionRewritingEnabled()
+    {
+        return sessionRewritingEnabled;
+    }
+
+    /**
+     * Sets whether the session rewriting is enabled.
+     *
+     * @param value The session writing enabled value.
+     */
+    public void setSessionRewritingEnabled(boolean value)
+    {
+        sessionRewritingEnabled = value;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Public Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Handle AMF/AMFX encoded messages sent over HTTP.
+     *
+     * @param req The original servlet request.
+     * @param res The active servlet response.
+     */
+    @Override
+    public void service(HttpServletRequest req, HttpServletResponse res)
+    {
+        super.service(req, res);
+
+        try
+        {
+            // Setup serialization and type marshalling contexts
+            setThreadLocals();
+
+            // Create a context for this request
+            ActionContext context = new ActionContext();
+
+            // Pass endpoint's mpi settings to the context so that it knows what level of
+            // performance metrics should be gathered during serialization/deserialization
+            context.setRecordMessageSizes(isRecordMessageSizes());
+            context.setRecordMessageTimes(isRecordMessageTimes());
+
+            // Send invocation through filter chain, which ends at the MessageBroker
+            filterChain.invoke(context);
+
+            // After serialization completes, increment endpoint byte counters,
+            // if the endpoint is managed
+            if (isManaged())
+            {
+                controller.addToBytesDeserialized(context.getDeserializedBytes());
+                controller.addToBytesSerialized(context.getSerializedBytes());
+            }
+
+            if (context.getStatus() != MessageIOConstants.STATUS_NOTAMF)
+            {
+                if (addNoCacheHeaders)
+                    addNoCacheHeaders(req, res);
+
+                addHeadersToResponse(req, res);
+
+                ByteArrayOutputStream outBuffer = context.getResponseOutput();
+
+                res.setContentType(getResponseContentType());
+
+                res.setContentLength(outBuffer.size());
+                outBuffer.writeTo(res.getOutputStream());
+                res.flushBuffer();
+            }
+            else
+            {
+                // Not an AMF request, probably viewed in a browser
+                if (redirectURL != null)
+                {
+                    try
+                    {
+                        //Check for redirect URL context-root token
+                        redirectURL = SettingsReplaceUtil.replaceContextPath(redirectURL,
req.getContextPath());
+                        res.sendRedirect(redirectURL);
+                    }
+                    catch (IllegalStateException alreadyFlushed)
+                    {
+                        // ignore
+                    }
+                }
+            }
+        }
+        catch (IOException ioe)
+        {
+            // This happens when client closes the connection, log it at info level
+            log.info(ioe.getMessage());
+            // Store exception information for latter logging
+            req.setAttribute(HTTPRequestLog.HTTP_ERROR_INFO, ioe.toString());
+        }
+        catch (Throwable t)
+        {
+            log.error(t.getMessage(), t);
+            // Store exception information for latter logging
+            req.setAttribute(HTTPRequestLog.HTTP_ERROR_INFO, t.toString());
+        }
+        finally
+        {
+            clearThreadLocals();
+        }
+    }
+
+
+    /**
+     * @exclude
+     * Returns a <code>ConfigMap</code> of endpoint properties that the client
+     * needs. This includes properties from <code>super.describeEndpoint</code>
+     * and additional <code>BaseHTTPEndpoint</code> specific properties under
+     * "properties" key.
+     */
+    @Override
+    public ConfigMap describeEndpoint()
+    {
+        ConfigMap endpointConfig = super.describeEndpoint();
+
+        if (loginAfterDisconnect)
+        {
+            ConfigMap loginAfterDisconnect = new ConfigMap();
+            // Adding as a value rather than attribute to the parent
+            loginAfterDisconnect.addProperty(EMPTY_STRING, TRUE_STRING);
+
+            ConfigMap properties = endpointConfig.getPropertyAsMap(PROPERTIES_ELEMENT, null);
+            if (properties == null)
+            {
+                properties = new ConfigMap();
+                endpointConfig.addProperty(PROPERTIES_ELEMENT, properties);
+            }
+            properties.addProperty(ConfigurationConstants.LOGIN_AFTER_DISCONNECT_ELEMENT,
loginAfterDisconnect);
+        }
+
+        return endpointConfig;
+    }
+
+    /**
+     * Overrides to guard against duplicate HTTP-based sessions for the same FlexClient
+     * which will occur if the remote host has disabled session cookies.
+     *
+     * @see AbstractEndpoint#setupFlexClient(String)
+     */
+    @Override
+    public FlexClient setupFlexClient(String id)
+    {
+        FlexClient flexClient = super.setupFlexClient(id);
+
+        // Scan for duplicate HTTP-sessions and if found, invalidate them and throw a MessageException.
+        // A request attribute is used to deal with batched AMF messages that arrive in a
single request by trigger multiple passes through this method.
+        boolean duplicateSessionDetected = (FlexContext.getHttpRequest().getAttribute(REQUEST_ATTR_DUPLICATE_SESSION_FLAG)
!= null);
+
+        List<FlexSession> sessions = null;
+        if (!duplicateSessionDetected)
+        {
+            sessions = flexClient.getFlexSessions();
+            int n = sessions.size();
+            if (n > 1)
+            {
+                List<HttpFlexSession> httpFlexSessions = new ArrayList<HttpFlexSession>();
+                for (int i = 0; i < n; i++)
+                {
+                    FlexSession currentSession = sessions.get(i);
+                    if (currentSession instanceof HttpFlexSession)
+                        httpFlexSessions.add((HttpFlexSession)currentSession);
+                    if (httpFlexSessions.size() > 1)
+                    {
+                        FlexContext.getHttpRequest().setAttribute(REQUEST_ATTR_DUPLICATE_SESSION_FLAG,
httpFlexSessions);
+                        duplicateSessionDetected = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        // If more than one was found, remote host isn't using session cookies. Kill all
duplicate sessions and return an error.
+        // Simplest to just re-scan the list given that it will be very short, but use an
iterator for concurrent modification.
+        if (duplicateSessionDetected)
+        {
+            Object attributeValue = FlexContext.getHttpRequest().getAttribute(REQUEST_ATTR_DUPLICATE_SESSION_FLAG);
+            String newSessionId = null;
+            String oldSessionId = null;
+            if (attributeValue != null)
+            {
+                @SuppressWarnings("unchecked")
+                List<HttpFlexSession> httpFlexSessions = (List<HttpFlexSession>)attributeValue;
+                oldSessionId = httpFlexSessions.get(0).getId();
+                newSessionId = httpFlexSessions.get(1).getId();
+            }
+
+            if (sessions != null)
+            {
+                for (FlexSession session : sessions)
+                {
+                    if (session instanceof HttpFlexSession)
+                    {
+                        session.invalidate();
+                    }
+                }
+            }
+
+            // Return an error to the client.
+
+            DuplicateSessionException e = new DuplicateSessionException();
+            // Duplicate HTTP-based FlexSession error: A request for FlexClient ''{0}'' arrived
over a new FlexSession ''{1}'', but FlexClient is already associated with FlexSession ''{2}'',
therefore it cannot be associated with the new session.
+            e.setMessage(ERR_MSG_DUPLICATE_SESSIONS_DETECTED, new Object[]{flexClient.getId(),
newSessionId, oldSessionId});
+            throw e;
+        }
+
+        return flexClient;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Protected Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Adds custom headers specified in the config to the HTTP response. The only
+     * exception is that access control headers (Access-Control-*) are sent only
+     * if there is an Origin header in the request.
+     *
+     * @param request The HTTP request.
+     * @param response The HTTP response.
+     */
+    protected void addHeadersToResponse(HttpServletRequest request, HttpServletResponse response)
+    {
+        if (httpResponseHeaders == null || httpResponseHeaders.isEmpty())
+            return;
+
+        String origin = request.getHeader(HEADER_NAME_ORIGIN);
+        boolean originHeaderExists = origin != null && origin.length() != 0;
+
+        for (HttpHeader header : httpResponseHeaders)
+        {
+            if (header.name.startsWith(ACCESS_CONTROL) && !originHeaderExists)
+                continue;
+
+            response.addHeader(header.name, header.value);
+        }
+    }
+
+    /**
+     * Create the gateway filters that transform action requests
+     * and responses.
+     */
+    protected abstract AMFFilter createFilterChain();
+
+    /**
+     * Returns the content type used by the connection handler to set on the
+     * HTTP response. Subclasses should either return MessageIOConstants.AMF_CONTENT_TYPE
+     * or MessageIOConstants.XML_CONTENT_TYPE.
+     */
+    protected abstract String getResponseContentType();
+
+    /**
+     * Returns https which is the secure protocol scheme for the endpoint.
+     *
+     * @return https.
+     */
+    @Override protected String getSecureProtocolScheme()
+    {
+        return HTTPS_PROTOCOL_SCHEME;
+    }
+
+    /**
+     * Returns http which is the insecure protocol scheme for the endpoint.
+     *
+     * @return http.
+     */
+    @Override protected String getInsecureProtocolScheme()
+    {
+        return HTTP_PROTOCOL_SCHEME;
+    }
+
+    /**
+     * @see flex.messaging.endpoints.AbstractEndpoint#handleChannelDisconnect(CommandMessage)
+     */
+    @Override protected Message handleChannelDisconnect(CommandMessage disconnectCommand)
+    {
+        HttpFlexSession session = (HttpFlexSession)FlexContext.getFlexSession();
+        FlexClient flexClient = FlexContext.getFlexClient();
+
+        // Shut down any subscriptions established over this channel/endpoint
+        // for this specific FlexClient.
+        if (flexClient.isValid())
+        {
+            String endpointId = getId();
+            List<MessageClient> messageClients = flexClient.getMessageClients();
+            for (MessageClient messageClient : messageClients)
+            {
+                if (messageClient.getEndpointId().equals(endpointId))
+                {
+                    messageClient.setClientChannelDisconnected(true);
+                    messageClient.invalidate();
+                }
+            }
+        }
+
+        // And optionally invalidate the session.
+        if (session.isValid() && isInvalidateSessionOnDisconnect())
+            session.invalidate(false /* don't recreate */);
+
+        return super.handleChannelDisconnect(disconnectCommand);
+    }
+
+    protected void initializeHttpResponseHeaders(ConfigMap properties)
+    {
+        if (!properties.containsKey(HTTP_RESPONSE_HEADERS))
+            return;
+
+        ConfigMap httpResponseHeaders = properties.getPropertyAsMap(HTTP_RESPONSE_HEADERS,
null);
+        if (httpResponseHeaders == null)
+            return;
+
+        @SuppressWarnings("unchecked")
+        List<String> headers = httpResponseHeaders.getPropertyAsList(HEADER_ATTR, null);
+        if (headers == null || headers.isEmpty())
+            return;
+
+        if (this.httpResponseHeaders == null)
+            this.httpResponseHeaders = new ArrayList<HttpHeader>();
+
+        for (String header : headers)
+        {
+            int colonIndex = header.indexOf(":");
+            String name = header.substring(0, colonIndex).trim();
+            String value = header.substring(colonIndex + 1).trim();
+            this.httpResponseHeaders.add(new HttpHeader(name, value));
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Nested Classes
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Helper class used for headers in the HTTP request/response.
+     */
+    static class HttpHeader
+    {
+        public HttpHeader(String name, String value)
+        {
+            this.name = name;
+            this.value = value;
+        }
+        public final String name;
+        public final String value;
+    }
 }
\ No newline at end of file


Mime
View raw message