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 */ 022package org.granite.gravity.weblogic; 023 024import java.io.IOException; 025import java.lang.reflect.Method; 026import java.util.concurrent.atomic.AtomicReference; 027 028import org.granite.gravity.AbstractChannel; 029import org.granite.gravity.AsyncHttpContext; 030import org.granite.gravity.Gravity; 031import org.granite.logging.Logger; 032 033import weblogic.servlet.http.AbstractAsyncServlet; 034import weblogic.servlet.http.RequestResponseKey; 035 036/** 037 * @author Franck WOLFF 038 */ 039public class WebLogicChannel extends AbstractChannel { 040 041 private static final Logger log = Logger.getLogger(WebLogicChannel.class); 042 043 // For WebLogic 9.1 compatibility. 044 private static Method isValid = null; 045 static { 046 try { 047 isValid = RequestResponseKey.class.getDeclaredMethod("isValid"); 048 } 049 catch (Throwable t) { 050 } 051 } 052 053 private final AtomicReference<RequestResponseKey> key = new AtomicReference<RequestResponseKey>(); 054 055 056 public WebLogicChannel(Gravity gravity, String id, WebLogicChannelFactory factory, String clientType) { 057 super(gravity, id, factory, clientType); 058 } 059 060 public void setRequestResponseKey(RequestResponseKey key) { 061 if (log.isDebugEnabled()) 062 log.debug("Channel: %s got new asyncContext: %s", getId(), key); 063 064 // Set this channel's request/response key. 065 RequestResponseKey previousKey = this.key.getAndSet(key); 066 067 // Normally, we should have only two cases here: 068 // 069 // 1) this.key == null && key != null -> new (re)connect message. 070 // 2) this.key != null && key == null -> timeout. 071 // 072 // Not sure about what should be done if this.key != null && key != null, so 073 // warn about this case and close this.key if it is not the same as the key 074 // parameter. 075 if (previousKey != null) { 076 if (key != null) { 077 log.warn( 078 "Got a new non null key %s while current key %s isn't null", 079 key, this.key.get() 080 ); 081 } 082 if (previousKey != key) { 083 try { 084 previousKey.getResponse().getOutputStream().close(); 085 } 086 catch (Exception e) { 087 log.debug(e, "Error while closing key"); 088 } 089 } 090 } 091 092 // Try to queue receiver if the new asyncContext isn't null. 093 if (key != null) 094 queueReceiver(); 095 } 096 097 @Override 098 protected boolean hasAsyncHttpContext() { 099 return key.get() != null; 100 } 101 102 @Override 103 protected AsyncHttpContext acquireAsyncHttpContext() { 104 RequestResponseKey key = this.key.getAndSet(null); 105 if (key == null || !isValid(key)) 106 return null; 107 108 try { 109 AbstractAsyncServlet.notify(key, this); 110 } 111 catch (IOException e) { 112 throw new RuntimeException(e); 113 } 114 115 return null; 116 } 117 118 @Override 119 protected void releaseAsyncHttpContext(AsyncHttpContext context) { 120 // This method shouldn't be called in a WebLogic environment, anyway... 121 try { 122 if (context != null) 123 context.getResponse().getOutputStream().close(); 124 } 125 catch (Exception e) { 126 log.warn(e, "Could not release asyncHttpContext for channel: %s", this); 127 } 128 } 129 130 @Override 131 public void destroy() { 132 try { 133 super.destroy(); 134 } 135 finally { 136 close(); 137 } 138 } 139 140 public void close() { 141 RequestResponseKey key = this.key.getAndSet(null); 142 if (key != null) { 143 try { 144 key.getResponse().getOutputStream().close(); 145 } 146 catch (Exception e) { 147 log.debug(e, "Could not close key: %s for channel: %s", key, this); 148 } 149 } 150 } 151 152 private static boolean isValid(RequestResponseKey key) { 153 if (isValid != null) try { 154 return (Boolean)isValid.invoke(key); 155 } 156 catch (Exception e) { 157 return false; 158 } 159 return true; 160 } 161}