1 7 package winstone; 8 9 import java.io.ByteArrayOutputStream ; 10 import java.io.IOException ; 11 import java.io.OutputStream ; 12 import java.util.Iterator ; 13 import java.util.Stack ; 14 15 import javax.servlet.http.Cookie ; 16 17 23 public class WinstoneOutputStream extends javax.servlet.ServletOutputStream { 24 private static final int DEFAULT_BUFFER_SIZE = 8192; 25 private static final byte[] CR_LF = "\r\n".getBytes(); 26 protected OutputStream outStream; 27 protected int bufferSize; 28 protected int bufferPosition; 29 protected int bytesCommitted; 30 protected ByteArrayOutputStream buffer; 31 protected boolean committed; 32 protected boolean bodyOnly; 33 protected WinstoneResponse owner; 34 protected boolean disregardMode = false; 35 protected boolean closed = false; 36 protected Stack includeByteStreams; 37 38 41 public WinstoneOutputStream(OutputStream out, boolean bodyOnlyForInclude) { 42 this.outStream = out; 43 this.bodyOnly = bodyOnlyForInclude; 44 this.bufferSize = DEFAULT_BUFFER_SIZE; 45 this.committed = false; 46 this.buffer = new ByteArrayOutputStream (); 48 } 49 50 public void setResponse(WinstoneResponse response) { 51 this.owner = response; 52 } 53 54 public int getBufferSize() { 55 return this.bufferSize; 56 } 57 58 public void setBufferSize(int bufferSize) { 59 if (this.owner.isCommitted()) { 60 throw new IllegalStateException (Launcher.RESOURCES.getString( 61 "WinstoneOutputStream.AlreadyCommitted")); 62 } 63 this.bufferSize = bufferSize; 64 } 65 66 public boolean isCommitted() { 67 return this.committed; 68 } 69 70 public int getOutputStreamLength() { 71 return this.bytesCommitted + this.bufferPosition; 72 } 73 74 public int getBytesCommitted() { 75 return this.bytesCommitted; 76 } 77 78 public void setDisregardMode(boolean disregard) { 79 this.disregardMode = disregard; 80 } 81 82 public void setClosed(boolean closed) { 83 this.closed = closed; 84 } 85 86 public void write(int oneChar) throws IOException { 87 if (this.disregardMode || this.closed) { 88 return; 89 } 90 String contentLengthHeader = this.owner.getHeader(WinstoneResponse.CONTENT_LENGTH_HEADER); 91 if ((contentLengthHeader != null) && 92 (this.bytesCommitted >= Integer.parseInt(contentLengthHeader))) { 93 return; 94 } 95 this.buffer.write(oneChar); 97 this.bufferPosition++; 98 if (this.bufferPosition >= this.bufferSize) { 100 commit(); 101 } else if ((contentLengthHeader != null) && 102 ((this.bufferPosition + this.bytesCommitted) 103 >= Integer.parseInt(contentLengthHeader))) { 104 commit(); 105 } 106 } 107 108 public void commit() throws IOException { 109 this.buffer.flush(); 110 111 if (!this.committed && !this.bodyOnly) { 113 this.owner.validateHeaders(); 114 this.committed = true; 115 116 Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WinstoneOutputStream.CommittingOutputStream"); 117 118 String statusLine = this.owner.getProtocol() + " " + this.owner.getStatus(); 119 this.outStream.write(statusLine.getBytes("8859_1")); 120 this.outStream.write(CR_LF); 121 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 122 "WinstoneOutputStream.ResponseStatus", statusLine); 123 124 for (Iterator i = this.owner.getHeaders().iterator(); i.hasNext();) { 126 String header = (String ) i.next(); 127 this.outStream.write(header.getBytes("8859_1")); 128 this.outStream.write(CR_LF); 129 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 130 "WinstoneOutputStream.Header", header); 131 } 132 133 if (!this.owner.getHeaders().isEmpty()) { 134 for (Iterator i = this.owner.getCookies().iterator(); i.hasNext();) { 135 Cookie cookie = (Cookie ) i.next(); 136 String cookieText = this.owner.writeCookie(cookie); 137 this.outStream.write(cookieText.getBytes("8859_1")); 138 this.outStream.write(CR_LF); 139 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 140 "WinstoneOutputStream.Header", cookieText); 141 } 142 } 143 this.outStream.write(CR_LF); 144 this.outStream.flush(); 145 } 148 byte content[] = this.buffer.toByteArray(); 149 int commitLength = content.length; 152 String contentLengthHeader = this.owner.getHeader(WinstoneResponse.CONTENT_LENGTH_HEADER); 153 if (contentLengthHeader != null) { 154 commitLength = Math.min(Integer.parseInt(contentLengthHeader) 155 - this.bytesCommitted, content.length); 156 } 157 if (commitLength > 0) { 158 this.outStream.write(content, 0, commitLength); 159 } 160 this.outStream.flush(); 161 162 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 163 "WinstoneOutputStream.CommittedBytes", 164 "" + (this.bytesCommitted + commitLength)); 165 166 this.bytesCommitted += commitLength; 167 this.buffer.reset(); 168 this.bufferPosition = 0; 169 } 170 171 public void reset() { 172 if (isCommitted()) 173 throw new IllegalStateException (Launcher.RESOURCES 174 .getString("WinstoneOutputStream.AlreadyCommitted")); 175 else { 176 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 177 "WinstoneOutputStream.ResetBuffer", this.bufferPosition 178 + ""); 179 this.buffer.reset(); 180 this.bufferPosition = 0; 181 this.bytesCommitted = 0; 182 } 183 } 184 185 public void finishResponse() throws IOException { 186 this.outStream.flush(); 187 this.outStream = null; 188 } 189 190 public void flush() throws IOException { 191 if (this.disregardMode) { 192 return; 193 } 194 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WinstoneOutputStream.Flushing"); 195 this.buffer.flush(); 196 this.commit(); 197 } 198 199 public void close() throws IOException { 200 if (!isCommitted() && !this.disregardMode && !this.closed && 201 (this.owner.getHeader(WinstoneResponse.CONTENT_LENGTH_HEADER) == null)) { 202 if ((this.owner != null) && !this.bodyOnly) { 203 this.owner.setContentLength(getOutputStreamLength()); 204 } 205 } 206 flush(); 207 } 208 209 public boolean isIncluding() { 211 return (this.includeByteStreams != null && !this.includeByteStreams.isEmpty()); 212 } 213 214 public void startIncludeBuffer() { 215 synchronized (this.buffer) { 216 if (this.includeByteStreams == null) { 217 this.includeByteStreams = new Stack (); 218 } 219 } 220 this.includeByteStreams.push(new ByteArrayOutputStream ()); 221 } 222 223 public void finishIncludeBuffer() throws IOException { 224 if (isIncluding()) { 225 ByteArrayOutputStream body = (ByteArrayOutputStream ) this.includeByteStreams.pop(); 226 OutputStream topStream = this.outStream; 227 if (!this.includeByteStreams.isEmpty()) { 228 topStream = (OutputStream ) this.includeByteStreams.peek(); 229 } 230 byte bodyArr[] = body.toByteArray(); 231 if (bodyArr.length > 0) { 232 topStream.write(bodyArr); 233 } 234 body.close(); 235 } 236 } 237 238 public void clearIncludeStackForForward() throws IOException { 239 if (isIncluding()) { 240 for (Iterator i = this.includeByteStreams.iterator(); i.hasNext(); ) { 241 ((ByteArrayOutputStream ) i.next()).close(); 242 } 243 this.includeByteStreams.clear(); 244 } 245 } 246 } 247 | Popular Tags |