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.workplace.tools.content.propertyviewer; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProperty; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsResourceFilter; 034import org.opencms.file.types.I_CmsResourceType; 035import org.opencms.i18n.CmsMessageContainer; 036import org.opencms.i18n.CmsMessages; 037import org.opencms.jsp.CmsJspActionElement; 038import org.opencms.main.CmsException; 039import org.opencms.main.CmsLog; 040import org.opencms.main.CmsRuntimeException; 041import org.opencms.main.OpenCms; 042import org.opencms.util.CmsStringUtil; 043import org.opencms.workplace.CmsWorkplace; 044import org.opencms.workplace.CmsWorkplaceSettings; 045import org.opencms.workplace.list.A_CmsListDialog; 046import org.opencms.workplace.list.CmsListColumnAlignEnum; 047import org.opencms.workplace.list.CmsListColumnDefinition; 048import org.opencms.workplace.list.CmsListItem; 049import org.opencms.workplace.list.CmsListMetadata; 050import org.opencms.workplace.list.CmsListOrderEnum; 051 052import java.io.FileNotFoundException; 053import java.io.IOException; 054import java.text.DecimalFormat; 055import java.text.NumberFormat; 056import java.util.ArrayList; 057import java.util.Collections; 058import java.util.LinkedList; 059import java.util.List; 060 061import javax.servlet.ServletException; 062import javax.servlet.http.HttpServletRequest; 063import javax.servlet.http.HttpServletResponse; 064import javax.servlet.jsp.PageContext; 065 066import org.apache.commons.logging.Log; 067 068/** 069 * A list that displays properties . 070 * <p> 071 * 072 * Caution: The list ID argument has to be dynamic to prevent caching causing exception in case of varying collumns. 073 * <p> 074 * 075 * @since 7.5.1 076 */ 077public class CmsPropertyviewList extends A_CmsListDialog { 078 079 /** Used for ID column formatting. */ 080 public static final NumberFormat ID_NUMBER_FORMAT = new DecimalFormat("00000"); 081 082 /** list action id constant. */ 083 public static final String LIST_ACTION_NONE = "an"; 084 085 /** list column id constant. */ 086 public static final String LIST_COLUMN_ICON = "lcic"; 087 088 /** list column id constant. */ 089 public static final String LIST_COLUMN_ID = "lcid"; 090 091 /** list column id constant. */ 092 public static final String LIST_COLUMN_PATH = "lcp"; 093 094 /** list column id constant. */ 095 public static final String LIST_COLUMN_PREFIX_PROPERTY = "cnp-"; 096 097 /** List detail all properties info. */ 098 public static final String LIST_DETAIL_ALL_PROPERTIES = "allpropertiesinfo"; 099 100 /** list item detail id constant. */ 101 public static final String LIST_DETAIL_FULLPATH = "df"; 102 103 /** The request parameter for the properties to work on. */ 104 public static final String PARAM_PROPERTIES = "props"; 105 106 /** The request parameter for the property value to search for. */ 107 public static final String PARAM_PROPERTY_VALUE = "propvalue"; 108 109 /** The request parameter for the paths to work on. */ 110 public static final String PARAM_RESOURCES = "paths"; 111 112 /** The request parameter for the paths to work on. */ 113 public static final String PARAM_SIBLINGS = "siblings"; 114 115 /** The log object for this class. */ 116 private static final Log LOG = CmsLog.getLog(CmsPropertyviewList.class); 117 118 /** Message for translation. */ 119 private CmsMessages m_messages; 120 121 /** The paths. */ 122 private String[] m_paths; 123 124 /** The properties. */ 125 private String[] m_props; 126 127 /** The value of the properties to check. */ 128 private String m_propvalue; 129 130 /** Flag for showing siblings. */ 131 private boolean m_siblings; 132 133 /** 134 * Public constructor. 135 * <p> 136 * 137 * @param jsp an initialized JSP action element 138 * 139 * @throws CmsException if something goes wrong. 140 * @throws FileNotFoundException if something goes wrong. 141 */ 142 public CmsPropertyviewList(CmsJspActionElement jsp) 143 throws FileNotFoundException, CmsException { 144 145 this(jsp, "proplist", Messages.get().container(Messages.GUI_LIST_PROPERTYVIEW_NAME_0)); 146 } 147 148 /** 149 * Public constructor. 150 * <p> 151 * @param jsp an initialized JSP action element 152 * @param listId the id of the list 153 * @param listName the list name 154 * 155 * @throws CmsException if something goes wrong. 156 * @throws FileNotFoundException if something goes wrong. 157 */ 158 public CmsPropertyviewList(CmsJspActionElement jsp, String listId, CmsMessageContainer listName) 159 throws FileNotFoundException, CmsException { 160 161 this(jsp, listId, listName, LIST_COLUMN_ID, CmsListOrderEnum.ORDER_ASCENDING, null); 162 } 163 164 /** 165 * Public constructor. 166 * <p> 167 * @param jsp an initialized JSP action element 168 * @param listId the id of the displayed list 169 * @param listName the name of the list 170 * @param sortedColId the a priory sorted column 171 * @param sortOrder the order of the sorted column 172 * @param searchableColId the column to search into 173 * 174 * @throws CmsException if something goes wrong. 175 * @throws FileNotFoundException if something goes wrong. 176 */ 177 @SuppressWarnings("unused") 178 public CmsPropertyviewList( 179 CmsJspActionElement jsp, 180 String listId, 181 CmsMessageContainer listName, 182 String sortedColId, 183 CmsListOrderEnum sortOrder, 184 String searchableColId) 185 throws FileNotFoundException, CmsException { 186 187 super(jsp, listId, listName, sortedColId, sortOrder, searchableColId); 188 m_messages = new CmsMessages( 189 "org.opencms.workplace.tools.content.propertyviewer.messages", 190 jsp.getRequestContext().getLocale()); 191 } 192 193 /** 194 * Public constructor. 195 * <p> 196 * 197 * Public constructor with JSP variables. 198 * <p> 199 * @param context the JSP page context 200 * @param req the JSP request 201 * @param res the JSP response 202 * 203 * @throws CmsException if something goes wrong. 204 * @throws FileNotFoundException if something goes wrong. 205 */ 206 public CmsPropertyviewList(final PageContext context, final HttpServletRequest req, final HttpServletResponse res) 207 throws FileNotFoundException, CmsException { 208 209 this(new CmsJspActionElement(context, req, res)); 210 } 211 212 /** 213 * @see org.opencms.workplace.list.A_CmsListDialog#executeListMultiActions() 214 */ 215 @SuppressWarnings("unused") 216 @Override 217 public void executeListMultiActions() throws IOException, ServletException, CmsRuntimeException { 218 219 // nothing to do 220 } 221 222 /** 223 * @see org.opencms.workplace.list.A_CmsListDialog#executeListSingleActions() 224 */ 225 @SuppressWarnings("unused") 226 @Override 227 public void executeListSingleActions() throws IOException, ServletException, CmsRuntimeException { 228 229 // nothing to do 230 } 231 232 /** 233 * @return the paths 234 */ 235 public String getParamPaths() { 236 237 return CmsStringUtil.arrayAsString(m_paths, ","); 238 } 239 240 /** 241 * @return the props 242 */ 243 public String getParamProps() { 244 245 return CmsStringUtil.arrayAsString(m_props, ","); 246 } 247 248 /** 249 * Returns the property value parameter.<p> 250 * 251 * @return the property value 252 * 253 */ 254 public String getParamPropvalue() { 255 256 return m_propvalue; 257 } 258 259 /** 260 * Returns true if siblings are shown. 261 * <p> 262 * 263 * @return true if siblings are shown. 264 */ 265 public String getParamSiblings() { 266 267 return Boolean.toString(m_siblings); 268 } 269 270 /** 271 * @param paths the paths to set 272 */ 273 public void setParamPaths(final String paths) { 274 275 m_paths = CmsStringUtil.splitAsArray(paths, ','); 276 } 277 278 /** 279 * @param props the props to set 280 */ 281 public void setParamProps(final String props) { 282 283 m_props = CmsStringUtil.splitAsArray(props, ','); 284 } 285 286 /** 287 * Sets the property value parameter.<p> 288 * 289 * @param propvalue the property value to set 290 */ 291 public void setParamPropvalue(final String propvalue) { 292 293 m_propvalue = propvalue; 294 } 295 296 /** 297 * Set if siblings should be shown. 298 * <p> 299 * 300 * @param showSiblings if siblings should be shown. 301 */ 302 public void setParamSiblings(final String showSiblings) { 303 304 m_siblings = Boolean.parseBoolean(showSiblings); 305 } 306 307 /** 308 * @see org.opencms.workplace.list.A_CmsListDialog#fillDetails(java.lang.String) 309 */ 310 @Override 311 protected void fillDetails(final String detailId) { 312 313 // nothing to do 314 } 315 316 /** 317 * @see org.opencms.workplace.list.A_CmsListDialog#getListItems() 318 */ 319 @Override 320 protected List<CmsListItem> getListItems() { 321 322 List<CmsListItem> result = new ArrayList<CmsListItem>(); 323 // get content 324 CmsListItem item; 325 int idCounter = 0; 326 CmsObject cms = getCms(); 327 for (CmsResource resource : getResources()) { 328 item = getList().newItem(resource.getRootPath()); 329 if (fillItem(resource, item, false, idCounter)) { 330 // there is at least one property to display with content 331 idCounter++; 332 result.add(item); 333 } 334 335 if (m_siblings) { 336 try { 337 List<CmsResource> siblings = cms.readSiblings(cms.getSitePath(resource), CmsResourceFilter.ALL); 338 for (CmsResource sibling : siblings) { 339 // Don't render siblings that are in the path: 340 if (!isInPaths(sibling)) { 341 item = getList().newItem(sibling.getRootPath()); 342 if (fillItem(sibling, item, true, idCounter)) { 343 // there is at least one property to display with content 344 idCounter++; 345 result.add(item); 346 } 347 } 348 } 349 } catch (CmsException e) { 350 if (LOG.isErrorEnabled()) { 351 LOG.error( 352 Messages.get().getBundle().key( 353 Messages.LOG_ERR_PROPERTYVIEWER_READSIBL_1, 354 resource.getRootPath()), 355 e); 356 } 357 } 358 } 359 } 360 return result; 361 } 362 363 /** 364 * @see org.opencms.workplace.CmsWorkplace#initMessages() 365 */ 366 @Override 367 protected void initMessages() { 368 369 // add specific dialog resource bundle 370 addMessages(Messages.get().getBundleName()); 371 // add default resource bundles 372 super.initMessages(); 373 } 374 375 /** 376 * @see org.opencms.workplace.list.A_CmsListDialog#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, 377 * javax.servlet.http.HttpServletRequest) 378 */ 379 @Override 380 protected void initWorkplaceRequestValues(final CmsWorkplaceSettings settings, final HttpServletRequest request) { 381 382 super.initWorkplaceRequestValues(settings, request); 383 } 384 385 /** 386 * @see org.opencms.workplace.list.A_CmsListDialog#listRecovery(java.lang.String) 387 */ 388 @Override 389 protected synchronized void listRecovery(final String listId) { 390 391 // nothing to do 392 } 393 394 /** 395 * @see org.opencms.workplace.list.A_CmsListDialog#setColumns(org.opencms.workplace.list.CmsListMetadata) 396 */ 397 @Override 398 protected void setColumns(CmsListMetadata metadata) { 399 400 // enforce re-invocation of this method because columns are varying and must not be cached: 401 metadata.setVolatile(true); 402 403 // add column for icon 404 CmsListColumnDefinition iconCol = new CmsListColumnDefinition(LIST_COLUMN_ICON); 405 iconCol.setName(Messages.get().container(Messages.GUI_LIST_PROPERTYVIEW_COL_ICON_NAME_0)); 406 iconCol.setHelpText(Messages.get().container(Messages.GUI_LIST_PROPERTYVIEW_COL_ICON_HELP_0)); 407 iconCol.setAlign(CmsListColumnAlignEnum.ALIGN_LEFT); 408 iconCol.setWidth("16"); 409 iconCol.setSorteable(false); 410 metadata.addColumn(iconCol); 411 iconCol.setPrintable(true); 412 413 // add column for invisible ID (needed for sorting to show siblings below each other: 414 CmsListColumnDefinition idCol = new CmsListColumnDefinition(LIST_COLUMN_ID); 415 idCol.setName(Messages.get().container(Messages.GUI_LIST_PROPERTYVIEW_COL_ID_NAME_0)); 416 idCol.setHelpText(Messages.get().container(Messages.GUI_LIST_PROPERTYVIEW_COL_ID_HELP_0)); 417 idCol.setAlign(CmsListColumnAlignEnum.ALIGN_LEFT); 418 idCol.setSorteable(false); 419 idCol.setVisible(false); 420 metadata.addColumn(idCol); 421 idCol.setPrintable(true); 422 423 // add column for name 424 CmsListColumnDefinition nameCol = new CmsListColumnDefinition(LIST_COLUMN_PATH); 425 nameCol.setName(Messages.get().container(Messages.GUI_LIST_PROPERTYVIEW_COL_PATH_NAME_0)); 426 nameCol.setHelpText(Messages.get().container(Messages.GUI_LIST_PROPERTYVIEW_COL_PATH_HELP_0)); 427 nameCol.setAlign(CmsListColumnAlignEnum.ALIGN_LEFT); 428 nameCol.setSorteable(false); 429 metadata.addColumn(nameCol); 430 nameCol.setPrintable(true); 431 432 // add columns for properties: 433 CmsListColumnDefinition propCol; 434 for (String property : m_props) { 435 propCol = new CmsListColumnDefinition(getPropertyColumnID(property)); 436 propCol.setName( 437 Messages.get().container(Messages.GUI_LIST_PROPERTYVIEW_COL_PROPERTY_NAME_1, new Object[] {property})); 438 propCol.setHelpText(Messages.get().container(Messages.GUI_LIST_PROPERTYVIEW_COL_PROPERTY_HELP_0)); 439 propCol.setAlign(CmsListColumnAlignEnum.ALIGN_LEFT); 440 propCol.setSorteable(false); 441 metadata.addColumn(propCol); 442 propCol.setPrintable(true); 443 } 444 445 } 446 447 /** 448 * @see org.opencms.workplace.list.A_CmsListDialog#setIndependentActions(org.opencms.workplace.list.CmsListMetadata) 449 */ 450 @Override 451 protected void setIndependentActions(CmsListMetadata metadata) { 452 453 // nothing to do here 454 } 455 456 /** 457 * @see org.opencms.workplace.list.A_CmsListDialog#setMultiActions(org.opencms.workplace.list.CmsListMetadata) 458 */ 459 @Override 460 protected void setMultiActions(final CmsListMetadata metadata) { 461 462 // do nothing here 463 } 464 465 /** 466 * Fills a single item. 467 * <p> 468 * @param resource the corresponding resource. 469 * @param item the item to fill 470 * @param isSibling if false no boldface markup will be marked. 471 * @param id used for the ID column. 472 * 473 * @return true if the item contains at least one property with content, false if there is no property with content 474 */ 475 private boolean fillItem( 476 final CmsResource resource, 477 final CmsListItem item, 478 final boolean isSibling, 479 final int id) { 480 481 item.set(LIST_COLUMN_ID, ID_NUMBER_FORMAT.format(id)); 482 I_CmsResourceType type; 483 CmsObject cms = getCms(); 484 String iconPath; 485 String pathValue; 486 String sitePath = cms.getSitePath(resource); 487 if (!isSibling) { 488 sitePath = "<b>" + sitePath + "</b>"; 489 } 490 item.set(LIST_COLUMN_PATH, sitePath); 491 // flag is true, if there is at least one property to display with content 492 boolean onePropCont = false; 493 for (String property : m_props) { 494 CmsProperty prop; 495 try { 496 497 prop = cms.readPropertyObject(resource, property, false); 498 if (prop.isNullProperty()) { 499 pathValue = m_messages.key("GUI_LIST_PROPERTYVIEW_NOTFOUND_0"); 500 } else { 501 pathValue = prop.getValue(); 502 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getParamPropvalue())) { 503 if (prop.getValue().contains(getParamPropvalue())) { 504 onePropCont = true; 505 } 506 } else { 507 onePropCont = true; 508 } 509 } 510 item.set(getPropertyColumnID(property), pathValue); 511 512 } catch (CmsException e) { 513 if (LOG.isErrorEnabled()) { 514 LOG.error( 515 Messages.get().getBundle().key( 516 Messages.LOG_ERR_PROPERTYVIEWER_READONEPROP_2, 517 property, 518 resource.getRootPath()), 519 e); 520 } 521 item.set(getPropertyColumnID(property), "n/a"); 522 } 523 } 524 // check if there is at least one property to display with content 525 if (!onePropCont) { 526 // there is no property to display with content 527 return false; 528 } 529 530 type = OpenCms.getResourceManager().getResourceType(resource); 531 iconPath = getSkinUri() 532 + CmsWorkplace.RES_PATH_FILETYPES 533 + OpenCms.getWorkplaceManager().getExplorerTypeSetting(type.getTypeName()).getIcon(); 534 String iconImage; 535 536 if (isSibling) { 537 iconImage = "<div style=\"background-image: url(" 538 + iconPath 539 + "); padding:0px;background-position: 0px; margin:0px; background-repeat: no-repeat;\">" 540 + "<img height=\"16\" border=\"0\" width=\"16\" src=\"" 541 + getSkinUri() 542 + "/explorer/link.gif\"/></div>"; 543 } else { 544 iconImage = "<img src=\"" + iconPath + "\" alt=\"icon\" />"; 545 } 546 item.set(LIST_COLUMN_ICON, iconImage); 547 // there is at least one property to display with content 548 return true; 549 } 550 551 /** 552 * Returns the list column constant for the given property. 553 * <p> 554 * @param property the property that will be shown in the column. 555 * 556 * @return the list column constant for the given property. 557 */ 558 private String getPropertyColumnID(final String property) { 559 560 String result = LIST_COLUMN_PREFIX_PROPERTY + property; 561 return result; 562 } 563 564 /** 565 * Internally reads the resources to use.<p> 566 * 567 * @return the resources to use. 568 */ 569 private List<CmsResource> getResources() { 570 571 List<CmsResource> result = new LinkedList<CmsResource>(); 572 CmsObject cms = getCms(); 573 CmsResourceFilter filter = CmsResourceFilter.ALL; 574 try { 575 for (String path : m_paths) { 576 List<CmsResource> resources = cms.readResources(path, filter, true); 577 result.addAll(resources); 578 } 579 } catch (CmsException e) { 580 if (LOG.isErrorEnabled()) { 581 LOG.error(Messages.get().getBundle().key(Messages.LOG_ERR_PROPERTYVIEWER_READRESOURCES_0), e); 582 } 583 result = Collections.emptyList(); 584 } 585 return result; 586 } 587 588 /** 589 * Checks if the resource is in the selected path.<p> 590 * 591 * @param resource the resource to check 592 * 593 * @return true, if the resource is in the selected path, otherwise false 594 */ 595 private boolean isInPaths(final CmsResource resource) { 596 597 boolean result = false; 598 String resourcePath = getCms().getSitePath(resource); 599 for (String path : m_paths) { 600 if (resourcePath.startsWith(path)) { 601 result = true; 602 break; 603 } 604 } 605 return result; 606 607 } 608 609}