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.file.CmsResourceFilter; 033import org.opencms.file.CmsVfsResourceNotFoundException; 034import org.opencms.flex.CmsFlexController; 035import org.opencms.i18n.CmsLocaleManager; 036import org.opencms.jsp.util.CmsJspLinkWrapper; 037import org.opencms.main.CmsException; 038import org.opencms.main.CmsLog; 039import org.opencms.main.OpenCms; 040import org.opencms.staticexport.CmsLinkManager; 041import org.opencms.util.CmsStringUtil; 042 043import java.util.Locale; 044 045import javax.servlet.ServletRequest; 046import javax.servlet.jsp.JspException; 047import javax.servlet.jsp.PageContext; 048import javax.servlet.jsp.tagext.BodyTagSupport; 049 050import org.apache.commons.logging.Log; 051 052/** 053 * Implements the <code><cms:link>[filename]</cms:link></code> 054 * tag to add OpenCms managed links to a JSP page, required for link 055 * management and the static 056 * export to work properly.<p> 057 * 058 * @since 6.0.0 059 */ 060public class CmsJspTagLink extends BodyTagSupport { 061 062 /** 063 * Parameters for the link tag. 064 */ 065 public static class Parameters { 066 067 /** The target. */ 068 public String m_target; 069 070 /** The base uri. */ 071 public String m_baseUri; 072 073 /** The detail page. */ 074 public String m_detailPage; 075 076 /** The locale. */ 077 public Locale m_locale; 078 079 /** The type. */ 080 public Type m_type; 081 082 /** 083 * Default constructor. 084 */ 085 public Parameters() {} 086 087 /** 088 * Instantiates a new link tag params. 089 * 090 * @param target the target 091 * @param baseUri the base uri 092 * @param detailPage the detail page 093 * @param locale the locale 094 * @param type the type 095 */ 096 public Parameters(String target, String baseUri, String detailPage, Locale locale, Type type) { 097 098 m_target = target; 099 m_baseUri = baseUri; 100 m_detailPage = detailPage; 101 m_locale = locale; 102 m_type = type != null ? type : Type.DEFAULT; 103 } 104 105 /** 106 * Gets the base uri. 107 * 108 * @return the base uri 109 */ 110 public String getBaseUri() { 111 112 return m_baseUri; 113 } 114 115 /** 116 * Gets the detail page. 117 * 118 * @return the detail page 119 */ 120 public String getDetailPage() { 121 122 return m_detailPage; 123 } 124 125 /** 126 * Gets the locale. 127 * 128 * @return the locale 129 */ 130 public Locale getLocale() { 131 132 return m_locale; 133 } 134 135 /** 136 * Gets the target. 137 * 138 * @return the target 139 */ 140 public String getTarget() { 141 142 return m_target; 143 } 144 145 /** 146 * Gets the type. 147 * 148 * @return the type 149 */ 150 public Type getType() { 151 152 return m_type; 153 } 154 155 /** 156 * Sets the base uri. 157 * 158 * @param baseUri the new base uri 159 */ 160 public void setBaseUri(String baseUri) { 161 162 m_baseUri = baseUri; 163 } 164 165 /** 166 * Sets the detail page. 167 * 168 * @param detailPage the new detail page 169 */ 170 public void setDetailPage(String detailPage) { 171 172 m_detailPage = detailPage; 173 } 174 175 /** 176 * Sets the locale. 177 * 178 * @param locale the new locale 179 */ 180 public void setLocale(Locale locale) { 181 182 m_locale = locale; 183 } 184 185 /** 186 * Sets the target. 187 * 188 * @param target the new target 189 */ 190 public void setTarget(String target) { 191 192 m_target = target; 193 } 194 195 /** 196 * Sets the type. 197 * 198 * @param type the new type 199 */ 200 public void setType(Type type) { 201 202 m_type = type; 203 } 204 } 205 206 /** Link type. */ 207 public enum Type { 208 /** Default mode. */ 209 DEFAULT, 210 /** Online link mode. */ 211 ONLINE, 212 213 /** Server link mode. */ 214 SERVER, 215 216 /** Permalink mode. */ 217 PERMA; 218 } 219 220 /** String describing request scope. */ 221 private static final String SCOPE_REQUEST = "request"; 222 223 /** String describing session scope. */ 224 private static final String SCOPE_SESSION = "session"; 225 226 /** String describing application scope. */ 227 private static final String SCOPE_APPLICATION = "application"; 228 229 /** The log object for this class. */ 230 private static final Log LOG = CmsLog.getLog(CmsJspTagLink.class); 231 232 /** Serial version UID required for safe serialization. */ 233 private static final long serialVersionUID = -2361021288258405388L; 234 235 /** The variable to store the result. */ 236 private String m_var; 237 238 /** The scope used for the var parameter. */ 239 private String m_scope; 240 241 /** The optional base URI to create the link from. */ 242 private String m_baseUri; 243 244 /** The target detail page path. */ 245 private String m_detailPage; 246 247 /** The optional locale attribute. */ 248 private Locale m_locale; 249 250 /** The link type. */ 251 private Type m_type; 252 253 /** 254 * Tries to read the active locale for the given (site) path, or for its parent path if the path can't be read. 255 * <p> 256 * If this fails, null is returned. 257 * 258 * @param cms the CMS context 259 * @param baseUri the base URI for which to read the locale 260 * @return the locale 261 */ 262 public static Locale getBaseUriLocale(CmsObject cms, String baseUri) { 263 264 try { 265 try { 266 return OpenCms.getLocaleManager().getDefaultLocale( 267 cms, 268 cms.readResource(baseUri, CmsResourceFilter.IGNORE_EXPIRATION)); 269 } catch (CmsVfsResourceNotFoundException e) { 270 String parent = CmsResource.getParentFolder(baseUri); 271 if (parent != null) { 272 return OpenCms.getLocaleManager().getDefaultLocale( 273 cms, 274 cms.readResource(parent, CmsResourceFilter.IGNORE_EXPIRATION)); 275 } 276 } 277 } catch (CmsException e) { 278 LOG.info(e.getLocalizedMessage(), e); 279 } 280 return null; 281 282 } 283 284 /** 285 * Returns a link to a file in the OpenCms VFS 286 * that has been adjusted according to the web application path and the 287 * OpenCms static export rules.<p> 288 * 289 * <p>If the <code>baseUri</code> parameter is provided, this will be treated as the source of the link, 290 * if this is <code>null</code> then the current OpenCms user context URI will be used as source.</p> 291 * 292 * <p>If the <code>locale</code> parameter is provided, the locale in the request context will be switched 293 * to the provided locale. This influences only the behavior of the 294 * {@link org.opencms.staticexport.CmsLocalePrefixLinkSubstitutionHandler}.</p> 295 * 296 * 297 * Relative links are converted to absolute links, using the current element URI as base.<p> 298 * @param params TODO 299 * @param req the current request 300 * 301 * @return the target link adjusted according to the web application path and the OpenCms static export rules 302 * 303 * @see #linkTagAction(String, ServletRequest) 304 * 305 * @since 8.0.3 306 */ 307 public static String linkTagAction(Parameters params, ServletRequest req) { 308 309 CmsFlexController controller = CmsFlexController.getController(req); 310 // be sure the link is absolute 311 String uri = CmsLinkManager.getAbsoluteUri(params.getTarget(), controller.getCurrentRequest().getElementUri()); 312 CmsObject cms = prepareCmsObject(controller.getCmsObject(), params); 313 CmsLinkManager linkManager = OpenCms.getLinkManager(); 314 // generate the link 315 switch (params.getType()) { 316 case ONLINE: 317 return linkManager.getOnlineLink(cms, uri, params.getDetailPage(), false); 318 case PERMA: 319 return linkManager.getPermalink(cms, uri); 320 case SERVER: 321 return linkManager.getServerLink(cms, uri); 322 case DEFAULT: 323 default: 324 return linkManager.substituteLinkForUnknownTarget(cms, uri, params.getDetailPage(), false); 325 326 } 327 } 328 329 /** 330 * Returns a link to a file in the OpenCms VFS 331 * that has been adjusted according to the web application path and the 332 * OpenCms static export rules.<p> 333 * 334 * The current OpenCms user context URI will be used as source of the link.</p> 335 * 336 * Since OpenCms version 7.0.2, you can also use this method in case you are not sure 337 * if the link is internal or external, as 338 * {@link CmsLinkManager#substituteLinkForUnknownTarget(org.opencms.file.CmsObject, String)} 339 * is used to calculate the link target.<p> 340 * 341 * Relative links are converted to absolute links, using the current element URI as base.<p> 342 * 343 * @param target the link that should be calculated, can be relative or absolute 344 * @param req the current request 345 * 346 * @return the target link adjusted according to the web application path and the OpenCms static export rules 347 * 348 * @see org.opencms.staticexport.CmsLinkManager#substituteLinkForUnknownTarget(org.opencms.file.CmsObject, String) 349 */ 350 public static String linkTagAction(String target, ServletRequest req) { 351 352 return linkTagAction(target, req, null); 353 } 354 355 /** 356 * Returns a link to a file in the OpenCms VFS 357 * that has been adjusted according to the web application path and the 358 * OpenCms static export rules.<p> 359 * 360 * If the <code>baseUri</code> parameter is provided, this will be treated as the source of the link, 361 * if this is <code>null</code> then the current OpenCms user context URI will be used as source.</p> 362 * 363 * Relative links are converted to absolute links, using the current element URI as base.<p> 364 * 365 * @param target the link that should be calculated, can be relative or absolute 366 * @param req the current request 367 * @param baseUri the base URI for the link source 368 * 369 * @return the target link adjusted according to the web application path and the OpenCms static export rules 370 * 371 * @see #linkTagAction(String, ServletRequest) 372 * 373 * @since 8.0.3 374 */ 375 public static String linkTagAction(String target, ServletRequest req, String baseUri) { 376 377 return linkTagAction(target, req, baseUri, null); 378 } 379 380 /** 381 * Returns a link to a file in the OpenCms VFS 382 * that has been adjusted according to the web application path and the 383 * OpenCms static export rules.<p> 384 * 385 * <p>If the <code>baseUri</code> parameter is provided, this will be treated as the source of the link, 386 * if this is <code>null</code> then the current OpenCms user context URI will be used as source.</p> 387 * 388 * <p>If the <code>locale</code> parameter is provided, the locale in the request context will be switched 389 * to the provided locale. This influences only the behavior of the 390 * {@link org.opencms.staticexport.CmsLocalePrefixLinkSubstitutionHandler}.</p> 391 * 392 * 393 * Relative links are converted to absolute links, using the current element URI as base.<p> 394 * 395 * @param target the link that should be calculated, can be relative or absolute 396 * @param req the current request 397 * @param baseUri the base URI for the link source 398 * @param locale the locale for which the link should be created (see {@link org.opencms.staticexport.CmsLocalePrefixLinkSubstitutionHandler} 399 * 400 * @return the target link adjusted according to the web application path and the OpenCms static export rules 401 * 402 * @see #linkTagAction(String, ServletRequest) 403 * 404 * @since 8.0.3 405 */ 406 public static String linkTagAction(String target, ServletRequest req, String baseUri, Locale locale) { 407 408 return linkTagAction(target, req, baseUri, null, locale); 409 } 410 411 /** 412 * Returns a link to a file in the OpenCms VFS 413 * that has been adjusted according to the web application path and the 414 * OpenCms static export rules.<p> 415 * 416 * <p>If the <code>baseUri</code> parameter is provided, this will be treated as the source of the link, 417 * if this is <code>null</code> then the current OpenCms user context URI will be used as source.</p> 418 * 419 * <p>If the <code>locale</code> parameter is provided, the locale in the request context will be switched 420 * to the provided locale. This influences only the behavior of the 421 * {@link org.opencms.staticexport.CmsLocalePrefixLinkSubstitutionHandler}.</p> 422 * 423 * 424 * Relative links are converted to absolute links, using the current element URI as base.<p> 425 * 426 * @param target the link that should be calculated, can be relative or absolute 427 * @param req the current request 428 * @param baseUri the base URI for the link source 429 * @param detailPage the target detail page, in case of linking to a specific detail page 430 * @param locale the locale for which the link should be created (see {@link org.opencms.staticexport.CmsLocalePrefixLinkSubstitutionHandler} 431 * 432 * @return the target link adjusted according to the web application path and the OpenCms static export rules 433 * 434 * @see #linkTagAction(String, ServletRequest) 435 * 436 * @since 8.0.3 437 */ 438 public static String linkTagAction( 439 String target, 440 ServletRequest req, 441 String baseUri, 442 String detailPage, 443 Locale locale) { 444 445 return linkTagAction(new Parameters(target, baseUri, detailPage, locale, Type.DEFAULT), req); 446 } 447 448 /** 449 * Initializes CmsObject with data from the tag parameters. 450 * 451 * @param cms1 the CmsObject to use as a base 452 * @param params the parameters to use for the initialization 453 * @return the initialized CmsObject 454 */ 455 private static CmsObject prepareCmsObject(CmsObject cms1, Parameters params) { 456 457 CmsObject cms = cms1; 458 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(params.getBaseUri()) || (null != params.getLocale())) { 459 try { 460 cms = OpenCms.initCmsObject(cms); 461 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(params.getBaseUri())) { 462 cms.getRequestContext().setUri(params.getBaseUri()); 463 if (params.getLocale() == null) { 464 Locale baseUriLocale = getBaseUriLocale(cms, params.getBaseUri()); 465 if (baseUriLocale != null) { 466 cms.getRequestContext().setLocale(baseUriLocale); 467 } 468 } 469 } 470 if (null != params.getLocale()) { 471 cms.getRequestContext().setLocale(params.getLocale()); 472 } 473 } catch (CmsException e) { 474 // should not happen, if it does we can't do anything useful and will just keep the original object 475 LOG.debug(e.getLocalizedMessage(), e); 476 } 477 } 478 return cms; 479 } 480 481 /** 482 * @see javax.servlet.jsp.tagext.Tag#doEndTag() 483 * 484 * @return EVAL_PAGE 485 * 486 * @throws JspException in case something goes wrong 487 */ 488 @Override 489 public int doEndTag() throws JspException { 490 491 ServletRequest req = pageContext.getRequest(); 492 493 // This will always be true if the page is called through OpenCms 494 if (CmsFlexController.isCmsRequest(req)) { 495 try { 496 497 // Get link-string from the body and reset body 498 String link = getBodyContent().getString(); 499 getBodyContent().clear(); 500 Parameters params = new Parameters(link, getBaseUri(), getDetailPage(), m_locale, m_type); 501 if (m_var != null) { 502 int scope = PageContext.PAGE_SCOPE; // default 503 if (SCOPE_REQUEST.equalsIgnoreCase(m_scope)) { 504 scope = PageContext.REQUEST_SCOPE; 505 } else if (SCOPE_SESSION.equalsIgnoreCase(m_scope)) { 506 scope = PageContext.SESSION_SCOPE; 507 } else if (SCOPE_APPLICATION.equalsIgnoreCase(m_scope)) { 508 scope = PageContext.APPLICATION_SCOPE; 509 } 510 CmsFlexController controller = CmsFlexController.getController(req); 511 CmsObject cms = prepareCmsObject(controller.getCmsObject(), params); 512 pageContext.setAttribute(m_var, new CmsJspLinkWrapper(cms, link, true), scope); 513 } else { 514 // Calculate the link substitution 515 String newlink = linkTagAction(params, req); 516 // Write the result back to the page 517 getBodyContent().print(newlink); 518 getBodyContent().writeOut(pageContext.getOut()); 519 } 520 } catch (Exception ex) { 521 if (LOG.isErrorEnabled()) { 522 LOG.error(Messages.get().getBundle().key(Messages.ERR_PROCESS_TAG_1, "link"), ex); 523 } 524 throw new JspException(ex); 525 } 526 } 527 return EVAL_PAGE; 528 } 529 530 /** 531 * Returns the base URI used to create the link target.<p> 532 * 533 * @return the base URI used to create the link target 534 */ 535 public String getBaseUri() { 536 537 return m_baseUri; 538 } 539 540 /** 541 * Returns the target detail page path.<p> 542 * 543 * @return the target detail page path 544 */ 545 public String getDetailPage() { 546 547 return m_detailPage; 548 } 549 550 /** 551 * @see javax.servlet.jsp.tagext.Tag#release() 552 */ 553 @Override 554 public void release() { 555 556 super.release(); 557 } 558 559 /** 560 * Sets the base URI used to create the link target.<p> 561 * 562 * @param baseUri the base URI used to create the link target 563 */ 564 public void setBaseUri(String baseUri) { 565 566 m_baseUri = baseUri; 567 } 568 569 /** 570 * Sets the target detail page path.<p> 571 * 572 * @param detailPage the target detail page path 573 */ 574 public void setDetailPage(String detailPage) { 575 if ("".equals(detailPage)) { 576 detailPage = null; 577 } 578 579 m_detailPage = detailPage; 580 } 581 582 /** 583 * Sets the locale to use for the link. 584 * 585 * @param locale the locale to use for the link 586 */ 587 public void setLocale(Locale locale) { 588 589 m_locale = locale; 590 } 591 592 /** 593 * Sets the locale for the link to create. 594 * 595 * @param localeName name of the locale, e.g. "en", "en_US", ... 596 */ 597 public void setLocale(String localeName) { 598 599 m_locale = CmsLocaleManager.getLocale(localeName); 600 } 601 602 /** 603 * Sets the scope (only used in combination with the var parameter). 604 * @param scope the scope for the variable 605 */ 606 public void setScope(String scope) { 607 608 m_scope = scope; 609 } 610 611 /** 612 * Sets the type. 613 * 614 * @param type the link type 615 */ 616 public void setType(String type) { 617 618 if (type == null) { 619 m_type = null; 620 } else { 621 m_type = Type.valueOf(type.toUpperCase()); 622 } 623 624 } 625 626 /** 627 * Sets the type. 628 * 629 * @param type the type 630 */ 631 public void setType(Type type) { 632 633 m_type = type; 634 } 635 636 /** 637 * Sets the variable name to store the result in. 638 * @param var the variable name to store the result in 639 */ 640 public void setVar(String var) { 641 642 m_var = var; 643 } 644 645}