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.collectors.I_CmsResourceCollector; 033import org.opencms.flex.CmsFlexController; 034import org.opencms.jsp.util.CmsJspResourceLoadBean; 035import org.opencms.main.CmsException; 036import org.opencms.main.CmsIllegalArgumentException; 037import org.opencms.main.OpenCms; 038import org.opencms.util.CmsMacroResolver; 039import org.opencms.util.CmsStringUtil; 040 041import java.util.List; 042 043import javax.servlet.jsp.JspException; 044import javax.servlet.jsp.PageContext; 045import javax.servlet.jsp.tagext.Tag; 046 047/** 048 * Implementation of the <code><cms:resourceload/></code> tag, 049 * used to access and display resource information from the VFS.<p> 050 * 051 * @since 8.0 052 */ 053public class CmsJspTagResourceLoad extends CmsJspScopedVarBodyTagSuport implements I_CmsResourceContainer { 054 055 /** Serial version UID required for safe serialization. */ 056 private static final long serialVersionUID = -3753361821868919139L; 057 058 /** The CmsObject for the current user. */ 059 protected transient CmsObject m_cms; 060 061 /** The name of the collector to use for list building. */ 062 protected String m_collector; 063 064 /** The name of the resource collector used. */ 065 protected String m_collectorName; 066 067 /** The parameters of the resource collector uses. */ 068 protected String m_collectorParam; 069 070 /** The list of collected resource items. */ 071 protected List<CmsResource> m_collectorResult; 072 073 /** The bean to store information required to make the result list browsable. */ 074 protected CmsContentInfoBean m_contentInfoBean; 075 076 /** The FlexController for the current request. */ 077 protected CmsFlexController m_controller; 078 079 /** The index of the current page that gets displayed. */ 080 protected String m_pageIndex; 081 082 /** The number of page links in the Google-like page navigation. */ 083 protected String m_pageNavLength; 084 085 /** The size of a page to be displayed. */ 086 protected String m_pageSize; 087 088 /** Parameter used for the collector. */ 089 protected String m_param; 090 091 /** Indicates if the collector results should be preloaded. */ 092 protected boolean m_preload; 093 094 /** The (optional) property to extend the parameter with. */ 095 protected String m_property; 096 097 /** Reference to the last loaded resource element. */ 098 protected transient CmsResource m_resource; 099 100 /** The file name to load the current content value from. */ 101 protected String m_resourceName; 102 103 /** 104 * Empty constructor, required for JSP tags.<p> 105 */ 106 public CmsJspTagResourceLoad() { 107 108 super(); 109 } 110 111 /** 112 * Constructor used when using <code>resourceload</code> from scriptlet code.<p> 113 * 114 * @param container the parent resource container (could be a preloader) 115 * @param context the JSP page context 116 * @param collectorName the collector name to use 117 * @param collectorParam the collector param to use 118 * 119 * @throws JspException in case something goes wrong 120 */ 121 public CmsJspTagResourceLoad( 122 I_CmsResourceContainer container, 123 PageContext context, 124 String collectorName, 125 String collectorParam) 126 throws JspException { 127 128 this(container, context, collectorName, collectorParam, null, null); 129 } 130 131 /** 132 * Constructor used when using <code>resourceload</code> from scriptlet code.<p> 133 * 134 * @param container the parent resource container (could be a preloader) 135 * @param context the JSP page context 136 * @param collectorName the collector name to use 137 * @param collectorParam the collector param to use 138 * @param pageIndex the display page index (may contain macros) 139 * @param pageSize the display page size (may contain macros) 140 * 141 * @throws JspException in case something goes wrong 142 */ 143 public CmsJspTagResourceLoad( 144 I_CmsResourceContainer container, 145 PageContext context, 146 String collectorName, 147 String collectorParam, 148 String pageIndex, 149 String pageSize) 150 throws JspException { 151 152 setCollector(collectorName); 153 setParam(collectorParam); 154 setPageIndex(pageIndex); 155 setPageSize(pageSize); 156 m_preload = false; 157 158 setPageContext(context); 159 init(container); 160 } 161 162 /** 163 * Returns the resource name currently processed.<p> 164 * 165 * @param cms the current OpenCms user context 166 * @param contentContainer the current resource container 167 * 168 * @return the resource name currently processed 169 */ 170 protected static String getResourceName(CmsObject cms, I_CmsResourceContainer contentContainer) { 171 172 if ((contentContainer != null) && (contentContainer.getResourceName() != null)) { 173 return contentContainer.getResourceName(); 174 } else if (cms != null) { 175 return cms.getRequestContext().getUri(); 176 } else { 177 return null; 178 } 179 } 180 181 /** 182 * Limits the collector's result list to the size of a page to be displayed in a JSP.<p> 183 * 184 * @param contentInfoBean the info bean of the collector 185 * @param collectorResult the result list of the collector 186 * 187 * @return a limited collector's result list 188 */ 189 protected static List<CmsResource> limitCollectorResult( 190 CmsContentInfoBean contentInfoBean, 191 List<CmsResource> collectorResult) { 192 193 List<CmsResource> result = null; 194 int pageCount = -1; 195 196 if (contentInfoBean.getPageSize() > 0) { 197 198 pageCount = collectorResult.size() / contentInfoBean.getPageSize(); 199 if ((collectorResult.size() % contentInfoBean.getPageSize()) != 0) { 200 pageCount++; 201 } 202 203 contentInfoBean.setPageCount(pageCount); 204 205 int startIndex = (contentInfoBean.getPageIndex() - 1) * contentInfoBean.getPageSize(); 206 int endIndex = contentInfoBean.getPageIndex() * contentInfoBean.getPageSize(); 207 if (endIndex > collectorResult.size()) { 208 endIndex = collectorResult.size(); 209 } 210 211 result = collectorResult.subList(startIndex, endIndex); 212 } else { 213 214 result = collectorResult; 215 if (collectorResult.size() > 0) { 216 contentInfoBean.setPageCount(1); 217 } 218 } 219 220 return result; 221 } 222 223 /** 224 * @see javax.servlet.jsp.tagext.BodyTagSupport#doAfterBody() 225 */ 226 @Override 227 public int doAfterBody() throws JspException { 228 229 // close open direct edit first 230 if (hasMoreResources()) { 231 // another loop is required 232 return EVAL_BODY_AGAIN; 233 } 234 if (OpenCms.getSystemInfo().getServletContainerSettings().isReleaseTagsAfterEnd()) { 235 // need to release manually, JSP container may not call release as required (happens with Tomcat) 236 release(); 237 } 238 // no more files are available, so skip the body and finish the loop 239 return SKIP_BODY; 240 } 241 242 /** 243 * @see javax.servlet.jsp.tagext.Tag#doEndTag() 244 */ 245 @Override 246 public int doEndTag() { 247 248 release(); 249 return EVAL_PAGE; 250 } 251 252 /** 253 * @see javax.servlet.jsp.tagext.Tag#doStartTag() 254 */ 255 @Override 256 public int doStartTag() throws JspException, CmsIllegalArgumentException { 257 258 // get a reference to the parent "content container" class (if available) 259 Tag ancestor = findAncestorWithClass(this, I_CmsResourceContainer.class); 260 I_CmsResourceContainer container = null; 261 if (ancestor != null) { 262 // parent content container available, use preloaded values from this container 263 container = (I_CmsResourceContainer)ancestor; 264 // check if container really is a preloader 265 if (!container.isPreloader()) { 266 // don't use ancestor if not a preloader 267 container = null; 268 } 269 } 270 271 // initialize the content load tag 272 init(container); 273 274 hasMoreResources(); 275 return isScopeVarSet() ? SKIP_BODY : EVAL_BODY_INCLUDE; 276 } 277 278 /** 279 * Returns the collector.<p> 280 * 281 * @return the collector 282 */ 283 public String getCollector() { 284 285 return m_collector; 286 } 287 288 /** 289 * @see org.opencms.jsp.I_CmsResourceContainer#getCollectorName() 290 */ 291 public String getCollectorName() { 292 293 return m_collectorName; 294 } 295 296 /** 297 * @see org.opencms.jsp.I_CmsResourceContainer#getCollectorParam() 298 */ 299 public String getCollectorParam() { 300 301 return m_collectorParam; 302 } 303 304 /** 305 * @see org.opencms.jsp.I_CmsResourceContainer#getCollectorResult() 306 */ 307 public List<CmsResource> getCollectorResult() { 308 309 return m_collectorResult; 310 } 311 312 /** 313 * Returns the index of the page to be displayed.<p> 314 * 315 * @return the index of the page to be displayed 316 */ 317 public String getPageIndex() { 318 319 return m_pageIndex; 320 } 321 322 /** 323 * Returns the number of page links in the Google-like page navigation.<p> 324 * 325 * @return the number of page links in the Google-like page navigation 326 */ 327 public String getPageNavLength() { 328 329 return m_pageNavLength; 330 } 331 332 /** 333 * Returns the size of a single page to be displayed.<p> 334 * 335 * @return the size of a single page to be displayed 336 */ 337 public String getPageSize() { 338 339 return m_pageSize; 340 } 341 342 /** 343 * Returns the collector parameter.<p> 344 * 345 * @return the collector parameter 346 */ 347 public String getParam() { 348 349 return m_param; 350 } 351 352 /** 353 * Returns <code>"true"</code> if this content load tag should only preload the values from the collector.<p> 354 * 355 * @return <code>"true"</code> if this content load tag should only preload the values from the collector 356 */ 357 public String getPreload() { 358 359 return String.valueOf(isPreloader()); 360 } 361 362 /** 363 * Returns the property.<p> 364 * 365 * @return the property 366 */ 367 public String getProperty() { 368 369 return m_property; 370 } 371 372 /** 373 * @see org.opencms.jsp.I_CmsResourceContainer#getResource() 374 */ 375 public CmsResource getResource() { 376 377 return m_resource; 378 } 379 380 /** 381 * @see org.opencms.jsp.I_CmsResourceContainer#getResourceName() 382 */ 383 public String getResourceName() { 384 385 return m_resourceName; 386 } 387 388 /** 389 * @see org.opencms.jsp.I_CmsResourceContainer#hasMoreContent() 390 */ 391 @Deprecated 392 public boolean hasMoreContent() throws JspException { 393 394 return hasMoreResources(); 395 } 396 397 /** 398 * @see org.opencms.jsp.I_CmsResourceContainer#hasMoreResources() 399 */ 400 @SuppressWarnings("unused") 401 public boolean hasMoreResources() throws JspException { 402 403 if (isPreloader()) { 404 // if in preload mode, no result is required 405 return false; 406 } 407 408 // check if there are more files to iterate 409 boolean hasMoreResources = m_collectorResult.size() > 0; 410 if (hasMoreResources) { 411 // there are more results available... 412 doLoadNextResource(); 413 } 414 415 return hasMoreResources; 416 } 417 418 /** 419 * @see org.opencms.jsp.I_CmsResourceContainer#isPreloader() 420 */ 421 public boolean isPreloader() { 422 423 return isScopeVarSet() ? true : m_preload; 424 } 425 426 /** 427 * @see javax.servlet.jsp.tagext.Tag#release() 428 */ 429 @Override 430 public void release() { 431 432 m_cms = null; 433 m_collector = null; 434 m_collectorName = null; 435 m_collectorParam = null; 436 m_collectorResult = null; 437 m_resource = null; 438 m_contentInfoBean = null; 439 m_controller = null; 440 m_pageIndex = null; 441 m_pageNavLength = null; 442 m_pageSize = null; 443 m_param = null; 444 m_preload = false; 445 m_property = null; 446 m_resourceName = null; 447 super.release(); 448 } 449 450 /** 451 * Sets the collector name.<p> 452 * 453 * @param collector the collector name to set 454 */ 455 public void setCollector(String collector) { 456 457 m_collector = collector; 458 } 459 460 /** 461 * Sets the index of the page to be displayed.<p> 462 * 463 * @param pageIndex the index of the page to be displayed 464 */ 465 public void setPageIndex(String pageIndex) { 466 467 m_pageIndex = pageIndex; 468 } 469 470 /** 471 * Sets the number of page links in the Google-like page navigation.<p> 472 * 473 * @param pageNavLength the number of page links in the Google-like page navigation 474 */ 475 public void setPageNavLength(String pageNavLength) { 476 477 m_pageNavLength = pageNavLength; 478 } 479 480 /** 481 * Sets the size of a single page to be displayed.<p> 482 * 483 * @param pageSize the size of a single page to be displayed 484 */ 485 public void setPageSize(String pageSize) { 486 487 m_pageSize = pageSize; 488 } 489 490 /** 491 * Sets the collector parameter.<p> 492 * 493 * @param param the collector parameter to set 494 */ 495 public void setParam(String param) { 496 497 m_param = param; 498 } 499 500 /** 501 * Sets the preload flag for this resource load tag.<p> 502 * 503 * If this is set to <code>true</code>, then the collector result will only 504 * be preloaded, but not iterated.<p> 505 * 506 * @param preload the preload flag to set 507 */ 508 public void setPreload(String preload) { 509 510 m_preload = Boolean.valueOf(preload).booleanValue(); 511 } 512 513 /** 514 * Sets the property.<p> 515 * 516 * @param property the property to set 517 */ 518 public void setProperty(String property) { 519 520 m_property = property; 521 } 522 523 /** 524 * Load the next resource from the initialized list of resources.<p> 525 */ 526 protected void doLoadNextResource() { 527 528 // get the next resource from the collector 529 CmsResource resource = getNextResource(); 530 if (resource == null) { 531 m_resourceName = null; 532 m_resource = null; 533 return; 534 } 535 536 // set the resource name 537 m_resourceName = m_cms.getSitePath(resource); 538 539 // set the resource 540 m_resource = resource; 541 } 542 543 /** 544 * Returns the content info bean.<p> 545 * 546 * @return the content info bean 547 */ 548 protected CmsContentInfoBean getContentInfoBean() { 549 550 return m_contentInfoBean; 551 } 552 553 /** 554 * Returns the next resource from the collector.<p> 555 * 556 * @return the next resource from the collector 557 */ 558 protected CmsResource getNextResource() { 559 560 if ((m_collectorResult != null) && (m_collectorResult.size() > 0)) { 561 562 m_contentInfoBean.incResultIndex(); 563 return m_collectorResult.remove(0); 564 } 565 566 return null; 567 } 568 569 /** 570 * Initializes this content load tag.<p> 571 * 572 * @param container the parent container (could be a preloader) 573 * 574 * @throws JspException in case something goes wrong 575 */ 576 protected void init(I_CmsResourceContainer container) throws JspException { 577 578 // check if the tag contains a pageSize, pageIndex and pageNavLength attribute, or none of them 579 int pageAttribCount = 0; 580 pageAttribCount += CmsStringUtil.isNotEmpty(m_pageSize) ? 1 : 0; 581 pageAttribCount += CmsStringUtil.isNotEmpty(m_pageIndex) ? 1 : 0; 582 583 if ((pageAttribCount > 0) && (pageAttribCount < 2)) { 584 throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_TAG_RESOURCELOAD_INDEX_SIZE_0)); 585 } 586 587 I_CmsResourceContainer usedContainer; 588 if (container == null) { 589 // no preloading ancestor has been found 590 usedContainer = this; 591 if (CmsStringUtil.isEmpty(m_collector)) { 592 // check if the tag contains a collector attribute 593 throw new CmsIllegalArgumentException( 594 Messages.get().container(Messages.ERR_TAG_RESOURCELOAD_MISSING_COLLECTOR_0)); 595 } 596 if (CmsStringUtil.isEmpty(m_param)) { 597 // check if the tag contains a param attribute 598 throw new CmsIllegalArgumentException( 599 Messages.get().container(Messages.ERR_TAG_RESOURCELOAD_MISSING_PARAM_0)); 600 } 601 } else { 602 // use provided container (preloading ancestor) 603 usedContainer = container; 604 } 605 606 // initialize OpenCms access objects 607 m_controller = CmsFlexController.getController(pageContext.getRequest()); 608 m_cms = m_controller.getCmsObject(); 609 610 // get the resource name from the selected container 611 String resourcename = getResourceName(m_cms, usedContainer); 612 613 // initialize a string mapper to resolve EL like strings in tag attributes 614 CmsMacroResolver resolver = CmsMacroResolver.newInstance().setCmsObject(m_cms).setJspPageContext( 615 pageContext).setResourceName(resourcename).setKeepEmptyMacros(true); 616 617 // resolve the collector name 618 if (container == null) { 619 // no preload parent container, initialize new values 620 m_collectorName = resolver.resolveMacros(getCollector()); 621 // resolve the parameter 622 m_collectorParam = resolver.resolveMacros(getParam()); 623 m_collectorResult = null; 624 } else { 625 // preload parent content container available, use values from this container 626 m_collectorName = usedContainer.getCollectorName(); 627 m_collectorParam = usedContainer.getCollectorParam(); 628 m_collectorResult = usedContainer.getCollectorResult(); 629 } 630 631 try { 632 // now collect the resources 633 I_CmsResourceCollector collector = OpenCms.getResourceManager().getContentCollector(m_collectorName); 634 if (collector == null) { 635 throw new CmsException(Messages.get().container(Messages.ERR_COLLECTOR_NOT_FOUND_1, m_collectorName)); 636 } 637 // execute the collector if not already done in parent tag 638 if (m_collectorResult == null) { 639 m_collectorResult = collector.getResults(m_cms, m_collectorName, m_collectorParam); 640 } 641 642 m_contentInfoBean = new CmsContentInfoBean(); 643 m_contentInfoBean.setPageSizeAsString(resolver.resolveMacros(m_pageSize)); 644 m_contentInfoBean.setPageIndexAsString(resolver.resolveMacros(m_pageIndex)); 645 m_contentInfoBean.setPageNavLengthAsString(resolver.resolveMacros(m_pageNavLength)); 646 m_contentInfoBean.setResultSize(m_collectorResult.size()); 647 m_contentInfoBean.initResultIndex(); 648 649 if (!isPreloader()) { 650 // not required when only preloading 651 m_collectorResult = CmsJspTagResourceLoad.limitCollectorResult(m_contentInfoBean, m_collectorResult); 652 m_contentInfoBean.initPageNavIndexes(); 653 } else if (isScopeVarSet()) { 654 // scope variable is set, store resource load bean in JSP context 655 CmsJspResourceLoadBean bean = new CmsJspResourceLoadBean(m_cms, m_collectorResult); 656 storeAttribute(bean); 657 } 658 659 } catch (CmsException e) { 660 m_controller.setThrowable(e, m_cms.getRequestContext().getUri()); 661 throw new JspException(e); 662 } 663 } 664}