001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2014 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.jbossweb; 023 024import org.granite.gravity.AbstractGravityServlet; 025import org.granite.logging.Logger; 026import org.jboss.servlet.http.HttpEvent; 027import org.jboss.servlet.http.HttpEventServlet; 028 029import javax.servlet.ServletException; 030import javax.servlet.http.HttpServletRequest; 031import javax.servlet.http.HttpServletResponse; 032import java.io.IOException; 033import java.io.InputStream; 034 035/** 036 * @author Franck WOLFF 037 */ 038public abstract class AbstractHttpEventServlet extends AbstractGravityServlet implements HttpEventServlet { 039 040 /////////////////////////////////////////////////////////////////////////// 041 // Fields. 042 043 private static final long serialVersionUID = 1L; 044 private static final Logger log = Logger.getLogger(AbstractHttpEventServlet.class); 045 046 private boolean longPollingTimeoutSupported = true; 047 048 /////////////////////////////////////////////////////////////////////////// 049 // Abstract methods. 050 051 public abstract CometIO createCometIO(); 052 053 public abstract boolean handleRequest(HttpEvent event, InputStream content) 054 throws IOException, ServletException; 055 056 public abstract boolean handleEnd(HttpEvent event) 057 throws IOException, ServletException; 058 059 public abstract boolean handleError(HttpEvent event) 060 throws IOException, ServletException; 061 062 /////////////////////////////////////////////////////////////////////////// 063 // CometProcessor implementation. 064 065 public void event(HttpEvent event) throws IOException, ServletException { 066 067 // make sure we've got a valid CometEvent (should never happen) 068 if (!EventUtil.isValid(event)) { 069 log.error("JBossWeb sent an invalid HttpEvent: %s", event.getType()); 070 return; 071 } 072 073 if (log.isDebugEnabled()) { 074 log.debug( 075 "%s: %s/%s", 076 event.getType(), 077 event.getHttpServletRequest(), event.getHttpServletResponse() 078 ); 079 } 080 081 if (event.getType() == HttpEvent.EventType.BEGIN) 082 begin(event); 083 else if (event.getType() == HttpEvent.EventType.READ) 084 read(event); 085 else if (event.getType() == HttpEvent.EventType.END) 086 end(event); 087 else if (event.getType() == HttpEvent.EventType.ERROR 088 || event.getType() == HttpEvent.EventType.EOF 089 || event.getType() == HttpEvent.EventType.TIMEOUT) 090 error(event); 091 else 092 throw new ServletException("Unknown HttpEvent type: " + event.getType()); 093 } 094 095 /////////////////////////////////////////////////////////////////////////// 096 // Comet events processing. 097 098 protected void begin(HttpEvent event) throws IOException, ServletException { 099 boolean close = true; 100 try { 101 // Event timeout isn't supported with APR connectors... 102 if (longPollingTimeoutSupported) { 103 try { 104 event.setTimeout((int)getLongPollingTimeout()); 105 } 106 catch (Exception e) { 107 longPollingTimeoutSupported = false; 108 } 109 } 110 111 HttpServletRequest request = event.getHttpServletRequest(); 112 CometIO io = createCometIO(); 113 io.readFully(request.getInputStream()); 114 115 close = handleRequest(event, io.getInputStream()); 116 } 117 finally { 118 if (close) { 119 try { 120 event.close(); 121 } catch (Exception e) { 122 log.debug(e, "Could not close event: %s", EventUtil.toString(event)); 123 } 124 } 125 } 126 } 127 128 protected void read(HttpEvent event) { 129 // This implementation doesn't use asynchronous reads. 130 throw new RuntimeException("Unsupported operation"); 131 } 132 133 protected void end(HttpEvent event) throws IOException, ServletException { 134 boolean close = true; 135 try { 136 close = handleEnd(event); 137 } 138 finally { 139 if (close) { 140 try { 141 event.close(); 142 } catch (Exception e) { 143 log.debug(e, "Could not close event: %s", EventUtil.toString(event)); 144 } 145 } 146 } 147 } 148 149 protected void error(HttpEvent event) throws IOException, ServletException { 150 boolean close = true; 151 try { 152 close = handleError(event); 153 } 154 finally { 155 if (close) { 156 try { 157 event.close(); 158 } catch (Exception e) { 159 log.debug(e, "Could not close event: %s", EventUtil.toString(event)); 160 } 161 } 162 } 163 } 164 165 /////////////////////////////////////////////////////////////////////////// 166 // Utility. 167 168 @Override 169 protected void service(HttpServletRequest request, HttpServletResponse response) 170 throws IOException, ServletException { 171 throw new ServletException("Not in a valid Comet configuration (use an APR or NIO connector)"); 172 } 173}