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.catalina.connector;
18
19 import java.io.IOException;
20 import java.nio.ByteBuffer;
21
22 import javax.servlet.ServletOutputStream;
23 import javax.servlet.WriteListener;
24
25 import org.apache.tomcat.util.res.StringManager;
26
27 /**
28  * Coyote implementation of the servlet output stream.
29  *
30  * @author Costin Manolache
31  * @author Remy Maucherat
32  */

33 public class CoyoteOutputStream extends ServletOutputStream {
34
35     protected static final StringManager sm = StringManager.getManager(CoyoteOutputStream.class);
36
37
38     // ----------------------------------------------------- Instance Variables
39
40     protected OutputBuffer ob;
41
42
43     // ----------------------------------------------------------- Constructors
44
45
46     protected CoyoteOutputStream(OutputBuffer ob) {
47         this.ob = ob;
48     }
49
50
51     // --------------------------------------------------------- Public Methods
52
53
54     /**
55      * Prevent cloning the facade.
56      */

57     @Override
58     protected Object clone() throws CloneNotSupportedException {
59         throw new CloneNotSupportedException();
60     }
61
62
63     // -------------------------------------------------------- Package Methods
64
65
66     /**
67      * Clear facade.
68      */

69     void clear() {
70         ob = null;
71     }
72
73
74     // --------------------------------------------------- OutputStream Methods
75
76
77     @Override
78     public void write(int i) throws IOException {
79         boolean nonBlocking = checkNonBlockingWrite();
80         ob.writeByte(i);
81         if (nonBlocking) {
82             checkRegisterForWrite();
83         }
84     }
85
86
87     @Override
88     public void write(byte[] b) throws IOException {
89         write(b, 0, b.length);
90     }
91
92
93     @Override
94     public void write(byte[] b, int off, int len) throws IOException {
95         boolean nonBlocking = checkNonBlockingWrite();
96         ob.write(b, off, len);
97         if (nonBlocking) {
98             checkRegisterForWrite();
99         }
100     }
101
102
103     public void write(ByteBuffer from) throws IOException {
104         boolean nonBlocking = checkNonBlockingWrite();
105         ob.write(from);
106         if (nonBlocking) {
107             checkRegisterForWrite();
108         }
109     }
110
111
112     /**
113      * Will send the buffer to the client.
114      */

115     @Override
116     public void flush() throws IOException {
117         boolean nonBlocking = checkNonBlockingWrite();
118         ob.flush();
119         if (nonBlocking) {
120             checkRegisterForWrite();
121         }
122     }
123
124
125     /**
126      * Checks for concurrent writes which are not permitted. This object has no
127      * state information so the call chain is
128      * CoyoteOutputStream->OutputBuffer->CoyoteResponse.
129      *
130      * @return <code>true</code> if this OutputStream is currently in
131      *         non-blocking mode.
132      */

133     private boolean checkNonBlockingWrite() {
134         boolean nonBlocking = !ob.isBlocking();
135         if (nonBlocking && !ob.isReady()) {
136             throw new IllegalStateException(sm.getString("coyoteOutputStream.nbNotready"));
137         }
138         return nonBlocking;
139     }
140
141
142     /**
143      * Checks to see if there is data left in the Coyote output buffers (NOT the
144      * servlet output buffer) and if so registers the associated socket for
145      * write so the buffers will be emptied. The container will take care of
146      * this. As far as the app is concerned, there is a non-blocking write in
147      * progress. It doesn't have visibility of whether the data is buffered in
148      * the socket buffer or the Coyote buffers.
149      */

150     private void checkRegisterForWrite() {
151         ob.checkRegisterForWrite();
152     }
153
154
155     @Override
156     public void close() throws IOException {
157         ob.close();
158     }
159
160     @Override
161     public boolean isReady() {
162         return ob.isReady();
163     }
164
165
166     @Override
167     public void setWriteListener(WriteListener listener) {
168         ob.setWriteListener(listener);
169     }
170 }
171
172