1 // ========================================================================
2 // Copyright (c) 2008-2009 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // All rights reserved. This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v1.0
6 // and Apache License v2.0 which accompanies this distribution.
7 // The Eclipse Public License is available at
8 // http://www.eclipse.org/legal/epl-v10.html
9 // The Apache License v2.0 is available at
10 // http://www.opensource.org/licenses/apache2.0.php
11 // You may elect to redistribute this code under either of these licenses.
12 // ========================================================================
13
14 package org.eclipse.jetty.server;
15
16 import java.io.IOException;
17 import java.io.Writer;
18
19 import javax.servlet.ServletOutputStream;
20
21 import org.eclipse.jetty.http.AbstractGenerator;
22 import org.eclipse.jetty.http.Generator;
23 import org.eclipse.jetty.io.Buffer;
24 import org.eclipse.jetty.io.ByteArrayBuffer;
25 import org.eclipse.jetty.io.EofException;
26 import org.eclipse.jetty.util.ByteArrayOutputStream2;
27
28 /** Output.
29 *
30 * <p>
31 * Implements {@link javax.servlet.ServletOutputStream} from the <code>javax.servlet</code> package.
32 * </p>
33 * A {@link ServletOutputStream} implementation that writes content
34 * to a {@link AbstractGenerator}. The class is designed to be reused
35 * and can be reopened after a close.
36 */
37 public class HttpOutput extends ServletOutputStream
38 {
39 protected final AbstractHttpConnection _connection;
40 protected final AbstractGenerator _generator;
41 private boolean _closed;
42
43 // These are held here for reuse by Writer
44 String _characterEncoding;
45 Writer _converter;
46 char[] _chars;
47 ByteArrayOutputStream2 _bytes;
48
49 /* ------------------------------------------------------------ */
50 public HttpOutput(AbstractHttpConnection connection)
51 {
52 _connection=connection;
53 _generator=(AbstractGenerator)connection.getGenerator();
54 }
55
56 /* ------------------------------------------------------------ */
57 public int getMaxIdleTime()
58 {
59 return _connection.getMaxIdleTime();
60 }
61
62 /* ------------------------------------------------------------ */
63 public boolean isWritten()
64 {
65 return _generator.getContentWritten()>0;
66 }
67
68 /* ------------------------------------------------------------ */
69 /*
70 * @see java.io.OutputStream#close()
71 */
72 @Override
73 public void close() throws IOException
74 {
75 _closed=true;
76 }
77
78 /* ------------------------------------------------------------ */
79 public boolean isClosed()
80 {
81 return _closed;
82 }
83
84 /* ------------------------------------------------------------ */
85 public void reopen()
86 {
87 _closed=false;
88 }
89
90 /* ------------------------------------------------------------ */
91 @Override
92 public void flush() throws IOException
93 {
94 _generator.flush(getMaxIdleTime());
95 }
96
97 /* ------------------------------------------------------------ */
98 @Override
99 public void write(byte[] b, int off, int len) throws IOException
100 {
101 write(new ByteArrayBuffer(b,off,len));
102 }
103
104 /* ------------------------------------------------------------ */
105 /*
106 * @see java.io.OutputStream#write(byte[])
107 */
108 @Override
109 public void write(byte[] b) throws IOException
110 {
111 write(new ByteArrayBuffer(b));
112 }
113
114 /* ------------------------------------------------------------ */
115 /*
116 * @see java.io.OutputStream#write(int)
117 */
118 @Override
119 public void write(int b) throws IOException
120 {
121 if (_closed)
122 throw new IOException("Closed");
123 if (!_generator.isOpen())
124 throw new EofException();
125
126 // Block until we can add _content.
127 while (_generator.isBufferFull())
128 {
129 _generator.blockForOutput(getMaxIdleTime());
130 if (_closed)
131 throw new IOException("Closed");
132 if (!_generator.isOpen())
133 throw new EofException();
134 }
135
136 // Add the _content
137 if (_generator.addContent((byte)b))
138 // Buffers are full so commit.
139 _connection.commitResponse(Generator.MORE);
140
141 if (_generator.isAllContentWritten())
142 {
143 flush();
144 close();
145 }
146 }
147
148 /* ------------------------------------------------------------ */
149 private void write(Buffer buffer) throws IOException
150 {
151 if (_closed)
152 throw new IOException("Closed");
153 if (!_generator.isOpen())
154 throw new EofException();
155
156 // Block until we can add _content.
157 while (_generator.isBufferFull())
158 {
159 _generator.blockForOutput(getMaxIdleTime());
160 if (_closed)
161 throw new IOException("Closed");
162 if (!_generator.isOpen())
163 throw new EofException();
164 }
165
166 // Add the _content
167 _generator.addContent(buffer, Generator.MORE);
168
169 // Have to flush and complete headers?
170
171 if (_generator.isAllContentWritten())
172 {
173 flush();
174 close();
175 }
176 else if (_generator.isBufferFull())
177 _connection.commitResponse(Generator.MORE);
178
179 // Block until our buffer is free
180 while (buffer.length() > 0 && _generator.isOpen())
181 {
182 _generator.blockForOutput(getMaxIdleTime());
183 }
184 }
185
186 /* ------------------------------------------------------------ */
187 /*
188 * @see javax.servlet.ServletOutputStream#print(java.lang.String)
189 */
190 @Override
191 public void print(String s) throws IOException
192 {
193 write(s.getBytes());
194 }
195 }