2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
17
package org.apache.coyote.http11.upgrade;
19
import java.io.IOException;
21
import javax.servlet.ServletOutputStream;
23
import org.apache.coyote.http11.upgrade.servlet31.WriteListener;
24
import org.apache.tomcat.util.ExceptionUtils;
25
import org.apache.tomcat.util.res.StringManager;
28
* Implements the new Servlet 3.1 methods for {@link ServletOutputStream}.
30
public abstract class AbstractServletOutputStream extends ServletOutputStream {
32
protected static final StringManager sm =
33
StringManager.getManager(Constants.Package);
35
private final Object fireListenerLock = new Object();
36
private final Object writeLock = new Object();
38
private volatile boolean closeRequired = false;
39
// Start in blocking-mode
40
private volatile WriteListener listener = null;
41
private volatile boolean fireListener = false;
42
private volatile byte[] buffer;
45
* New Servlet 3.1 method.
47
public final boolean isReady() {
48
if (listener == null) {
49
throw new IllegalStateException(
50
sm.getString("upgrade.sos.canWrite.is"));
53
// Make sure isReady() and onWritePossible() have a consistent view of
54
// buffer and fireListener when determining if the listener should fire
55
synchronized (fireListenerLock) {
56
boolean result = (buffer == null);
57
fireListener = !result;
63
* New Servlet 3.1 method.
65
public final void setWriteListener(WriteListener listener) {
66
if (listener == null) {
67
throw new IllegalArgumentException(
68
sm.getString("upgrade.sos.writeListener.null"));
70
this.listener = listener;
73
protected final boolean isCloseRequired() {
78
public void write(int b) throws IOException {
79
synchronized (writeLock) {
81
writeInternal(new byte[] { (byte) b }, 0, 1);
87
public void write(byte[] b, int off, int len) throws IOException {
88
synchronized (writeLock) {
90
writeInternal(b, off, len);
96
public void close() throws IOException {
101
private void preWriteChecks() {
102
if (buffer != null) {
103
throw new IllegalStateException(
104
sm.getString("upgrade.sis.write.ise"));
110
* Must hold writeLock to call this method.
112
private void writeInternal(byte[] b, int off, int len) throws IOException {
113
if (listener == null) {
114
// Simple case - blocking IO
115
doWrite(true, b, off, len);
118
// If the non-blocking read does not complete, doWrite() will add
119
// the socket back into the poller. The poller may trigger a new
120
// write event before this method has finished updating buffer. The
121
// writeLock sync makes sure that buffer is updated before the next
123
int written = doWrite(false, b, off, len);
125
// TODO: - Reuse the buffer
126
// - Only reallocate if it gets too big (>8k?)
127
buffer = new byte[len - written];
128
System.arraycopy(b, off + written, buffer, 0, len - written);
136
protected final void onWritePossible() throws IOException {
137
synchronized (writeLock) {
139
writeInternal(buffer, 0, buffer.length);
140
} catch (Throwable t) {
141
ExceptionUtils.handleThrowable(t);
143
if (t instanceof IOException) {
144
throw (IOException) t;
146
throw new IOException(t);
150
// Make sure isReady() and onWritePossible() have a consistent view of
151
// buffer and fireListener when determining if the listener should fire
152
boolean fire = false;
154
synchronized (fireListenerLock) {
155
if (buffer == null && fireListener) {
156
fireListener = false;
161
listener.onWritePossible();
167
* Abstract method to be overridden by concrete implementations. The base
168
* class will ensure that there are no concurrent calls to this method for
171
protected abstract int doWrite(boolean block, byte[] b, int off, int len)
174
protected abstract void doFlush() throws IOException;
176
protected abstract void doClose() throws IOException;