001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.http.server; 018 019import java.io.IOException; 020import java.util.concurrent.atomic.AtomicBoolean; 021import javax.servlet.AsyncContext; 022import javax.servlet.AsyncEvent; 023import javax.servlet.AsyncListener; 024import javax.servlet.http.HttpServletRequest; 025import javax.servlet.http.HttpServletResponse; 026 027import org.springframework.util.Assert; 028 029/** 030 * A {@link ServerHttpAsyncRequestControl} to use on Servlet containers (Servlet 3.0+). 031 * 032 * @author Rossen Stoyanchev 033 * @since 4.0 034 */ 035public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequestControl, AsyncListener { 036 037 private static final long NO_TIMEOUT_VALUE = Long.MIN_VALUE; 038 039 040 private final ServletServerHttpRequest request; 041 042 private final ServletServerHttpResponse response; 043 044 private AsyncContext asyncContext; 045 046 private AtomicBoolean asyncCompleted = new AtomicBoolean(false); 047 048 049 /** 050 * Constructor accepting a request and response pair that are expected to be of type 051 * {@link ServletServerHttpRequest} and {@link ServletServerHttpResponse} 052 * respectively. 053 */ 054 public ServletServerHttpAsyncRequestControl(ServletServerHttpRequest request, ServletServerHttpResponse response) { 055 Assert.notNull(request, "request is required"); 056 Assert.notNull(response, "response is required"); 057 058 Assert.isTrue(request.getServletRequest().isAsyncSupported(), 059 "Async support must be enabled on a servlet and for all filters involved " + 060 "in async request processing. This is done in Java code using the Servlet API " + 061 "or by adding \"<async-supported>true</async-supported>\" to servlet and " + 062 "filter declarations in web.xml. Also you must use a Servlet 3.0+ container"); 063 064 this.request = request; 065 this.response = response; 066 } 067 068 069 @Override 070 public boolean isStarted() { 071 return (this.asyncContext != null && this.request.getServletRequest().isAsyncStarted()); 072 } 073 074 @Override 075 public boolean isCompleted() { 076 return this.asyncCompleted.get(); 077 } 078 079 @Override 080 public void start() { 081 start(NO_TIMEOUT_VALUE); 082 } 083 084 @Override 085 public void start(long timeout) { 086 Assert.state(!isCompleted(), "Async processing has already completed"); 087 if (isStarted()) { 088 return; 089 } 090 091 HttpServletRequest servletRequest = this.request.getServletRequest(); 092 HttpServletResponse servletResponse = this.response.getServletResponse(); 093 094 this.asyncContext = servletRequest.startAsync(servletRequest, servletResponse); 095 this.asyncContext.addListener(this); 096 097 if (timeout != NO_TIMEOUT_VALUE) { 098 this.asyncContext.setTimeout(timeout); 099 } 100 } 101 102 @Override 103 public void complete() { 104 if (isStarted() && !isCompleted()) { 105 this.asyncContext.complete(); 106 } 107 } 108 109 110 // --------------------------------------------------------------------- 111 // Implementation of AsyncListener methods 112 // --------------------------------------------------------------------- 113 114 @Override 115 public void onComplete(AsyncEvent event) throws IOException { 116 this.asyncContext = null; 117 this.asyncCompleted.set(true); 118 } 119 120 @Override 121 public void onStartAsync(AsyncEvent event) throws IOException { 122 } 123 124 @Override 125 public void onError(AsyncEvent event) throws IOException { 126 } 127 128 @Override 129 public void onTimeout(AsyncEvent event) throws IOException { 130 } 131 132}