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; 021 022import javax.servlet.AsyncContext; 023import javax.servlet.AsyncEvent; 024import javax.servlet.AsyncListener; 025import javax.servlet.http.HttpServletRequest; 026import javax.servlet.http.HttpServletResponse; 027 028import org.springframework.lang.Nullable; 029import org.springframework.util.Assert; 030 031/** 032 * A {@link ServerHttpAsyncRequestControl} to use on Servlet containers (Servlet 3.0+). 033 * 034 * @author Rossen Stoyanchev 035 * @since 4.0 036 */ 037public class ServletServerHttpAsyncRequestControl implements ServerHttpAsyncRequestControl, AsyncListener { 038 039 private static final long NO_TIMEOUT_VALUE = Long.MIN_VALUE; 040 041 042 private final ServletServerHttpRequest request; 043 044 private final ServletServerHttpResponse response; 045 046 @Nullable 047 private AsyncContext asyncContext; 048 049 private AtomicBoolean asyncCompleted = new AtomicBoolean(false); 050 051 052 /** 053 * Constructor accepting a request and response pair that are expected to be of type 054 * {@link ServletServerHttpRequest} and {@link ServletServerHttpResponse} 055 * respectively. 056 */ 057 public ServletServerHttpAsyncRequestControl(ServletServerHttpRequest request, ServletServerHttpResponse response) { 058 Assert.notNull(request, "request is required"); 059 Assert.notNull(response, "response is required"); 060 061 Assert.isTrue(request.getServletRequest().isAsyncSupported(), 062 "Async support must be enabled on a servlet and for all filters involved " + 063 "in async request processing. This is done in Java code using the Servlet API " + 064 "or by adding \"<async-supported>true</async-supported>\" to servlet and " + 065 "filter declarations in web.xml. Also you must use a Servlet 3.0+ container"); 066 067 this.request = request; 068 this.response = response; 069 } 070 071 072 @Override 073 public boolean isStarted() { 074 return (this.asyncContext != null && this.request.getServletRequest().isAsyncStarted()); 075 } 076 077 @Override 078 public boolean isCompleted() { 079 return this.asyncCompleted.get(); 080 } 081 082 @Override 083 public void start() { 084 start(NO_TIMEOUT_VALUE); 085 } 086 087 @Override 088 public void start(long timeout) { 089 Assert.state(!isCompleted(), "Async processing has already completed"); 090 if (isStarted()) { 091 return; 092 } 093 094 HttpServletRequest servletRequest = this.request.getServletRequest(); 095 HttpServletResponse servletResponse = this.response.getServletResponse(); 096 097 this.asyncContext = servletRequest.startAsync(servletRequest, servletResponse); 098 this.asyncContext.addListener(this); 099 100 if (timeout != NO_TIMEOUT_VALUE) { 101 this.asyncContext.setTimeout(timeout); 102 } 103 } 104 105 @Override 106 public void complete() { 107 if (this.asyncContext != null && isStarted() && !isCompleted()) { 108 this.asyncContext.complete(); 109 } 110 } 111 112 113 // --------------------------------------------------------------------- 114 // Implementation of AsyncListener methods 115 // --------------------------------------------------------------------- 116 117 @Override 118 public void onComplete(AsyncEvent event) throws IOException { 119 this.asyncContext = null; 120 this.asyncCompleted.set(true); 121 } 122 123 @Override 124 public void onStartAsync(AsyncEvent event) throws IOException { 125 } 126 127 @Override 128 public void onError(AsyncEvent event) throws IOException { 129 } 130 131 @Override 132 public void onTimeout(AsyncEvent event) throws IOException { 133 } 134 135}