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.ServletConfig;
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.GravityConfig;
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(ServletConfig servletConfig, GravityConfig gravityConfig, String id) {
048 super(servletConfig, gravityConfig, id);
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 HttpEvent event = this.event.getAndSet(null);
157 if (event != null) {
158 try {
159 event.close();
160 }
161 catch (Exception e) {
162 log.debug(e, "Could not close event: %s for channel: %s", EventUtil.toString(event), this);
163 }
164 }
165 }
166 }
167 }