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 }