1 16 17 package org.apache.coyote.tomcat4; 18 19 import java.io.IOException ; 20 import java.io.Writer ; 21 import java.util.Hashtable ; 22 23 import org.apache.catalina.connector.ClientAbortException; 24 import org.apache.coyote.ActionCode; 25 import org.apache.coyote.Response; 26 import org.apache.tomcat.util.buf.ByteChunk; 27 import org.apache.tomcat.util.buf.C2BConverter; 28 import org.apache.tomcat.util.buf.CharChunk; 29 30 31 39 public class OutputBuffer extends Writer 40 implements ByteChunk.ByteOutputChannel, CharChunk.CharOutputChannel { 41 42 43 private static org.apache.commons.logging.Log log= 44 org.apache.commons.logging.LogFactory.getLog( OutputBuffer.class ); 45 46 48 49 public static final String DEFAULT_ENCODING = 50 org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING; 51 public static final int DEFAULT_BUFFER_SIZE = 8*1024; 52 static final int debug = 0; 53 54 55 public final int INITIAL_STATE = 0; 59 public final int CHAR_STATE = 1; 60 public final int BYTE_STATE = 2; 61 62 63 65 66 69 private ByteChunk bb; 70 71 72 75 private CharChunk cb; 76 77 78 81 private int state = 0; 82 83 84 87 private int bytesWritten = 0; 88 89 90 93 private int charsWritten = 0; 94 95 96 99 private boolean closed = false; 100 101 102 105 private boolean doFlush = false; 106 107 108 111 private ByteChunk outputChunk = new ByteChunk(); 112 113 114 117 private String enc; 118 119 120 123 private boolean gotEnc = false; 124 125 126 129 protected Hashtable encoders = new Hashtable (); 130 131 132 135 protected C2BConverter conv; 136 137 138 141 private Response coyoteResponse; 142 143 144 147 private boolean suspended = false; 148 149 150 152 153 156 public OutputBuffer() { 157 158 this(DEFAULT_BUFFER_SIZE); 159 160 } 161 162 163 168 public OutputBuffer(int size) { 169 170 bb = new ByteChunk(size); 171 bb.setLimit(size); 172 bb.setByteOutputChannel(this); 173 cb = new CharChunk(size); 174 cb.setCharOutputChannel(this); 175 cb.setLimit(size); 176 177 } 178 179 180 182 183 188 public void setResponse(Response coyoteResponse) { 189 this.coyoteResponse = coyoteResponse; 190 } 191 192 193 198 public Response getResponse() { 199 return this.coyoteResponse; 200 } 201 202 203 208 public boolean isSuspended() { 209 return this.suspended; 210 } 211 212 213 218 public void setSuspended(boolean suspended) { 219 this.suspended = suspended; 220 } 221 222 223 225 226 229 public void recycle() { 230 231 if (debug > 0) 232 log("recycle()"); 233 234 state = INITIAL_STATE; 235 bytesWritten = 0; 236 charsWritten = 0; 237 238 cb.recycle(); 239 bb.recycle(); 240 closed = false; 241 suspended = false; 242 243 if (conv!= null) { 244 conv.recycle(); 245 } 246 247 gotEnc = false; 248 enc = null; 249 250 } 251 252 253 259 public void close() 260 throws IOException { 261 262 if (closed) 263 return; 264 if (suspended) 265 return; 266 267 if ((!coyoteResponse.isCommitted()) 268 && (coyoteResponse.getContentLengthLong() == -1)) { 269 if (state == CHAR_STATE) { 271 cb.flushBuffer(); 272 state = BYTE_STATE; 273 } 274 if (!coyoteResponse.isCommitted()) { 277 coyoteResponse.setContentLength(bb.getLength()); 278 } 279 } 280 281 doFlush(false); 282 closed = true; 283 284 coyoteResponse.finish(); 285 286 } 287 288 289 294 public void flush() 295 throws IOException { 296 doFlush(true); 297 } 298 299 300 305 protected void doFlush(boolean realFlush) 306 throws IOException { 307 308 if (suspended) 309 return; 310 311 doFlush = true; 312 if (state == CHAR_STATE) { 313 cb.flushBuffer(); 314 bb.flushBuffer(); 315 state = BYTE_STATE; 316 } else if (state == BYTE_STATE) { 317 bb.flushBuffer(); 318 } else if (state == INITIAL_STATE) 319 realWriteBytes(null, 0, 0); doFlush = false; 321 322 if (realFlush) { 323 coyoteResponse.action(ActionCode.ACTION_CLIENT_FLUSH, 324 coyoteResponse); 325 if (coyoteResponse.isExceptionPresent()) { 328 throw new ClientAbortException 329 (coyoteResponse.getErrorException()); 330 } 331 } 332 333 } 334 335 336 338 339 349 public void realWriteBytes(byte buf[], int off, int cnt) 350 throws IOException { 351 352 if (debug > 2) 353 log("realWrite(b, " + off + ", " + cnt + ") " + coyoteResponse); 354 355 if (closed) 356 return; 357 if (coyoteResponse == null) 358 return; 359 360 if (cnt > 0) { 362 outputChunk.setBytes(buf, off, cnt); 364 try { 365 coyoteResponse.doWrite(outputChunk); 366 } catch (IOException e) { 367 throw new ClientAbortException(e); 371 } 372 } 373 374 } 375 376 377 public void write(byte b[], int off, int len) throws IOException { 378 379 if (suspended) 380 return; 381 382 if (state == CHAR_STATE) 383 cb.flushBuffer(); 384 state = BYTE_STATE; 385 writeBytes(b, off, len); 386 387 } 388 389 390 private void writeBytes(byte b[], int off, int len) 391 throws IOException { 392 393 if (closed) 394 return; 395 if (debug > 0) 396 log("write(b,off,len)"); 397 398 bb.append(b, off, len); 399 bytesWritten += len; 400 401 if (doFlush) { 404 bb.flushBuffer(); 405 } 406 407 } 408 409 410 public void writeByte(int b) 412 throws IOException { 413 414 if (suspended) 415 return; 416 417 if (state == CHAR_STATE) 418 cb.flushBuffer(); 419 state = BYTE_STATE; 420 421 if (debug > 0) 422 log("write(b)"); 423 424 bb.append( (byte)b ); 425 bytesWritten++; 426 427 } 428 429 430 432 433 public void write(int c) 434 throws IOException { 435 436 if (suspended) 437 return; 438 439 state = CHAR_STATE; 440 441 if (debug > 0) 442 log("writeChar(b)"); 443 444 cb.append((char) c); 445 charsWritten++; 446 447 } 448 449 450 public void write(char c[]) 451 throws IOException { 452 453 if (suspended) 454 return; 455 456 write(c, 0, c.length); 457 458 } 459 460 461 public void write(char c[], int off, int len) 462 throws IOException { 463 464 if (suspended) 465 return; 466 467 state = CHAR_STATE; 468 469 if (debug > 0) 470 log("write(c,off,len)" + cb.getLength() + " " + cb.getLimit()); 471 472 cb.append(c, off, len); 473 charsWritten += len; 474 475 } 476 477 478 public void write(StringBuffer sb) 479 throws IOException { 480 481 if (suspended) 482 return; 483 484 state = CHAR_STATE; 485 486 if (debug > 1) 487 log("write(s,off,len)"); 488 489 int len = sb.length(); 490 charsWritten += len; 491 cb.append(sb); 492 493 } 494 495 496 499 public void write(String s, int off, int len) 500 throws IOException { 501 502 if (suspended) 503 return; 504 505 state=CHAR_STATE; 506 507 if (debug > 1) 508 log("write(s,off,len)"); 509 510 charsWritten += len; 511 if (s==null) 512 s="null"; 513 cb.append( s, off, len ); 514 515 } 516 517 518 public void write(String s) 519 throws IOException { 520 521 if (suspended) 522 return; 523 524 state = CHAR_STATE; 525 if (s==null) 526 s="null"; 527 write(s, 0, s.length()); 528 529 } 530 531 532 public void flushChars() 533 throws IOException { 534 535 if (debug > 0) 536 log("flushChars() " + cb.getLength()); 537 538 cb.flushBuffer(); 539 state = BYTE_STATE; 540 541 } 542 543 544 public boolean flushCharsNeeded() { 545 return state == CHAR_STATE; 546 } 547 548 549 public void setEncoding(String s) { 550 enc = s; 551 } 552 553 554 public void realWriteChars(char c[], int off, int len) 555 throws IOException { 556 557 if (debug > 0) 558 log("realWrite(c,o,l) " + cb.getOffset() + " " + len); 559 560 if (!gotEnc) 561 setConverter(); 562 563 if (debug > 0) 564 log("encoder: " + conv + " " + gotEnc); 565 566 conv.convert(c, off, len); 567 conv.flushBuffer(); 569 } 570 571 572 protected void setConverter() { 573 574 if (coyoteResponse != null) 575 enc = coyoteResponse.getCharacterEncoding(); 576 577 if (debug > 0) 578 log("Got encoding: " + enc); 579 580 gotEnc = true; 581 if (enc == null) 582 enc = DEFAULT_ENCODING; 583 conv = (C2BConverter) encoders.get(enc); 584 if (conv == null) { 585 try { 586 conv = new C2BConverter(bb, enc); 587 encoders.put(enc, conv); 588 } catch (IOException e) { 589 conv = (C2BConverter) encoders.get(DEFAULT_ENCODING); 590 if (conv == null) { 591 try { 592 conv = new C2BConverter(bb, DEFAULT_ENCODING); 593 encoders.put(DEFAULT_ENCODING, conv); 594 } catch (IOException ex) { 595 } 597 } 598 } 599 } 600 } 601 602 603 605 606 609 public void flushBytes() 610 throws IOException { 611 612 if (debug > 0) 613 log("flushBytes() " + bb.getLength()); 614 bb.flushBuffer(); 615 616 } 617 618 619 public int getBytesWritten() { 620 return bytesWritten; 621 } 622 623 624 public int getCharsWritten() { 625 return charsWritten; 626 } 627 628 629 public int getContentWritten() { 630 return bytesWritten + charsWritten; 631 } 632 633 634 638 public boolean isNew() { 639 return (bytesWritten == 0) && (charsWritten == 0); 640 } 641 642 643 public void setBufferSize(int size) { 644 if (size > bb.getLimit()) { bb.setLimit(size); 646 } 647 } 648 649 650 public void reset() { 651 652 bb.recycle(); 654 bytesWritten = 0; 655 cb.recycle(); 656 charsWritten = 0; 657 gotEnc = false; 658 enc = null; 659 660 } 661 662 663 public int getBufferSize() { 664 return bb.getLimit(); 665 } 666 667 668 669 protected void log( String s ) { 670 if (log.isDebugEnabled()) 671 log.debug("OutputBuffer: " + s); 672 } 673 674 675 } 676
| Popular Tags
|