~ubuntu-branches/ubuntu/vivid/tomcat7/vivid-proposed

« back to all changes in this revision

Viewing changes to java/org/apache/coyote/http11/upgrade/AbstractServletOutputStream.java

  • Committer: Package Import Robot
  • Author(s): tony mancill, Gianfranco Costamagna, tony mancill
  • Date: 2013-12-24 16:46:34 UTC
  • mfrom: (1.1.14)
  • Revision ID: package-import@ubuntu.com-20131224164634-2racvo4wty70t0za
Tags: 7.0.47-1
[ Gianfranco Costamagna ]
* Team upload.
* New upstream release, patch refresh.
* Renamed patch fix-manager-webapp.path
  to fix-manager-webapp.patch (extension typo).
* Refresh patches for upstream release.
* Removed -Djava.net.preferIPv4Stack=true
  from init script (lp: #1088681),
  thanks Hendrik Haddorp.
* Added webapp manager path patch (lp: #1128067)
  thanks TJ.

[ tony mancill ]
* Bump Standards-Version to 3.9.5.
* Change copyright year in javadocs to 2013.
* Add patch to include the distribution name in error pages.
  (Closes: #729840)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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
 
8
 *
 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
 
10
 *
 
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.
 
16
 */
 
17
package org.apache.coyote.http11.upgrade;
 
18
 
 
19
import java.io.IOException;
 
20
 
 
21
import javax.servlet.ServletOutputStream;
 
22
 
 
23
import org.apache.coyote.http11.upgrade.servlet31.WriteListener;
 
24
import org.apache.tomcat.util.ExceptionUtils;
 
25
import org.apache.tomcat.util.res.StringManager;
 
26
 
 
27
/**
 
28
 * Implements the new Servlet 3.1 methods for {@link ServletOutputStream}.
 
29
 */
 
30
public abstract class AbstractServletOutputStream extends ServletOutputStream {
 
31
 
 
32
    protected static final StringManager sm =
 
33
            StringManager.getManager(Constants.Package);
 
34
 
 
35
    private final Object fireListenerLock = new Object();
 
36
    private final Object writeLock = new Object();
 
37
 
 
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;
 
43
 
 
44
    /**
 
45
     * New Servlet 3.1 method.
 
46
     */
 
47
    public final boolean isReady() {
 
48
        if (listener == null) {
 
49
            throw new IllegalStateException(
 
50
                    sm.getString("upgrade.sos.canWrite.is"));
 
51
        }
 
52
 
 
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;
 
58
            return result;
 
59
        }
 
60
    }
 
61
 
 
62
    /**
 
63
     * New Servlet 3.1 method.
 
64
     */
 
65
    public final void setWriteListener(WriteListener listener) {
 
66
        if (listener == null) {
 
67
            throw new IllegalArgumentException(
 
68
                    sm.getString("upgrade.sos.writeListener.null"));
 
69
        }
 
70
        this.listener = listener;
 
71
    }
 
72
 
 
73
    protected final boolean isCloseRequired() {
 
74
        return closeRequired;
 
75
    }
 
76
 
 
77
    @Override
 
78
    public void write(int b) throws IOException {
 
79
        synchronized (writeLock) {
 
80
            preWriteChecks();
 
81
            writeInternal(new byte[] { (byte) b }, 0, 1);
 
82
        }
 
83
    }
 
84
 
 
85
 
 
86
    @Override
 
87
    public void write(byte[] b, int off, int len) throws IOException {
 
88
        synchronized (writeLock) {
 
89
            preWriteChecks();
 
90
            writeInternal(b, off, len);
 
91
        }
 
92
    }
 
93
 
 
94
 
 
95
    @Override
 
96
    public void close() throws IOException {
 
97
        closeRequired = true;
 
98
        doClose();
 
99
    }
 
100
 
 
101
    private void preWriteChecks() {
 
102
        if (buffer != null) {
 
103
            throw new IllegalStateException(
 
104
                    sm.getString("upgrade.sis.write.ise"));
 
105
        }
 
106
    }
 
107
 
 
108
 
 
109
    /**
 
110
     * Must hold writeLock to call this method.
 
111
     */
 
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);
 
116
        } else {
 
117
            // Non-blocking IO
 
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
 
122
            // write executes.
 
123
            int written = doWrite(false, b, off, len);
 
124
            if (written < 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);
 
129
            } else {
 
130
                buffer = null;
 
131
            }
 
132
        }
 
133
    }
 
134
 
 
135
 
 
136
    protected final void onWritePossible() throws IOException {
 
137
        synchronized (writeLock) {
 
138
            try {
 
139
                writeInternal(buffer, 0, buffer.length);
 
140
            } catch (Throwable t) {
 
141
                ExceptionUtils.handleThrowable(t);
 
142
                listener.onError(t);
 
143
                if (t instanceof IOException) {
 
144
                    throw (IOException) t;
 
145
                } else {
 
146
                    throw new IOException(t);
 
147
                }
 
148
            }
 
149
 
 
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;
 
153
 
 
154
            synchronized (fireListenerLock) {
 
155
                if (buffer == null && fireListener) {
 
156
                    fireListener = false;
 
157
                    fire = true;
 
158
                }
 
159
            }
 
160
            if (fire) {
 
161
                listener.onWritePossible();
 
162
            }
 
163
        }
 
164
    }
 
165
 
 
166
    /**
 
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
 
169
     * the same socket.
 
170
     */
 
171
    protected abstract int doWrite(boolean block, byte[] b, int off, int len)
 
172
            throws IOException;
 
173
 
 
174
    protected abstract void doFlush() throws IOException;
 
175
 
 
176
    protected abstract void doClose() throws IOException;
 
177
}