001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.jsp; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsResource; 032import org.opencms.flex.CmsFlexController; 033import org.opencms.i18n.CmsEncoder; 034import org.opencms.loader.CmsImageScaler; 035import org.opencms.main.CmsException; 036import org.opencms.main.CmsLog; 037import org.opencms.main.OpenCms; 038import org.opencms.staticexport.CmsLinkManager; 039import org.opencms.util.CmsRequestUtil; 040import org.opencms.util.CmsStringUtil; 041import org.opencms.util.CmsUriSplitter; 042 043import java.util.Arrays; 044import java.util.HashMap; 045import java.util.List; 046import java.util.Map; 047 048import javax.servlet.ServletRequest; 049import javax.servlet.jsp.JspException; 050 051import org.apache.commons.logging.Log; 052 053/** 054 * Creates HTML code for <img src> tags that use the OpenCms image scaling capabilities.<p> 055 * 056 * @since 6.2.0 057 */ 058public class CmsJspTagImage extends CmsJspImageScalerTagSupport implements I_CmsJspTagParamParent { 059 060 /** Optional HTML attribute constant. */ 061 private static final String ATTR_ALIGN = "align"; 062 063 /** Optional HTML attribute constant. */ 064 private static final String ATTR_ALT = "alt"; 065 066 /** Optional HTML attribute constant. */ 067 private static final String ATTR_BORDER = "border"; 068 069 /** Optional HTML attribute constant. */ 070 private static final String ATTR_CLASS = "class"; 071 072 /** Optional HTML attribute constant. */ 073 private static final String ATTR_HSPACE = "hspace"; 074 075 /** Optional HTML attribute constant. */ 076 private static final String ATTR_ID = "id"; 077 078 /** Optional HTML attribute constant. */ 079 private static final String ATTR_LONGDESC = "longdesc"; 080 081 /** Optional HTML attribute constant. */ 082 private static final String ATTR_NAME = "name"; 083 084 /** Optional HTML attribute constant. */ 085 private static final String ATTR_STYLE = "style"; 086 087 /** Optional HTML attribute constant. */ 088 private static final String ATTR_TITLE = "title"; 089 090 /** Optional HTML attribute constant. */ 091 private static final String ATTR_USEMAP = "usemap"; 092 093 /** Optional HTML attribute constant. */ 094 private static final String ATTR_VSPACE = "vspace"; 095 096 /** The log object for this class. */ 097 private static final Log LOG = CmsLog.getLog(CmsJspTagImage.class); 098 099 /** Required image scaler attributes constant. */ 100 private static final String SCALE_ATTR_COLOR = "scalecolor"; 101 102 /** Required image scaler attributes constant. */ 103 private static final String SCALE_ATTR_FILTER = "scalefilter"; 104 105 /** Required image scaler attributes constant. */ 106 private static final String SCALE_ATTR_NODIM = "nodim"; 107 108 /** Required image scaler attributes constant. */ 109 private static final String SCALE_ATTR_PARTIALTAG = "partialtag"; 110 111 /** Required image scaler attributes constant. */ 112 private static final String SCALE_ATTR_SRC = "src"; 113 114 /** Lists for fast lookup. */ 115 private static final String[] SCALER_ATTRS = { 116 SCALE_ATTR_COLOR, 117 SCALE_ATTR_FILTER, 118 SCALE_ATTR_HEIGHT, 119 SCALE_ATTR_PARTIALTAG, 120 SCALE_ATTR_POSITION, 121 SCALE_ATTR_QUALITY, 122 SCALE_ATTR_RENDERMODE, 123 SCALE_ATTR_SRC, 124 SCALE_ATTR_TYPE, 125 SCALE_ATTR_WIDTH, 126 SCALE_ATTR_MAXHEIGHT, 127 SCALE_ATTR_MAXWIDTH, 128 SCALE_ATTR_NODIM}; 129 130 /** Image scaler attribute list. */ 131 private static final List<String> SCALER_ATTRS_LIST = Arrays.asList(SCALER_ATTRS); 132 133 /** Serial version UID required for safe serialization. */ 134 private static final long serialVersionUID = 6513320107441256414L; 135 136 /** Map with additionally set image attributes not needed by the image scaler. */ 137 private Map<String, String> m_attributes; 138 139 /** Controls if the created HTML image tag contains height and width attributes. */ 140 private boolean m_noDim; 141 142 /** Controls if the created HTML image tag is a full or partial tag. */ 143 private boolean m_partialTag; 144 145 /** 146 * Creates a new image scaling tag instance.<p> 147 */ 148 public CmsJspTagImage() { 149 super(); 150 } 151 152 /** 153 * Creates the images scaler used by this image tag.<p> 154 * 155 * @param scaler the scaler created from this tags parameters 156 * @param original a scaler that contains the original image dimensions 157 * @param scaleParam optional scaler parameters for cropping 158 * 159 * @return the images scaler used by this image tag 160 */ 161 public static CmsImageScaler getScaler(CmsImageScaler scaler, CmsImageScaler original, String scaleParam) { 162 163 if (scaleParam != null) { 164 CmsImageScaler cropScaler = null; 165 // use cropped image as a base for scaling 166 cropScaler = new CmsImageScaler(scaleParam); 167 if (scaler.getType() == 5) { 168 // must reset height / width parameters in crop scaler for type 5 169 cropScaler.setWidth(cropScaler.getCropWidth()); 170 cropScaler.setHeight(cropScaler.getCropHeight()); 171 } 172 scaler = cropScaler.getCropScaler(scaler); 173 } 174 // calculate target scale dimensions (if required) 175 if (((scaler.getHeight() <= 0) || (scaler.getWidth() <= 0)) 176 || ((scaler.getType() == 5) && scaler.isValid() && !scaler.isCropping())) { 177 // read the image properties for the selected resource 178 if (original.isValid()) { 179 scaler = original.getReScaler(scaler); 180 } 181 } 182 return scaler; 183 } 184 185 /** 186 * Internal action method to create the tag content.<p> 187 * 188 * @param src the image source 189 * @param scaler the image scaleing parameters 190 * @param attributes the additional image HTML attributes 191 * @param partialTag if <code>true</code>, the opening <code><img</code> and closing <code> /></code> is omitted 192 * @param noDim if <code>true</code>, the <code>height</code> and <code>width</code> attributes are omitted 193 * @param req the current request 194 * 195 * @return the created <img src> tag content 196 * 197 * @throws CmsException in case something goes wrong 198 */ 199 public static String imageTagAction( 200 String src, 201 CmsImageScaler scaler, 202 Map<String, String> attributes, 203 boolean partialTag, 204 boolean noDim, 205 ServletRequest req) 206 throws CmsException { 207 208 CmsFlexController controller = CmsFlexController.getController(req); 209 CmsObject cms = controller.getCmsObject(); 210 211 // resolve possible relative URI 212 src = CmsLinkManager.getAbsoluteUri(src, controller.getCurrentRequest().getElementUri()); 213 CmsUriSplitter splitSrc = new CmsUriSplitter(src); 214 215 String scaleParam = null; 216 if (splitSrc.getQuery() != null) { 217 // check if the original URI already has parameters, this is true if original has been cropped 218 String[] scaleStr = CmsRequestUtil.createParameterMap(splitSrc.getQuery()).get(CmsImageScaler.PARAM_SCALE); 219 if (scaleStr != null) { 220 scaleParam = scaleStr[0]; 221 } 222 } 223 224 CmsResource imageRes = cms.readResource(splitSrc.getPrefix()); 225 CmsImageScaler original = new CmsImageScaler(cms, imageRes); 226 scaler = getScaler(scaler, original, scaleParam); 227 228 StringBuffer result = new StringBuffer(128); 229 if (!partialTag) { 230 // open tag if not a partial tag 231 result.append("<img"); 232 } 233 234 // append the image source 235 result.append(" src=\""); 236 237 String imageLink = cms.getSitePath(imageRes); 238 if (scaler.isValid()) { 239 // now append the scaler parameters 240 imageLink += scaler.toRequestParam(); 241 } 242 result.append(OpenCms.getLinkManager().substituteLink(cms, imageLink)); 243 result.append("\""); 244 245 if (!noDim && scaler.isValid()) { 246 // append image width and height 247 result.append(" width=\""); 248 result.append(scaler.getWidth()); 249 result.append("\""); 250 result.append(" height=\""); 251 result.append(scaler.getHeight()); 252 result.append("\""); 253 } 254 255 if (attributes != null) { 256 // append the HTML attributes 257 for (Map.Entry<String, String> entry : attributes.entrySet()) { 258 String attr = entry.getKey(); 259 String value = entry.getValue(); 260 result.append(" "); 261 result.append(attr); 262 result.append("=\""); 263 result.append(CmsEncoder.escapeXml(value)); 264 result.append("\""); 265 } 266 } 267 268 if (!partialTag) { 269 // close tag if not a partial tag 270 result.append(" />"); 271 } 272 return result.toString(); 273 } 274 275 /** 276 * Internal action method to create the tag content.<p> 277 * 278 * @param src the image source 279 * @param scaler the image scaleing parameters 280 * @param attributes the additional image HTML attributes 281 * @param partialTag if <code>true</code>, the opening <code><img</code> and closing <code> /></code> is omitted 282 * @param req the current request 283 * 284 * @return the created <img src> tag content 285 * 286 * @throws CmsException in case something goes wrong 287 */ 288 public static String imageTagAction( 289 String src, 290 CmsImageScaler scaler, 291 Map<String, String> attributes, 292 boolean partialTag, 293 ServletRequest req) 294 throws CmsException { 295 296 return imageTagAction(src, scaler, attributes, partialTag, false, req); 297 } 298 299 /** 300 * @see org.opencms.jsp.I_CmsJspTagParamParent#addParameter(java.lang.String, java.lang.String) 301 */ 302 public void addParameter(String name, String value) { 303 304 String key = name.trim().toLowerCase(); 305 switch (SCALER_ATTRS_LIST.indexOf(key)) { 306 case 0: // scaleColor 307 setScaleColor(value); 308 break; 309 case 1: // scaleFilter 310 setScaleFilter(value); 311 break; 312 case 2: // height 313 setHeight(value); 314 break; 315 case 3: // partialTag 316 setPartialTag(value); 317 break; 318 case 4: // scalePosition 319 setScalePosition(value); 320 break; 321 case 5: // scaleQuality 322 setScaleQuality(value); 323 break; 324 case 6: // scaleRendermode 325 setScaleRendermode(value); 326 break; 327 case 7: // src 328 setSrc(value); 329 break; 330 case 8: // scaleType 331 setScaleType(value); 332 break; 333 case 9: // width 334 setWidth(value); 335 break; 336 case 10: // maxHeight 337 setMaxHeight(value); 338 break; 339 case 11: // maxWidth 340 setMaxWidth(value); 341 break; 342 case 12: // noDim 343 setNoDim(value); 344 break; 345 default: // not a value used by the image scaler, treat as HTML attribute 346 setAttribute(key, value); 347 } 348 } 349 350 /** 351 * @see javax.servlet.jsp.tagext.Tag#doEndTag() 352 */ 353 @Override 354 public int doEndTag() throws JspException { 355 356 ServletRequest req = pageContext.getRequest(); 357 358 // this will always be true if the page is called through OpenCms 359 if (CmsFlexController.isCmsRequest(req)) { 360 361 try { 362 // create the HTML image tag 363 String imageTag = null; 364 try { 365 imageTag = imageTagAction(m_src, m_scaler, m_attributes, m_partialTag, m_noDim, req); 366 } catch (CmsException e) { 367 // any issue accessing the VFS - just return an empty string 368 // otherwise template layout will get mixed up with nasty exception messages 369 if (LOG.isWarnEnabled()) { 370 LOG.warn(Messages.get().getBundle().key(Messages.ERR_IMAGE_TAG_VFS_ACCESS_1, m_src), e); 371 } 372 } 373 // make sure that no null String is returned 374 pageContext.getOut().print(imageTag == null ? "" : imageTag); 375 376 } catch (Exception ex) { 377 if (LOG.isErrorEnabled()) { 378 LOG.error(Messages.get().getBundle().key(Messages.ERR_PROCESS_TAG_1, "image"), ex); 379 } 380 throw new javax.servlet.jsp.JspException(ex); 381 } 382 } 383 release(); 384 return EVAL_PAGE; 385 } 386 387 /** 388 * Returns <code>{@link #EVAL_BODY_BUFFERED}</code>.<p> 389 * 390 * @return <code>{@link #EVAL_BODY_BUFFERED}</code> 391 * 392 * @see javax.servlet.jsp.tagext.Tag#doStartTag() 393 */ 394 @Override 395 public int doStartTag() { 396 397 return EVAL_BODY_BUFFERED; 398 } 399 400 /** 401 * Returns the value of the HTML "align" attribute.<p> 402 * 403 * @return the value of the HTML "align" attribute 404 */ 405 public String getAlign() { 406 407 return getAttribute(ATTR_ALIGN); 408 } 409 410 /** 411 * Returns the value of the HTML "alt" attribute.<p> 412 * 413 * @return the value of the HTML "alt" attribute 414 */ 415 public String getAlt() { 416 417 return getAttribute(ATTR_ALT); 418 } 419 420 /** 421 * Returns the value of the HTML "border" attribute.<p> 422 * 423 * @return the value of the HTML "border" attribute 424 */ 425 public String getBorder() { 426 427 return getAttribute(ATTR_BORDER); 428 } 429 430 /** 431 * Returns the value of the HTML "class" attribute.<p> 432 * 433 * @return the value of the HTML "class" attribute 434 */ 435 public String getCssclass() { 436 437 return getAttribute(ATTR_CLASS); 438 } 439 440 /** 441 * Returns the value of the HTML "hspace" attribute.<p> 442 * 443 * @return the value of the HTML "hspace" attribute 444 */ 445 public String getHspace() { 446 447 return getAttribute(ATTR_HSPACE); 448 } 449 450 /** 451 * Returns the value of the HTML "id" attribute.<p> 452 * 453 * @return the value of the HTML "id" attribute 454 */ 455 @Override 456 public String getId() { 457 458 return getAttribute(ATTR_ID); 459 } 460 461 /** 462 * Returns the value of the HTML "longdesc" attribute.<p> 463 * 464 * @return the value of the HTML "longdesc" attribute 465 */ 466 public String getLongdesc() { 467 468 return getAttribute(ATTR_LONGDESC); 469 } 470 471 /** 472 * Returns the value of the HTML "name" attribute.<p> 473 * 474 * @return the value of the HTML "name" attribute 475 */ 476 public String getName() { 477 478 return getAttribute(ATTR_NAME); 479 } 480 481 /** 482 * Returns <code>"true"</code> if the created HTML image tag does not contain height and width attributes.<p> 483 * 484 * @return <code>"true"</code> if the created HTML image tag does not contain height and width attributes 485 */ 486 487 public String getNoDim() { 488 489 return String.valueOf(m_noDim); 490 } 491 492 /** 493 * Returns the value of the HTML "style" attribute.<p> 494 * 495 * @return the value of the HTML "style" attribute 496 */ 497 public String getStyle() { 498 499 return getAttribute(ATTR_STYLE); 500 } 501 502 /** 503 * Returns the value of the HTML "title" attribute.<p> 504 * 505 * @return the value of the HTML "title" attribute 506 */ 507 public String getTitle() { 508 509 return getAttribute(ATTR_TITLE); 510 } 511 512 /** 513 * Returns the value of the HTML "usemap" attribute.<p> 514 * 515 * @return the value of the HTML "usemap" attribute 516 */ 517 public String getUsemap() { 518 519 return getAttribute(ATTR_USEMAP); 520 } 521 522 /** 523 * Returns the value of the HTML "vspace" attribute.<p> 524 * 525 * @return the value of the HTML "vspace" attribute 526 */ 527 public String getVspace() { 528 529 return getAttribute(ATTR_VSPACE); 530 } 531 532 /** 533 * Returns <code>"true"</code> if the HTML tag should only be created as partial tag.<p> 534 * 535 * @return <code>"true"</code> if the HTML tag should only be created as partial tag 536 */ 537 public String isPartialTag() { 538 539 return String.valueOf(m_partialTag); 540 } 541 542 /** 543 * @see javax.servlet.jsp.tagext.Tag#release() 544 */ 545 @Override 546 public void release() { 547 548 m_attributes = null; 549 m_partialTag = false; 550 m_noDim = false; 551 super.release(); 552 } 553 554 /** 555 * Sets the value of the HTML "align" attribute.<p> 556 * 557 * @param value the value of the HTML "align" attribute to set 558 */ 559 public void setAlign(String value) { 560 561 setAttribute(ATTR_ALIGN, value); 562 } 563 564 /** 565 * Sets the value of the HTML "alt" attribute.<p> 566 * 567 * @param value the value of the HTML "alt" attribute to set 568 */ 569 public void setAlt(String value) { 570 571 setAttribute(ATTR_ALT, value, true); 572 573 } 574 575 /** 576 * Sets the value of the HTML "border" attribute.<p> 577 * 578 * @param value the value of the HTML "border" attribute to set 579 */ 580 public void setBorder(String value) { 581 582 setAttribute(ATTR_BORDER, value); 583 584 } 585 586 /** 587 * Sets the value of the HTML "class" attribute.<p> 588 * 589 * @param value the value of the HTML "class" attribute to set 590 */ 591 public void setCssclass(String value) { 592 593 setAttribute(ATTR_CLASS, value); 594 595 } 596 597 /** 598 * Sets the value of the HTML "hspace" attribute.<p> 599 * 600 * @param value the value of the HTML "hspace" attribute to set 601 */ 602 public void setHspace(String value) { 603 604 setAttribute(ATTR_HSPACE, value); 605 606 } 607 608 /** 609 * Sets the value of the HTML "id" attribute.<p> 610 * 611 * @param value the value of the HTML "id" attribute to set 612 */ 613 @Override 614 public void setId(String value) { 615 616 setAttribute(ATTR_ID, value); 617 618 } 619 620 /** 621 * Sets the value of the HTML "longdesc" attribute.<p> 622 * 623 * @param value the value of the HTML "longdesc" attribute to set 624 */ 625 public void setLongdesc(String value) { 626 627 setAttribute(ATTR_LONGDESC, value); 628 629 } 630 631 /** 632 * Sets the value of the HTML "name" attribute.<p> 633 * 634 * @param value the value of the HTML "name" attribute to set 635 */ 636 public void setName(String value) { 637 638 setAttribute(ATTR_NAME, value); 639 640 } 641 642 /** 643 * Controls if the created HTML image tag contains height and width attributes.<p> 644 * 645 * @param noDim the value to set 646 */ 647 public void setNoDim(String noDim) { 648 649 m_noDim = Boolean.valueOf(noDim).booleanValue(); 650 } 651 652 /** 653 * Controls if the created HTML image tag is a full or partial tag.<p> 654 * 655 * @param partialTag the value to set 656 */ 657 public void setPartialTag(String partialTag) { 658 659 m_partialTag = Boolean.valueOf(partialTag).booleanValue(); 660 } 661 662 /** 663 * Sets the value of the HTML "style" attribute.<p> 664 * 665 * @param value the value of the HTML "style" attribute to set 666 */ 667 public void setStyle(String value) { 668 669 setAttribute(ATTR_STYLE, value); 670 } 671 672 /** 673 * Sets the value of the HTML "title" attribute.<p> 674 * 675 * @param value the value of the HTML "title" attribute to set 676 */ 677 public void setTitle(String value) { 678 679 setAttribute(ATTR_TITLE, value); 680 } 681 682 /** 683 * Sets the value of the HTML "usemap" attribute.<p> 684 * 685 * @param value the value of the HTML "usemap" attribute to set 686 */ 687 public void setUsemap(String value) { 688 689 setAttribute(ATTR_USEMAP, value); 690 } 691 692 /** 693 * Sets the value of the HTML "vspace" attribute.<p> 694 * 695 * @param value the value of the HTML "vspace" attribute to set 696 */ 697 public void setVspace(String value) { 698 699 setAttribute(ATTR_VSPACE, value); 700 701 } 702 703 /** 704 * Returns the given keys attribute value from the attribute map.<p> 705 * 706 * @param key the attribute to read from the map 707 * @return the given keys attribute value from the attribute map 708 */ 709 private String getAttribute(String key) { 710 711 if (m_attributes != null) { 712 return m_attributes.get(key); 713 } 714 return null; 715 } 716 717 /** 718 * Sets the given key with the given value in the attribute map.<p> 719 * 720 * @param key the key to set 721 * @param value the value to set 722 */ 723 private void setAttribute(String key, String value) { 724 725 setAttribute(key, value, false); 726 } 727 728 /** 729 * Sets the given key with the given value in the attribute map.<p> 730 * 731 * @param key the key to set 732 * @param value the value to set 733 * @param allowEmptyValue flag to determine if an empty value (not <code>null</code>!) should be set 734 */ 735 private void setAttribute(String key, String value, boolean allowEmptyValue) { 736 737 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(value) || (allowEmptyValue && (value != null))) { 738 if (m_attributes == null) { 739 m_attributes = new HashMap<String, String>(); 740 } 741 m_attributes.put(key, value); 742 } 743 } 744}