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