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