1 52 53 package com.go.teaservlet; 54 55 import java.io.IOException ; 56 import java.io.OutputStream ; 57 import java.io.Serializable ; 58 import java.util.Locale ; 59 import java.util.List ; 60 import java.util.ArrayList ; 61 import javax.servlet.http.HttpServletResponse ; 62 import javax.servlet.http.Cookie ; 63 import com.go.teaservlet.io.CharToByteBuffer; 64 import com.go.teaservlet.io.DefaultCharToByteBuffer; 65 import com.go.teaservlet.io.InternedCharToByteBuffer; 66 import com.go.trove.io.ByteData; 67 import com.go.trove.io.ByteBuffer; 68 import com.go.trove.io.DefaultByteBuffer; 69 import com.go.trove.io.ByteBufferOutputStream; 70 import com.go.trove.util.Deflater; 71 import com.go.trove.util.DeflaterPool; 72 import com.go.trove.util.DeflaterOutputStream; 73 import com.go.trove.log.Log; 74 import com.go.tea.runtime.Substitution; 75 76 82 class DetachedResponseImpl extends ApplicationResponseImpl { 83 private static final int MINIMUM_SIZE = 100; 85 86 static ByteData compressByteData(ByteData original, int level) { 87 ByteBuffer compressed = new DefaultByteBuffer(); 88 OutputStream cout = new ByteBufferOutputStream(compressed); 89 90 try { 91 if (original.getByteCount() < MINIMUM_SIZE) { 92 level = Deflater.NO_COMPRESSION; 93 } 94 95 Deflater d = DeflaterPool.get(level, true); 96 97 DeflaterOutputStream dout = new DeflaterOutputStream(cout, d, 512); 98 original.writeTo(dout); 99 dout.fullFlush(); 100 101 DeflaterPool.put(d); 102 } 103 catch (IOException e) { 104 throw new InternalError (e.toString()); 105 } 106 107 return compressed; 108 } 109 110 private final SwappableBuffer mSwappableBuffer; 111 private final Data mData; 112 113 DetachedResponseImpl(HttpServletResponse response, Log log) 114 throws IOException 115 { 116 this(response, log, new SwappableBuffer()); 117 } 118 119 private DetachedResponseImpl(HttpServletResponse response, 120 Log log, 121 SwappableBuffer sb) 122 throws IOException 123 { 124 super(response, log, sb); 125 sb.setBuffer(new DefaultByteBuffer()); 126 mSwappableBuffer = sb; 127 mData = new Data(); 128 mData.addCommand(new AddByteData(sb.mBuffer)); 129 } 130 131 DetachedData getData() throws IOException { 132 drain(); 133 return mData; 134 } 135 136 public void setContentType(String type) { 137 try { 138 mBuffer.setEncoding(getCharacterEncoding()); 139 mData.addCommand(new SetContentType(type)); 140 } 141 catch (IOException e) { 142 Thread t = Thread.currentThread(); 143 t.getThreadGroup().uncaughtException(t, e); 144 } 145 } 146 147 public void reset() { 148 } 150 151 public void setLocale(Locale locale) { 152 getHttpContext().setLocale(locale); 153 } 154 155 public void addCookie(Cookie cookie) { 156 mData.addCommand(new AddCookie(cookie)); 157 } 158 159 public void sendError(int statusCode, String msg) throws IOException { 160 mState |= 1; 161 mData.addCommand(new SendError(statusCode, msg)); 162 } 163 164 public void sendError(int statusCode) throws IOException { 165 mState |= 1; 166 mData.addCommand(new SendError(statusCode, null)); 167 } 168 169 public void sendRedirect(String location) throws IOException { 170 mState |= 1; 171 mData.addCommand(new SendRedirect(location)); 172 } 173 174 public void setHeader(String name, String value) { 175 mData.addCommand(new SetHeader(name, value)); 176 } 177 178 public void setDateHeader(String name, long date) { 179 mData.addCommand(new SetHeader(name, new Long (date))); 180 } 181 182 public void setIntHeader(String name, int value) { 183 mData.addCommand(new SetHeader(name, new Integer (value))); 184 } 185 186 public void addHeader(String name, String value) { 187 mData.addCommand(new AddHeader(name, value)); 188 } 189 190 public void addDateHeader(String name, long date) { 191 mData.addCommand(new AddHeader(name, new Long (date))); 192 } 193 194 public void addIntHeader(String name, int value) { 195 mData.addCommand(new AddHeader(name, new Integer (value))); 196 } 197 198 public void setStatus(int sc) { 199 mData.addCommand(new SetStatus(sc, null)); 200 } 201 202 205 public void setStatus(int sc, String msg) { 206 mData.addCommand(new SetStatus(sc, msg)); 207 } 208 209 public boolean insertCommand(Command command) throws Exception { 210 mData.addCommand(command); 211 addByteDataCommand(); 212 return true; 213 } 214 215 public void finish() { 216 } 218 219 private void addByteDataCommand() throws IOException { 220 drain(); 221 ByteBuffer bb = new DefaultByteBuffer(); 222 mSwappableBuffer.setBuffer(bb); 223 mData.addCommand(new AddByteData(bb)); 224 } 225 226 private void drain() throws IOException { 227 if (mBuffer != null) { 228 mBuffer.drain(); 229 } 230 } 231 232 private static class SwappableBuffer implements ByteBuffer { 234 private ByteBuffer mBuffer; 235 236 SwappableBuffer() { 237 } 238 239 public void setBuffer(ByteBuffer bb) { 240 mBuffer = bb; 241 } 242 243 public long getByteCount() throws IOException { 244 return mBuffer.getByteCount(); 245 } 246 247 public void writeTo(OutputStream out) throws IOException { 248 mBuffer.writeTo(out); 249 } 250 251 public void reset() throws IOException { 252 mBuffer.reset(); 253 } 254 255 public long getBaseByteCount() throws IOException { 256 return mBuffer.getBaseByteCount(); 257 } 258 259 public void append(byte b) throws IOException { 260 mBuffer.append(b); 261 } 262 263 public void append(byte[] bytes) throws IOException { 264 mBuffer.append(bytes); 265 } 266 267 public void append(byte[] bytes, int offset, int length) 268 throws IOException 269 { 270 mBuffer.append(bytes, offset, length); 271 } 272 273 public void appendSurrogate(com.go.trove.io.ByteData s) 274 throws IOException 275 { 276 mBuffer.appendSurrogate(s); 277 } 278 279 public void addCaptureBuffer(com.go.trove.io.ByteBuffer buffer) 280 throws IOException 281 { 282 mBuffer.addCaptureBuffer(buffer); 283 } 284 285 public void removeCaptureBuffer(com.go.trove.io.ByteBuffer buffer) 286 throws IOException 287 { 288 mBuffer.removeCaptureBuffer(buffer); 289 } 290 } 291 292 private static class Data implements DetachedData, Serializable { 293 private List mCommands; 294 private boolean mCompressed; 295 296 public void playback(ApplicationRequest request, 297 ApplicationResponse response) throws Exception { 298 if (mCommands != null) { 299 int size = mCommands.size(); 300 for (int i=0; i<size; i++) { 301 ((Command)mCommands.get(i)).execute(request, response); 302 } 303 } 304 } 305 306 public void compress() { 307 compress(Deflater.DEFAULT_COMPRESSION); 308 } 309 310 public synchronized void compress(int level) { 311 if (!mCompressed) { 312 mCompressed = true; 313 List commands = mCommands; 314 int size = commands.size(); 315 316 enough: { 318 for (int i=0; i<size; i++) { 319 Object command = commands.get(i); 320 if (command instanceof AddByteData) { 321 ByteData bytes = ((AddByteData)command).mBytes; 322 try { 323 if (bytes.getByteCount() >= MINIMUM_SIZE) { 324 break enough; 325 } 326 } 327 catch (IOException e) { 328 throw new InternalError (e.toString()); 329 } 330 } 331 } 332 333 return; 335 } 336 337 for (int i=0; i<size; i++) { 338 Object command = commands.get(i); 339 if (command instanceof AddByteData) { 340 ByteData original = ((AddByteData)command).mBytes; 341 try { 342 if (original.getByteCount() > 0) { 343 command = new CompressedByteData 344 (compressByteData(original, level), 345 original); 346 mCommands.set(i, command); 347 } 348 } 349 catch (IOException e) { 350 throw new InternalError (e.toString()); 351 } 352 } 353 } 354 } 355 } 356 357 void addCommand(Command c) { 358 if (mCommands == null) { 359 mCommands = new ArrayList (); 360 } 361 mCommands.add(c); 362 } 363 } 364 365 private static class SetContentType implements Command, Serializable { 366 private final String mContentType; 367 368 SetContentType(String type) { 369 mContentType = type; 370 } 371 372 public void execute(ApplicationRequest request, 373 ApplicationResponse response) { 374 response.setContentType(mContentType); 375 } 376 } 377 378 private static class AddCookie implements Command, Serializable { 379 private transient Cookie mCookie; 380 381 AddCookie(Cookie cookie) { 382 mCookie = cookie; 383 } 384 385 public void execute(ApplicationRequest request, 386 ApplicationResponse response) { 387 response.addCookie(mCookie); 388 } 389 390 private void writeObject(java.io.ObjectOutputStream out) 391 throws IOException 392 { 393 out.writeUTF(mCookie.getName()); 394 out.writeUTF(mCookie.getValue()); 395 out.writeUTF(mCookie.getComment()); 396 out.writeUTF(mCookie.getDomain()); 397 out.writeInt(mCookie.getMaxAge()); 398 out.writeUTF(mCookie.getPath()); 399 out.writeBoolean(mCookie.getSecure()); 400 out.writeInt(mCookie.getVersion()); 401 } 402 403 private void readObject(java.io.ObjectInputStream in) 404 throws IOException , ClassNotFoundException 405 { 406 mCookie = new Cookie (in.readUTF(), in.readUTF()); 407 mCookie.setComment(in.readUTF()); 408 mCookie.setDomain(in.readUTF()); 409 mCookie.setMaxAge(in.readInt()); 410 mCookie.setPath(in.readUTF()); 411 mCookie.setSecure(in.readBoolean()); 412 mCookie.setVersion(in.readInt()); 413 } 414 } 415 416 private static class SetHeader implements Command, Serializable { 417 protected final String mName; 418 protected final Object mValue; 419 420 SetHeader(String name, Object value) { 421 mName = name; 422 mValue = value; 423 } 424 425 public void execute(ApplicationRequest request, 426 ApplicationResponse response) { 427 if (mValue instanceof String ) { 428 response.setHeader(mName, (String )mValue); 429 } 430 else if (mValue instanceof Long ) { 431 response.setDateHeader(mName, ((Long )mValue).longValue()); 432 } 433 else { 434 response.setIntHeader(mName, ((Integer )mValue).intValue()); 435 } 436 } 437 } 438 439 private static class AddHeader extends SetHeader 440 implements Command, Serializable 441 { 442 AddHeader(String name, Object value) { 443 super(name, value); 444 } 445 446 public void execute(ApplicationRequest request, 447 ApplicationResponse response) { 448 if (mValue instanceof String ) { 449 response.addHeader(mName, (String )mValue); 450 } 451 else if (mValue instanceof Long ) { 452 response.addDateHeader(mName, ((Long )mValue).longValue()); 453 } 454 else { 455 response.addIntHeader(mName, ((Integer )mValue).intValue()); 456 } 457 } 458 } 459 460 private static class SetStatus implements Command, Serializable { 461 protected final int mCode; 462 protected final String mMessage; 463 464 SetStatus(int code, String message) { 465 mCode = code; 466 mMessage = message; 467 } 468 469 public void execute(ApplicationRequest request, 470 ApplicationResponse response) throws IOException { 471 if (mMessage == null) { 472 response.setStatus(mCode); 473 } 474 else { 475 response.setStatus(mCode, mMessage); 476 } 477 } 478 } 479 480 private static class SendError extends SetStatus 481 implements Command, Serializable 482 { 483 SendError(int code, String message) { 484 super(code, message); 485 } 486 487 public void execute(ApplicationRequest request, 488 ApplicationResponse response) throws IOException { 489 if (mMessage == null) { 490 response.sendError(mCode); 491 } 492 else { 493 response.sendError(mCode, mMessage); 494 } 495 } 496 } 497 498 private static class SendRedirect implements Command, Serializable { 499 private final String mLocation; 500 501 SendRedirect(String location) { 502 mLocation = location; 503 } 504 505 public void execute(ApplicationRequest request, 506 ApplicationResponse response) throws IOException { 507 response.sendRedirect(mLocation); 508 } 509 } 510 511 private static class AddByteData implements Command, Serializable { 512 final ByteData mBytes; 513 514 AddByteData(ByteData bytes) { 515 mBytes = bytes; 516 } 517 518 public void execute(ApplicationRequest request, 519 ApplicationResponse response) throws IOException { 520 response.getResponseBuffer().appendSurrogate(mBytes); 521 } 522 } 523 524 private static class CompressedByteData implements Command, Serializable { 525 private final ByteData mCompressed; 526 private final ByteData mOriginal; 527 528 CompressedByteData(ByteData compressed, ByteData original) { 529 mCompressed = compressed; 530 mOriginal = original; 531 } 532 533 public void execute(ApplicationRequest request, 534 ApplicationResponse response) throws IOException { 535 536 if (request.isCompressionAccepted()) { 537 try { 538 ApplicationResponseImpl impl = 539 (ApplicationResponseImpl)response; 540 impl.appendCompressed(mCompressed, mOriginal); 541 return; 542 } 543 catch (ClassCastException e) { 544 } 545 } 546 547 response.getResponseBuffer().appendSurrogate(mOriginal); 548 } 549 } 550 } 551 | Popular Tags |