001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004     *
005     *   This file is part of the Granite Data Services Platform.
006     *
007     *   Granite Data Services is free software; you can redistribute it and/or
008     *   modify it under the terms of the GNU Lesser General Public
009     *   License as published by the Free Software Foundation; either
010     *   version 2.1 of the License, or (at your option) any later version.
011     *
012     *   Granite Data Services is distributed in the hope that it will be useful,
013     *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015     *   General Public License for more details.
016     *
017     *   You should have received a copy of the GNU Lesser General Public
018     *   License along with this library; if not, write to the Free Software
019     *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020     *   USA, or see <http://www.gnu.org/licenses/>.
021     */
022    package org.granite.gravity.jbossweb;
023    
024    import java.util.concurrent.atomic.AtomicReference;
025    
026    import javax.servlet.http.HttpServletRequest;
027    import javax.servlet.http.HttpServletResponse;
028    
029    import org.granite.gravity.AbstractChannel;
030    import org.granite.gravity.AbstractGravityServlet;
031    import org.granite.gravity.AsyncHttpContext;
032    import org.granite.gravity.Gravity;
033    import org.granite.logging.Logger;
034    import org.jboss.servlet.http.HttpEvent;
035    
036    import flex.messaging.messages.Message;
037    
038    /**
039     * @author Franck WOLFF
040     */
041    public class JBossWebChannel extends AbstractChannel {
042    
043        private static final Logger log = Logger.getLogger(JBossWebChannel.class);
044    
045        private final AtomicReference<HttpEvent> event = new AtomicReference<HttpEvent>();
046    
047        public JBossWebChannel(Gravity gravity, String id, JBossWebChannelFactory factory, String clientType) {
048            super(gravity, id, factory, clientType);
049        }
050        
051        public void setHttpEvent(HttpEvent event) {
052            if (log.isDebugEnabled())
053                log.debug("Channel: %s got new event: %s", getId(), EventUtil.toString(event));
054    
055            // Set this channel's event.
056            HttpEvent previousEvent = this.event.getAndSet(event);
057    
058            // Normally, we should have only two cases here:
059            //
060            // 1) this.event == null && event != null -> new (re)connect message.
061            // 2) this.event != null && event == null -> timeout.
062            //
063            // Not sure about what should be done if this.event != null && event != null, so
064            // warn about this case and close this.event if it is not the same as the event
065            // parameter.
066            if (previousEvent != null) {
067                    if (event != null) {
068                            log.warn(
069                                    "Got a new non null event %s while current event %s isn't null",
070                                    EventUtil.toString(event), EventUtil.toString(this.event.get())
071                            );
072                    }
073                    if (previousEvent != event) {
074                            try {
075                                    previousEvent.close();
076                            }
077                            catch (Exception e) {
078                                    log.debug(e, "Error while closing event");
079                            }
080                    }
081            }
082            
083            // Try to queue receiver if the new event isn't null.
084            if (event != null)
085                    queueReceiver();
086        }
087        
088        @Override
089            protected boolean hasAsyncHttpContext() {
090            return this.event.get() != null;
091            }
092    
093            @Override
094            protected AsyncHttpContext acquireAsyncHttpContext() {
095                    
096                    HttpEvent event = this.event.getAndSet(null);
097            if (event == null)
098                    return null;
099    
100            AsyncHttpContext context = null;
101            
102            try {
103                    HttpServletRequest request = null;
104                    HttpServletResponse response = null;
105                    try {
106                            request = event.getHttpServletRequest();
107                            response = event.getHttpServletResponse();
108                    } catch (Exception e) {
109                            log.warn(e, "Illegal event: %s", EventUtil.toString(event));
110                            return null;
111                    }
112                    if (request == null || response == null) {
113                            log.warn("Illegal event (request or response is null): %s", EventUtil.toString(event));
114                            return null;
115                    }
116            
117                    Message requestMessage = AbstractGravityServlet.getConnectMessage(request);
118                    if (requestMessage == null) {
119                            log.warn("No request message while running channel: %s", getId());
120                            return null;
121                    }
122                            
123                    context = new AsyncHttpContext(request, response, requestMessage, event);
124            }
125            finally {
126                    if (context == null) {
127                            try {
128                                    event.close();
129                            }
130                            catch (Exception e) {
131                                    log.debug(e, "Error while closing event: %s", EventUtil.toString(event));
132                            }
133                    }
134            }
135            
136            return context;
137            }
138    
139            @Override
140            protected void releaseAsyncHttpContext(AsyncHttpContext context) {
141                    try {
142                            if (context != null && context.getObject() != null)
143                                    ((HttpEvent)context.getObject()).close();
144                    }
145                    catch (Exception e) {
146                            log.debug(e, "Could not release event for channel: %s", this);
147                    }
148            }
149    
150            @Override
151            public void destroy() {
152                    try {
153                            super.destroy();
154                    }
155                    finally {
156                            close();
157                    }
158            }
159            
160            public void close() {
161                    HttpEvent event = this.event.getAndSet(null);
162                    if (event != null) {
163                            try {
164                                    event.close();
165                            }
166                            catch (Exception e) {
167                                    log.debug(e, "Could not close event: %s for channel: %s", EventUtil.toString(event), this);
168                            }
169                    }
170            }
171    }