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 AbstractGenerator _generator;
40 protected final long _maxIdleTime;
41 protected final ByteArrayBuffer _buf = new ByteArrayBuffer(AbstractGenerator.NO_BYTES);
42 private boolean _closed;
43
44 // These are held here for reuse by Writer
45 String _characterEncoding;
46 Writer _converter;
47 char[] _chars;
48 ByteArrayOutputStream2 _bytes;
49
50
51 /* ------------------------------------------------------------ */
52 public HttpOutput(AbstractGenerator generator, long maxIdleTime)
53 {
54 _generator=generator;
55 _maxIdleTime=maxIdleTime;
56 }
57
58 /* ------------------------------------------------------------ */
59 public boolean isWritten()
60 {
61 return _generator.getContentWritten()>0;
62 }
63
64 /* ------------------------------------------------------------ */
65 /*
66 * @see java.io.OutputStream#close()
67 */
68 @Override
69 public void close() throws IOException
70 {
71 _closed=true;
72 }
73
74 /* ------------------------------------------------------------ */
75 public boolean isClosed()
76 {
77 return _closed;
78 }
79
80 /* ------------------------------------------------------------ */
81 public void reopen()
82 {
83 _closed=false;
84 }
85
86 /* ------------------------------------------------------------ */
87 @Override
88 public void flush() throws IOException
89 {
90 _generator.flush(_maxIdleTime);
91 }
92
93 /* ------------------------------------------------------------ */
94 @Override
95 public void write(byte[] b, int off, int len) throws IOException
96 {
97 write(new ByteArrayBuffer(b,off,len));
98 }
99
100 /* ------------------------------------------------------------ */
101 /*
102 * @see java.io.OutputStream#write(byte[])
103 */
104 @Override
105 public void write(byte[] b) throws IOException
106 {
107 write(new ByteArrayBuffer(b));
108 }
109
110 /* ------------------------------------------------------------ */
111 /*
112 * @see java.io.OutputStream#write(int)
113 */
114 @Override
115 public void write(int b) throws IOException
116 {
117 if (_closed)
118 throw new IOException("Closed");
119 if (!_generator.isOpen())
120 throw new EofException();
121
122 // Block until we can add _content.
123 while (_generator.isBufferFull())
124 {
125 _generator.blockForOutput(_maxIdleTime);
126 if (_closed)
127 throw new IOException("Closed");
128 if (!_generator.isOpen())
129 throw new EofException();
130 }
131
132 // Add the _content
133 if (_generator.addContent((byte)b))
134 // Buffers are full so flush.
135 flush();
136
137 if (_generator.isAllContentWritten())
138 {
139 flush();
140 close();
141 }
142 }
143
144 /* ------------------------------------------------------------ */
145 private void write(Buffer buffer) throws IOException
146 {
147 if (_closed)
148 throw new IOException("Closed");
149 if (!_generator.isOpen())
150 throw new EofException();
151
152 // Block until we can add _content.
153 while (_generator.isBufferFull())
154 {
155 _generator.blockForOutput(_maxIdleTime);
156 if (_closed)
157 throw new IOException("Closed");
158 if (!_generator.isOpen())
159 throw new EofException();
160 }
161
162 // Add the _content
163 _generator.addContent(buffer, Generator.MORE);
164
165 // Have to flush and complete headers?
166
167 if (_generator.isAllContentWritten())
168 {
169 flush();
170 close();
171 }
172 else if (_generator.isBufferFull())
173 flush();
174
175 // Block until our buffer is free
176 while (buffer.length() > 0 && _generator.isOpen())
177 {
178 _generator.blockForOutput(_maxIdleTime);
179 }
180 }
181
182 /* ------------------------------------------------------------ */
183 /*
184 * @see javax.servlet.ServletOutputStream#print(java.lang.String)
185 */
186 @Override
187 public void print(String s) throws IOException
188 {
189 write(s.getBytes());
190 }
191 }