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