1 31 32 package org.opencms.flex; 33 34 import org.opencms.main.CmsIllegalArgumentException; 35 import org.opencms.main.CmsLog; 36 import org.opencms.util.CmsDateUtil; 37 import org.opencms.util.CmsRequestUtil; 38 39 import java.io.BufferedWriter ; 40 import java.io.ByteArrayOutputStream ; 41 import java.io.IOException ; 42 import java.io.OutputStreamWriter ; 43 import java.io.PrintWriter ; 44 import java.util.ArrayList ; 45 import java.util.HashMap ; 46 import java.util.Iterator ; 47 import java.util.List ; 48 import java.util.Map ; 49 50 import javax.servlet.ServletOutputStream ; 51 import javax.servlet.http.Cookie ; 52 import javax.servlet.http.HttpServletResponse ; 53 import javax.servlet.http.HttpServletResponseWrapper ; 54 55 import org.apache.commons.logging.Log; 56 57 69 public class CmsFlexResponse extends HttpServletResponseWrapper { 70 71 78 private class CmsServletOutputStream extends ServletOutputStream { 79 80 81 private ServletOutputStream m_servletStream; 82 83 84 private ByteArrayOutputStream m_stream; 85 86 90 public CmsServletOutputStream() { 91 92 m_servletStream = null; 93 clear(); 94 } 95 96 102 public CmsServletOutputStream(ServletOutputStream servletStream) { 103 104 m_servletStream = servletStream; 105 clear(); 106 } 107 108 111 public void clear() { 112 113 m_stream = new java.io.ByteArrayOutputStream (1024); 114 } 115 116 119 public void close() throws IOException { 120 121 if (m_stream != null) { 122 m_stream.close(); 123 } 124 if (m_servletStream != null) { 125 m_servletStream.close(); 126 } 127 super.close(); 128 } 129 130 133 public void flush() throws IOException { 134 135 if (LOG.isDebugEnabled()) { 136 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXRESPONSE_FLUSHED_1, m_servletStream)); 137 } 138 if (m_servletStream != null) { 139 m_servletStream.flush(); 140 } 141 } 142 143 148 public byte[] getBytes() { 149 150 return m_stream.toByteArray(); 151 } 152 153 156 public void write(byte[] b, int off, int len) throws IOException { 157 158 m_stream.write(b, off, len); 159 if (m_servletStream != null) { 160 m_servletStream.write(b, off, len); 161 } 162 } 163 164 167 public void write(int b) throws IOException { 168 169 m_stream.write(b); 170 if (m_servletStream != null) { 171 m_servletStream.write(b); 172 } 173 } 174 175 182 public void writeToServletStream(byte[] b) throws IOException { 183 184 if (m_servletStream != null) { 185 m_servletStream.write(b); 186 } 187 } 188 } 189 190 191 public static final char FLEX_CACHE_DELIMITER = (char)0; 192 193 194 public static final String SET_HEADER = "[setHeader]"; 195 196 197 protected static final Log LOG = CmsLog.getLog(CmsFlexResponse.class); 198 199 200 private Map m_bufferHeaders; 201 202 203 private String m_bufferRedirect; 204 205 206 private byte[] m_cacheBytes; 207 208 209 private CmsFlexCacheEntry m_cachedEntry; 210 211 212 private boolean m_cachingRequired; 213 214 215 private CmsFlexController m_controller; 216 217 218 private String m_encoding; 219 220 221 private Map m_headers; 222 223 224 private List m_includeList; 225 226 227 private List m_includeListParameters; 228 229 230 private boolean m_includeMode; 231 232 233 private List m_includeResults; 234 235 236 private boolean m_isTopElement; 237 238 239 private CmsFlexCacheKey m_key; 240 241 242 private CmsFlexResponse.CmsServletOutputStream m_out; 243 244 245 private boolean m_parentWritesOnlyToBuffer; 246 247 248 private HttpServletResponse m_res; 249 250 251 private boolean m_suspended; 252 253 254 private boolean m_typeSet; 255 256 257 private boolean m_writeOnlyToBuffer; 258 259 260 private java.io.PrintWriter m_writer; 261 262 269 public CmsFlexResponse(HttpServletResponse res, CmsFlexController controller) { 270 271 super(res); 272 m_res = res; 273 m_controller = controller; 274 m_encoding = controller.getCurrentResponse().getEncoding(); 275 m_isTopElement = controller.getCurrentResponse().isTopElement(); 276 m_parentWritesOnlyToBuffer = controller.getCurrentResponse().hasIncludeList() && !controller.isForwardMode(); 277 setOnlyBuffering(m_parentWritesOnlyToBuffer); 278 m_headers = new HashMap (16); 279 m_bufferHeaders = new HashMap (8); 280 } 281 282 291 public CmsFlexResponse( 292 HttpServletResponse res, 293 CmsFlexController controller, 294 boolean streaming, 295 boolean isTopElement) { 296 297 super(res); 298 m_res = res; 299 m_controller = controller; 300 m_encoding = controller.getCmsObject().getRequestContext().getEncoding(); 301 m_isTopElement = isTopElement; 302 m_parentWritesOnlyToBuffer = !streaming && !controller.isForwardMode(); 303 setOnlyBuffering(m_parentWritesOnlyToBuffer); 304 m_headers = new HashMap (16); 305 m_bufferHeaders = new HashMap (8); 306 } 307 308 314 public static void processHeaders(Map headers, HttpServletResponse res) { 315 316 if (headers != null) { 317 Iterator i = headers.keySet().iterator(); 318 while (i.hasNext()) { 319 String key = (String )i.next(); 320 List l = (List )headers.get(key); 321 for (int j = 0; j < l.size(); j++) { 322 if ((j == 0) && (((String )l.get(0)).startsWith(SET_HEADER))) { 323 String s = (String )l.get(0); 324 res.setHeader(key, s.substring(SET_HEADER.length())); 325 } else { 326 res.addHeader(key, (String )l.get(j)); 327 } 328 } 329 } 330 } 331 } 332 333 341 public void addCookie(Cookie cookie) { 342 343 if (cookie == null) { 344 throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_ADD_COOKIE_0)); 345 } 346 347 StringBuffer header = new StringBuffer (128); 348 349 header.append(cookie.getName()); 351 header.append('='); 352 header.append(cookie.getValue()); 353 354 if (cookie.getVersion() == 1) { 356 header.append("; Version=1"); 357 358 if (cookie.getComment() != null) { 360 header.append("; Comment="); 361 header.append(cookie.getComment()); 362 } 363 } 364 365 if (cookie.getDomain() != null) { 367 header.append("; Domain="); 368 header.append(cookie.getDomain()); 369 } 370 371 if (cookie.getMaxAge() >= 0) { 373 if (cookie.getVersion() == 0) { 374 header.append("; Expires="); 376 long time; 377 if (cookie.getMaxAge() == 0) { 378 time = 10000L; 379 } else { 380 time = System.currentTimeMillis() + (cookie.getMaxAge() * 1000L); 381 } 382 header.append(CmsDateUtil.getOldCookieDate(time)); 383 } else { 384 header.append("; Max-Age="); 386 header.append(cookie.getMaxAge()); 387 } 388 } 389 390 if (cookie.getPath() != null) { 392 header.append("; Path="); 393 header.append(cookie.getPath()); 394 } 395 396 if (cookie.getSecure()) { 398 header.append("; Secure"); 399 } 400 401 addHeader("Set-Cookie", header.toString()); 402 } 403 404 409 public void addDateHeader(String name, long date) { 410 411 addHeader(name, CmsDateUtil.getHeaderDate(date)); 412 } 413 414 419 public void addHeader(String name, String value) { 420 421 if (isSuspended()) { 422 return; 423 } 424 425 if (CmsRequestUtil.HEADER_CONTENT_TYPE.equalsIgnoreCase(name)) { 426 setContentType(value); 427 return; 428 } 429 430 if (m_cachingRequired && !m_includeMode) { 431 addHeaderList(m_bufferHeaders, name, value); 432 if (LOG.isDebugEnabled()) { 433 LOG.debug(Messages.get().getBundle().key( 434 Messages.LOG_FLEXRESPONSE_ADDING_HEADER_TO_ELEMENT_BUFFER_2, 435 name, 436 value)); 437 } 438 } 439 440 if (m_writeOnlyToBuffer) { 441 addHeaderList(m_headers, name, value); 442 if (LOG.isDebugEnabled()) { 443 LOG.debug(Messages.get().getBundle().key( 444 Messages.LOG_FLEXRESPONSE_ADDING_HEADER_TO_HEADERS_2, 445 name, 446 value)); 447 } 448 } else { 449 if (LOG.isDebugEnabled()) { 450 LOG.debug(Messages.get().getBundle().key( 451 Messages.LOG_FLEXRESPONSE_ADDING_HEADER_TO_PARENT_RESPONSE_2, 452 name, 453 value)); 454 } 455 m_res.addHeader(name, value); 456 } 457 } 458 459 464 public void addIntHeader(String name, int value) { 465 466 addHeader(name, String.valueOf(value)); 467 } 468 469 478 public void addToIncludeList(String target, Map parameterMap) { 479 480 if (m_includeList == null) { 481 m_includeList = new ArrayList (10); 482 m_includeListParameters = new ArrayList (10); 483 } 484 m_includeListParameters.add(parameterMap); 485 m_includeList.add(target); 486 } 487 488 493 public String getEncoding() { 494 495 return m_encoding; 496 } 497 498 503 public Map getHeaders() { 504 505 return m_headers; 506 } 507 508 513 public ServletOutputStream getOutputStream() throws IOException { 514 515 if (m_out == null) { 516 initStream(); 517 } 518 return m_out; 519 } 520 521 526 public PrintWriter getWriter() throws IOException { 527 528 if (m_writer == null) { 529 initStream(); 530 } 531 return m_writer; 532 } 533 534 539 public byte[] getWriterBytes() { 540 541 if (isSuspended()) { 542 return new byte[0]; 544 } 545 if (m_cacheBytes != null) { 546 return m_cacheBytes; 548 } 549 if (m_out == null) { 550 return new byte[0]; 552 } 553 if (m_writer != null) { 554 m_writer.flush(); 556 } 557 return m_out.getBytes(); 558 } 559 560 570 public boolean isSuspended() { 571 572 return m_suspended; 573 } 574 575 584 public boolean isTopElement() { 585 586 return m_isTopElement; 587 } 588 589 594 public void sendRedirect(String location) throws IOException { 595 596 if (isSuspended() && (!location.equals(m_bufferRedirect))) { 598 return; 599 } 600 if (LOG.isDebugEnabled()) { 601 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXRESPONSE_SENDREDIRECT_1, location)); 602 } 603 if (m_cachingRequired && !m_includeMode) { 604 m_bufferRedirect = location; 605 } 606 607 if (!m_cachingRequired) { 608 if (LOG.isDebugEnabled()) { 611 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXRESPONSE_TOPRESPONSE_SENDREDIRECT_1, location)); 612 } 613 if (LOG.isWarnEnabled()) { 614 if (m_controller.getResponseStackSize() > 2) { 615 LOG.warn(Messages.get().getBundle().key( 617 Messages.LOG_FLEXRESPONSE_REDIRECTWARNING_3, 618 m_controller.getCmsResource().getRootPath(), 619 m_controller.getCurrentRequest().getElementUri(), 620 location)); 621 } 622 } 623 HttpServletResponse topRes = m_controller.getTopResponse(); 625 processHeaders(getHeaders(), topRes); 627 topRes.sendRedirect(location); 628 } 629 630 m_controller.suspendFlexResponse(); 631 } 632 633 638 public void setContentType(String type) { 639 640 if (LOG.isDebugEnabled()) { 641 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXRESPONSE_SETTING_CONTENTTYPE_1, type)); 642 } 643 if (!m_typeSet && m_isTopElement) { 646 m_typeSet = true; 648 super.setContentType(type); 649 return; 650 } 651 } 652 653 658 public void setDateHeader(String name, long date) { 659 660 setHeader(name, CmsDateUtil.getHeaderDate(date)); 661 } 662 663 668 public void setHeader(String name, String value) { 669 670 if (isSuspended()) { 671 return; 672 } 673 674 if (CmsRequestUtil.HEADER_CONTENT_TYPE.equalsIgnoreCase(name)) { 675 setContentType(value); 676 return; 677 } 678 679 if (m_cachingRequired && !m_includeMode) { 680 setHeaderList(m_bufferHeaders, name, value); 681 if (LOG.isDebugEnabled()) { 682 LOG.debug(Messages.get().getBundle().key( 683 Messages.LOG_FLEXRESPONSE_SETTING_HEADER_IN_ELEMENT_BUFFER_2, 684 name, 685 value)); 686 } 687 } 688 689 if (m_writeOnlyToBuffer) { 690 setHeaderList(m_headers, name, value); 691 if (LOG.isDebugEnabled()) { 692 LOG.debug(Messages.get().getBundle().key( 693 Messages.LOG_FLEXRESPONSE_SETTING_HEADER_IN_HEADERS_2, 694 name, 695 value)); 696 } 697 } else { 698 if (LOG.isDebugEnabled()) { 699 LOG.debug(Messages.get().getBundle().key( 700 Messages.LOG_FLEXRESPONSE_SETTING_HEADER_IN_PARENT_RESPONSE_2, 701 name, 702 value)); 703 } 704 m_res.setHeader(name, value); 705 } 706 } 707 708 713 public void setIntHeader(String name, int value) { 714 715 setHeader(name, "" + value); 716 } 717 718 731 public void setOnlyBuffering(boolean value) { 732 733 m_writeOnlyToBuffer = value && !m_controller.isForwardMode(); 734 735 if (m_writeOnlyToBuffer) { 736 setCmsCachingRequired(true); 737 } 738 } 739 740 748 void addToIncludeResults(byte[] result) { 749 750 if (m_includeResults == null) { 751 m_includeResults = new ArrayList (10); 752 } 753 m_includeResults.add(result); 754 } 755 756 761 CmsFlexCacheKey getCmsCacheKey() { 762 763 return m_key; 764 } 765 766 773 boolean hasIncludeList() { 774 775 return m_includeList != null; 776 } 777 778 789 CmsFlexCacheEntry processCacheEntry() throws IOException { 790 791 if (isSuspended() && (m_bufferRedirect == null)) { 792 return null; 794 } 795 if (m_cachingRequired) { 796 m_cachedEntry = new CmsFlexCacheEntry(); 798 if (m_bufferRedirect != null) { 799 m_cachedEntry.setRedirect(m_bufferRedirect); 801 } else { 802 m_cachedEntry.addHeaders(m_bufferHeaders); 804 if (m_includeList != null) { 806 processIncludeList(); 809 } else { 810 m_cachedEntry.add(getWriterBytes()); 812 } 813 } 814 m_cachedEntry.complete(); 816 } 817 if (m_writeOnlyToBuffer) { 819 820 m_cachingRequired = false; 822 823 if (m_bufferRedirect != null) { 824 sendRedirect(m_bufferRedirect); 826 } else { 827 if (m_parentWritesOnlyToBuffer) { 829 if (m_out != null) { 831 try { 832 m_out.clear(); 833 } catch (Exception e) { 834 if (LOG.isDebugEnabled()) { 835 LOG.debug(Messages.get().getBundle().key( 836 Messages.LOG_FLEXRESPONSE_ERROR_FLUSHING_OUTPUT_STREAM_1, 837 e)); 838 } 839 } 840 } else { 841 if (LOG.isDebugEnabled()) { 842 LOG.debug(Messages.get().getBundle().key( 843 Messages.LOG_FLEXRESPONSE_ERROR_OUTPUT_STREAM_NULL_0)); 844 } 845 } 846 writeCachedResultToStream(this); 847 } else { 848 processHeaders(m_headers, m_res); 850 writeCachedResultToStream(m_res); 851 } 852 } 853 } 854 return m_cachedEntry; 855 } 856 857 863 void setCmsCacheKey(CmsFlexCacheKey value) { 864 865 m_key = value; 866 } 867 868 879 CmsFlexCacheKey setCmsCacheKey(String resourcename, String cacheDirectives, boolean online) 880 throws CmsFlexCacheException { 881 882 m_key = new CmsFlexCacheKey(resourcename, cacheDirectives, online); 883 if (m_key.hadParseError()) { 884 throw new CmsFlexCacheException(Messages.get().container( 886 Messages.LOG_FLEXRESPONSE_PARSE_ERROR_IN_CACHE_KEY_2, 887 cacheDirectives, 888 resourcename)); 889 } 890 return m_key; 891 } 892 893 902 void setCmsCachingRequired(boolean value) { 903 904 m_cachingRequired = (value || m_writeOnlyToBuffer) && !m_controller.isForwardMode(); 905 } 906 907 916 void setCmsIncludeMode(boolean value) { 917 918 m_includeMode = value; 919 } 920 921 930 void setSuspended(boolean value) { 931 932 m_suspended = value; 933 } 934 935 943 void writeToOutputStream(byte[] bytes, boolean useArray) throws IOException { 944 945 if (isSuspended()) { 946 return; 947 } 948 if (m_writeOnlyToBuffer) { 949 if (useArray) { 950 m_cacheBytes = bytes; 952 } else { 953 if (m_out == null) { 954 initStream(); 955 } 956 m_out.write(bytes); 958 } 959 } else { 960 if (LOG.isDebugEnabled()) { 961 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXRESPONSE_ERROR_WRITING_TO_OUTPUT_STREAM_0)); 962 } 963 m_res.getOutputStream().write(bytes); 965 m_res.getOutputStream().flush(); 966 } 967 } 968 969 976 private void addHeaderList(Map headers, String name, String value) { 977 978 ArrayList values = (ArrayList )headers.get(name); 979 if (values == null) { 980 values = new ArrayList (); 981 headers.put(name, values); 982 } 983 values.add(value); 984 } 985 986 992 private void initStream() throws IOException { 993 994 if (m_out == null) { 995 if (!m_writeOnlyToBuffer) { 996 if (m_cachingRequired || (m_controller.getResponseStackSize() > 1)) { 998 m_out = new CmsFlexResponse.CmsServletOutputStream(m_res.getOutputStream()); 1000 } else { 1001 m_out = (CmsFlexResponse.CmsServletOutputStream)m_res.getOutputStream(); 1003 } 1004 } else { 1005 m_out = new CmsFlexResponse.CmsServletOutputStream(); 1007 } 1008 } 1009 if (m_writer == null) { 1010 m_writer = new PrintWriter (new BufferedWriter (new OutputStreamWriter (m_out, m_encoding)), false); 1012 } 1013 } 1014 1015 1035 private void processIncludeList() { 1036 1037 byte[] result = getWriterBytes(); 1038 if (!hasIncludeList()) { 1039 m_cachedEntry.add(result); 1041 result = null; 1042 } else { 1043 int max = result.length; 1045 int pos = 0; 1046 int last = 0; 1047 int size = 0; 1048 int count = 0; 1049 1050 int i = 0; 1052 int j = 0; 1053 while (i < m_includeList.size() && (pos < max)) { 1054 while ((pos < max) && (result[pos] != FLEX_CACHE_DELIMITER)) { 1056 pos++; 1057 } 1058 if ((pos < max) && (result[pos] == FLEX_CACHE_DELIMITER)) { 1059 count++; 1060 size = pos - last; 1063 if (size > 0) { 1064 byte[] piece = new byte[size]; 1066 System.arraycopy(result, last, piece, 0, size); 1067 m_cachedEntry.add(piece); 1069 piece = null; 1070 } 1071 last = ++pos; 1072 m_cachedEntry.add((String )m_includeList.get(i++), (Map )m_includeListParameters.get(j++)); 1074 } 1075 } 1076 if (pos < max) { 1077 size = max - pos; 1079 byte[] piece = new byte[size]; 1080 System.arraycopy(result, pos, piece, 0, size); 1081 m_cachedEntry.add(piece); 1082 piece = null; 1083 } 1084 result = null; 1085 if (i >= m_includeList.size()) { 1086 m_includeList = null; 1088 m_includeListParameters = null; 1089 } else { 1090 m_includeList = m_includeList.subList(count, m_includeList.size()); 1092 m_includeListParameters = m_includeListParameters.subList(count, m_includeListParameters.size()); 1093 } 1094 } 1095 } 1096 1097 1104 private void setHeaderList(Map headers, String name, String value) { 1105 1106 ArrayList values = new ArrayList (); 1107 values.add(SET_HEADER + value); 1108 headers.put(name, values); 1109 } 1110 1111 1118 private void writeCachedResultToStream(HttpServletResponse res) throws IOException { 1119 1120 List elements = m_cachedEntry.elements(); 1121 int count = 0; 1122 if (elements != null) { 1123 for (int i = 0; i < elements.size(); i++) { 1124 Object o = elements.get(i); 1125 if (o instanceof byte[]) { 1126 res.getOutputStream().write((byte[])o); 1127 } else { 1128 if ((m_includeResults != null) && (m_includeResults.size() > count)) { 1129 res.getOutputStream().write((byte[])m_includeResults.get(count)); 1131 count++; 1132 } 1133 i++; 1135 } 1136 } 1137 } 1138 } 1139}
| Popular Tags
|