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, 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.ade.sitemap; 029 030import org.opencms.ade.configuration.CmsADEConfigData; 031import org.opencms.ade.configuration.CmsADEManager; 032import org.opencms.ade.configuration.CmsFunctionReference; 033import org.opencms.ade.configuration.CmsModelPageConfig; 034import org.opencms.ade.configuration.CmsResourceTypeConfig; 035import org.opencms.ade.detailpage.CmsDetailPageConfigurationWriter; 036import org.opencms.ade.detailpage.CmsDetailPageInfo; 037import org.opencms.ade.sitemap.shared.CmsClientSitemapEntry; 038import org.opencms.ade.sitemap.shared.CmsClientSitemapEntry.EntryType; 039import org.opencms.ade.sitemap.shared.CmsDetailPageTable; 040import org.opencms.ade.sitemap.shared.CmsGalleryFolderEntry; 041import org.opencms.ade.sitemap.shared.CmsGalleryType; 042import org.opencms.ade.sitemap.shared.CmsLocaleComparePropertyData; 043import org.opencms.ade.sitemap.shared.CmsModelInfo; 044import org.opencms.ade.sitemap.shared.CmsModelPageEntry; 045import org.opencms.ade.sitemap.shared.CmsNewResourceInfo; 046import org.opencms.ade.sitemap.shared.CmsSitemapCategoryData; 047import org.opencms.ade.sitemap.shared.CmsSitemapChange; 048import org.opencms.ade.sitemap.shared.CmsSitemapChange.ChangeType; 049import org.opencms.ade.sitemap.shared.CmsSitemapClipboardData; 050import org.opencms.ade.sitemap.shared.CmsSitemapData; 051import org.opencms.ade.sitemap.shared.CmsSitemapData.EditorMode; 052import org.opencms.ade.sitemap.shared.CmsSitemapInfo; 053import org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService; 054import org.opencms.configuration.CmsDefaultUserSettings; 055import org.opencms.db.CmsAlias; 056import org.opencms.db.CmsAliasManager; 057import org.opencms.db.CmsRewriteAlias; 058import org.opencms.file.CmsFile; 059import org.opencms.file.CmsObject; 060import org.opencms.file.CmsProject; 061import org.opencms.file.CmsProperty; 062import org.opencms.file.CmsPropertyDefinition; 063import org.opencms.file.CmsResource; 064import org.opencms.file.CmsResourceFilter; 065import org.opencms.file.CmsUser; 066import org.opencms.file.CmsVfsResourceNotFoundException; 067import org.opencms.file.history.CmsHistoryResourceHandler; 068import org.opencms.file.types.CmsResourceTypeFolder; 069import org.opencms.file.types.CmsResourceTypeFolderExtended; 070import org.opencms.file.types.CmsResourceTypeFolderSubSitemap; 071import org.opencms.file.types.CmsResourceTypeFunctionConfig; 072import org.opencms.file.types.CmsResourceTypeUnknownFolder; 073import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 074import org.opencms.file.types.I_CmsResourceType; 075import org.opencms.flex.CmsFlexController; 076import org.opencms.gwt.CmsCoreService; 077import org.opencms.gwt.CmsGwtService; 078import org.opencms.gwt.CmsIconUtil; 079import org.opencms.gwt.CmsPropertyEditorHelper; 080import org.opencms.gwt.CmsRpcException; 081import org.opencms.gwt.CmsTemplateFinder; 082import org.opencms.gwt.shared.CmsBrokenLinkBean; 083import org.opencms.gwt.shared.CmsCategoryTreeEntry; 084import org.opencms.gwt.shared.CmsClientLock; 085import org.opencms.gwt.shared.CmsCoreData; 086import org.opencms.gwt.shared.CmsCoreData.AdeContext; 087import org.opencms.gwt.shared.CmsListInfoBean; 088import org.opencms.gwt.shared.alias.CmsAliasEditValidationReply; 089import org.opencms.gwt.shared.alias.CmsAliasEditValidationRequest; 090import org.opencms.gwt.shared.alias.CmsAliasImportResult; 091import org.opencms.gwt.shared.alias.CmsAliasInitialFetchResult; 092import org.opencms.gwt.shared.alias.CmsAliasSaveValidationRequest; 093import org.opencms.gwt.shared.alias.CmsAliasTableRow; 094import org.opencms.gwt.shared.alias.CmsRewriteAliasTableRow; 095import org.opencms.gwt.shared.alias.CmsRewriteAliasValidationReply; 096import org.opencms.gwt.shared.alias.CmsRewriteAliasValidationRequest; 097import org.opencms.gwt.shared.property.CmsClientProperty; 098import org.opencms.gwt.shared.property.CmsPropertyModification; 099import org.opencms.i18n.CmsLocaleManager; 100import org.opencms.json.JSONArray; 101import org.opencms.jsp.CmsJspNavBuilder; 102import org.opencms.jsp.CmsJspNavBuilder.Visibility; 103import org.opencms.jsp.CmsJspNavElement; 104import org.opencms.loader.CmsLoaderException; 105import org.opencms.lock.CmsLock; 106import org.opencms.lock.CmsLockUtil; 107import org.opencms.main.CmsException; 108import org.opencms.main.CmsLog; 109import org.opencms.main.OpenCms; 110import org.opencms.relations.CmsCategory; 111import org.opencms.relations.CmsCategoryService; 112import org.opencms.search.galleries.CmsGallerySearch; 113import org.opencms.search.galleries.CmsGallerySearchResult; 114import org.opencms.security.CmsPermissionSet; 115import org.opencms.security.CmsRole; 116import org.opencms.security.CmsRoleViolationException; 117import org.opencms.security.CmsSecurityException; 118import org.opencms.site.CmsSite; 119import org.opencms.ui.apps.CmsQuickLaunchLocationCache; 120import org.opencms.util.CmsDateUtil; 121import org.opencms.util.CmsFileUtil; 122import org.opencms.util.CmsStringUtil; 123import org.opencms.util.CmsUUID; 124import org.opencms.workplace.CmsWorkplaceManager; 125import org.opencms.workplace.CmsWorkplaceMessages; 126import org.opencms.workplace.explorer.CmsExplorerTypeAccess; 127import org.opencms.workplace.explorer.CmsExplorerTypeSettings; 128import org.opencms.workplace.galleries.A_CmsAjaxGallery; 129import org.opencms.xml.CmsXmlException; 130import org.opencms.xml.I_CmsXmlDocument; 131import org.opencms.xml.containerpage.CmsADESessionCache; 132import org.opencms.xml.containerpage.CmsContainerBean; 133import org.opencms.xml.containerpage.CmsContainerElementBean; 134import org.opencms.xml.containerpage.CmsContainerPageBean; 135import org.opencms.xml.containerpage.CmsXmlContainerPage; 136import org.opencms.xml.containerpage.CmsXmlContainerPageFactory; 137import org.opencms.xml.containerpage.CmsXmlDynamicFunctionHandler; 138import org.opencms.xml.content.CmsXmlContentFactory; 139import org.opencms.xml.content.CmsXmlContentProperty; 140import org.opencms.xml.types.I_CmsXmlContentValue; 141 142import java.text.DateFormat; 143import java.util.ArrayList; 144import java.util.Arrays; 145import java.util.Collection; 146import java.util.Collections; 147import java.util.Comparator; 148import java.util.Date; 149import java.util.HashMap; 150import java.util.LinkedHashMap; 151import java.util.List; 152import java.util.Locale; 153import java.util.Map; 154import java.util.regex.Pattern; 155import java.util.regex.PatternSyntaxException; 156 157import javax.servlet.http.HttpServletRequest; 158 159import org.apache.commons.logging.Log; 160 161import com.google.common.collect.ComparisonChain; 162import com.google.common.collect.Lists; 163import com.google.common.collect.Maps; 164import com.google.common.collect.Ordering; 165 166/** 167 * Handles all RPC services related to the vfs sitemap.<p> 168 * 169 * @since 8.0.0 170 * 171 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService 172 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapServiceAsync 173 */ 174public class CmsVfsSitemapService extends CmsGwtService implements I_CmsSitemapService { 175 176 /** Helper class for representing information about a lock. */ 177 protected class LockInfo { 178 179 /** The lock state. */ 180 private CmsLock m_lock; 181 182 /** True if the lock was just locked. */ 183 private boolean m_wasJustLocked; 184 185 /** 186 * Creates a new LockInfo object.<p> 187 * 188 * @param lock the lock state 189 * @param wasJustLocked true if the lock was just locked 190 */ 191 public LockInfo(CmsLock lock, boolean wasJustLocked) { 192 193 m_lock = lock; 194 m_wasJustLocked = wasJustLocked; 195 } 196 197 /** 198 * Returns the lock state.<p> 199 * 200 * @return the lock state 201 */ 202 public CmsLock getLock() { 203 204 return m_lock; 205 } 206 207 /** 208 * Returns true if the lock was just locked.<p> 209 * 210 * @return true if the lock was just locked 211 */ 212 public boolean wasJustLocked() { 213 214 return m_wasJustLocked; 215 } 216 } 217 218 /** Properties to remove from the copied template when creating a new sitemap entry. */ 219 public static final List<String> FILTER_PROPERTIES = Arrays.asList( 220 new String[] { 221 CmsPropertyDefinition.PROPERTY_TITLE, 222 CmsPropertyDefinition.PROPERTY_DESCRIPTION, 223 CmsPropertyDefinition.PROPERTY_DESCRIPTION_HTML, 224 CmsPropertyDefinition.PROPERTY_NAVTEXT, 225 CmsPropertyDefinition.PROPERTY_NAVINFO}); 226 227 /** The path of the JSP used to download aliases. */ 228 public static final String ALIAS_DOWNLOAD_PATH = "/system/workplace/commons/download-aliases.jsp"; 229 230 /** The path to the JSP used to upload aliases. */ 231 public static final String ALIAS_IMPORT_PATH = "/system/workplace/commons/import-aliases.jsp"; 232 233 /** The show model edit confirm dialog attribute name. */ 234 public static final String ATTR_SHOW_MODEL_EDIT_CONFIRM = "showModelEditConfirm"; 235 236 /** The galleries folder name. */ 237 public static final String GALLERIES_FOLDER_NAME = ".galleries"; 238 239 /** The configuration key for the functionDetail attribute in the container.info property. */ 240 public static final String KEY_FUNCTION_DETAIL = "functionDetail"; 241 242 /** The additional user info key for deleted list. */ 243 private static final String ADDINFO_ADE_DELETED_LIST = "ADE_DELETED_LIST"; 244 245 /** The additional user info key for modified list. */ 246 private static final String ADDINFO_ADE_MODIFIED_LIST = "ADE_MODIFIED_LIST"; 247 248 /** The lock table to prevent multiple users from editing the alias table concurrently. */ 249 private static CmsAliasEditorLockTable aliasEditorLockTable = new CmsAliasEditorLockTable(); 250 251 /** The table containing the alias import results. */ 252 private static CmsAliasImportResponseTable aliasImportResponseTable = new CmsAliasImportResponseTable(); 253 254 /** The static log object for this class. */ 255 private static final Log LOG = CmsLog.getLog(CmsVfsSitemapService.class); 256 257 /** The redirect recource type name. */ 258 private static final String RECOURCE_TYPE_NAME_REDIRECT = "htmlredirect"; 259 260 /** The redirect target XPath. */ 261 private static final String REDIRECT_LINK_TARGET_XPATH = "Link"; 262 263 /** Serialization uid. */ 264 private static final long serialVersionUID = -7236544324371767330L; 265 266 /** The VFS path of the redirect copy page for navigation level entries. */ 267 private static final String SUB_LEVEL_REDIRECT_COPY_PAGE = "/system/modules/org.opencms.base/copyresources/sub-level-redirect.html"; 268 269 /** The navigation builder. */ 270 private CmsJspNavBuilder m_navBuilder; 271 272 /** 273 * Adds an alias import result.<p> 274 * 275 * @param results the list of alias import results to add 276 * 277 * @return the key to retrieve the alias import results 278 */ 279 public static String addAliasImportResult(List<CmsAliasImportResult> results) { 280 281 return aliasImportResponseTable.addImportResult(results); 282 } 283 284 /** 285 * Creates a client property bean from a server-side property.<p> 286 * 287 * @param prop the property from which to create the client property 288 * @param preserveOrigin if true, the origin will be copied into the new object 289 * 290 * @return the new client property 291 */ 292 public static CmsClientProperty createClientProperty(CmsProperty prop, boolean preserveOrigin) { 293 294 CmsClientProperty result = new CmsClientProperty( 295 prop.getName(), 296 prop.getStructureValue(), 297 prop.getResourceValue()); 298 if (preserveOrigin) { 299 result.setOrigin(prop.getOrigin()); 300 } 301 return result; 302 } 303 304 /** 305 * Fetches the sitemap data.<p> 306 * 307 * @param request the current request 308 * @param sitemapUri the site relative path 309 * 310 * @return the sitemap data 311 * 312 * @throws CmsRpcException if something goes wrong 313 */ 314 public static CmsSitemapData prefetch(HttpServletRequest request, String sitemapUri) throws CmsRpcException { 315 316 CmsVfsSitemapService service = new CmsVfsSitemapService(); 317 service.setCms(CmsFlexController.getCmsObject(request)); 318 service.setRequest(request); 319 CmsSitemapData result = null; 320 try { 321 result = service.prefetch(sitemapUri); 322 } finally { 323 service.clearThreadStorage(); 324 } 325 return result; 326 } 327 328 /** 329 * Converts a sequence of properties to a map of client-side property beans.<p> 330 * 331 * @param props the sequence of properties 332 * @param preserveOrigin if true, the origin of the properties should be copied to the client properties 333 * 334 * @return the map of client properties 335 * 336 */ 337 static Map<String, CmsClientProperty> createClientProperties(Iterable<CmsProperty> props, boolean preserveOrigin) { 338 339 Map<String, CmsClientProperty> result = new HashMap<String, CmsClientProperty>(); 340 for (CmsProperty prop : props) { 341 CmsClientProperty clientProp = createClientProperty(prop, preserveOrigin); 342 result.put(prop.getName(), clientProp); 343 } 344 return result; 345 } 346 347 /** 348 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#changeCategory(java.lang.String, org.opencms.util.CmsUUID, java.lang.String, java.lang.String) 349 */ 350 public void changeCategory(String entryPoint, CmsUUID id, String title, String name) throws CmsRpcException { 351 352 try { 353 name = OpenCms.getResourceManager().getFileTranslator().translateResource(name.trim().replace('/', '-')); 354 CmsObject cms = getCmsObject(); 355 CmsResource categoryResource = cms.readResource(id); 356 ensureLock(categoryResource); 357 String sitePath = cms.getSitePath(categoryResource); 358 String newPath = CmsStringUtil.joinPaths(CmsResource.getParentFolder(sitePath), name); 359 cms.writePropertyObject(sitePath, new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, title, null)); 360 if (!CmsStringUtil.joinPaths("/", newPath, "/").equals(CmsStringUtil.joinPaths("/", sitePath, "/"))) { 361 cms.moveResource(sitePath, newPath); 362 } 363 } catch (Exception e) { 364 error(e); 365 } 366 } 367 368 /** 369 * @see org.opencms.gwt.CmsGwtService#checkPermissions(org.opencms.file.CmsObject) 370 */ 371 @Override 372 public void checkPermissions(CmsObject cms) throws CmsRoleViolationException { 373 374 OpenCms.getRoleManager().checkRole(cms, CmsRole.EDITOR); 375 } 376 377 /** 378 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#createCategory(java.lang.String, org.opencms.util.CmsUUID, java.lang.String, java.lang.String) 379 */ 380 public void createCategory(String entryPoint, CmsUUID id, String title, String name) throws CmsRpcException { 381 382 try { 383 name = OpenCms.getResourceManager().getFileTranslator().translateResource(name.trim().replace('/', '-')); 384 CmsObject cms = getCmsObject(); 385 CmsCategoryService catService = CmsCategoryService.getInstance(); 386 387 CmsCategory createdCategory = null; 388 if (id.isNullUUID()) { 389 String localRepositoryPath = CmsStringUtil.joinPaths( 390 entryPoint, 391 CmsCategoryService.getInstance().getRepositoryBaseFolderName(getCmsObject())); 392 393 // ensure category repository exists 394 if (!cms.existsResource(localRepositoryPath)) { 395 tryUnlock( 396 cms.createResource( 397 localRepositoryPath, 398 OpenCms.getResourceManager().getResourceType(CmsResourceTypeFolder.getStaticTypeName()))); 399 } 400 createdCategory = catService.createCategory(cms, null, name, title, "", localRepositoryPath); 401 } else { 402 CmsResource parentResource = cms.readResource(id); 403 CmsCategory parent = catService.getCategory(cms, parentResource); 404 createdCategory = catService.createCategory( 405 cms, 406 parent, 407 name, 408 title, 409 "", 410 cms.getRequestContext().removeSiteRoot(parentResource.getRootPath())); 411 } 412 tryUnlock(cms.readResource(createdCategory.getId())); 413 } catch (Exception e) { 414 error(e); 415 } 416 } 417 418 /** 419 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#createNewGalleryFolder(java.lang.String, java.lang.String, int) 420 */ 421 public CmsGalleryFolderEntry createNewGalleryFolder(String parentFolder, String title, int folderTypeId) 422 throws CmsRpcException { 423 424 CmsObject cms = getCmsObject(); 425 CmsGalleryFolderEntry folderEntry = null; 426 try { 427 if (!cms.existsResource(parentFolder, CmsResourceFilter.IGNORE_EXPIRATION)) { 428 CmsResource parent = cms.createResource( 429 parentFolder, 430 OpenCms.getResourceManager().getResourceType(CmsResourceTypeFolder.getStaticTypeName())); 431 tryUnlock(parent); 432 } 433 String folderName = OpenCms.getResourceManager().getFileTranslator().translateResource(title); 434 435 folderName = OpenCms.getResourceManager().getNameGenerator().getUniqueFileName( 436 cms, 437 parentFolder, 438 folderName); 439 String folderPath = CmsStringUtil.joinPaths(parentFolder, folderName); 440 441 @SuppressWarnings("deprecation") 442 CmsResource galleryFolder = cms.createResource( 443 folderPath, 444 folderTypeId, 445 null, 446 Collections.singletonList(new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, title, null))); 447 folderEntry = readGalleryFolderEntry( 448 galleryFolder, 449 OpenCms.getResourceManager().getResourceType(galleryFolder).getTypeName()); 450 tryUnlock(galleryFolder); 451 } catch (CmsException e) { 452 error(e); 453 } 454 return folderEntry; 455 } 456 457 /** 458 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#createNewModelPage(java.lang.String, java.lang.String, java.lang.String, org.opencms.util.CmsUUID, boolean) 459 */ 460 public CmsModelPageEntry createNewModelPage( 461 String entryPointUri, 462 String title, 463 String description, 464 CmsUUID copyId, 465 boolean isModelGroup) 466 throws CmsRpcException { 467 468 try { 469 CmsObject cms = getCmsObject(); 470 CmsResource rootResource = cms.readResource(entryPointUri); 471 CmsModelPageHelper helper = new CmsModelPageHelper(getCmsObject(), rootResource); 472 CmsResource page; 473 if (isModelGroup) { 474 page = helper.createModelGroupPage(title, description, copyId); 475 } else { 476 page = helper.createPageInModelFolder(title, description, copyId); 477 String configPath = CmsStringUtil.joinPaths(entryPointUri, ".content/.config"); 478 CmsResource configResource = cms.readResource(configPath); 479 helper.addModelPageToSitemapConfiguration(configResource, page, false); 480 } 481 CmsModelPageEntry result = helper.createModelPageEntry(page, false, false, getWorkplaceLocale()); 482 OpenCms.getADEManager().waitForCacheUpdate(false); 483 return result; 484 } catch (Throwable e) { 485 error(e); 486 return null; 487 } 488 } 489 490 /** 491 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#createSubSitemap(org.opencms.util.CmsUUID) 492 */ 493 public CmsSitemapChange createSubSitemap(CmsUUID entryId) throws CmsRpcException { 494 495 CmsObject cms = getCmsObject(); 496 try { 497 ensureSession(); 498 CmsResource subSitemapFolder = cms.readResource(entryId); 499 ensureLock(subSitemapFolder); 500 String sitePath = cms.getSitePath(subSitemapFolder); 501 createSitemapContentFolder(cms, subSitemapFolder); 502 subSitemapFolder.setType(getSubsitemapType()); 503 cms.writeResource(subSitemapFolder); 504 tryUnlock(subSitemapFolder); 505 CmsSitemapClipboardData clipboard = getClipboardData(); 506 CmsClientSitemapEntry entry = toClientEntry( 507 getNavBuilder().getNavigationForResource(sitePath, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED), 508 false); 509 clipboard.addModified(entry); 510 setClipboardData(clipboard); 511 CmsSitemapChange result = new CmsSitemapChange(entry.getId(), entry.getSitePath(), ChangeType.modify); 512 result.setUpdatedEntry(entry); 513 return result; 514 } catch (Exception e) { 515 error(e); 516 } 517 return null; 518 519 } 520 521 /** 522 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#disableModelPage(java.lang.String, org.opencms.util.CmsUUID, boolean) 523 */ 524 public void disableModelPage(String baseUri, CmsUUID modelPageId, boolean disabled) throws CmsRpcException { 525 526 try { 527 CmsObject cms = getCmsObject(); 528 CmsResource rootResource = cms.readResource(baseUri); 529 CmsModelPageHelper helper = new CmsModelPageHelper(getCmsObject(), rootResource); 530 String configPath = CmsStringUtil.joinPaths(baseUri, ".content/.config"); 531 CmsResource configResource = cms.readResource(configPath); 532 helper.disableModelPage(configResource, modelPageId, disabled); 533 OpenCms.getADEManager().waitForCacheUpdate(false); 534 } catch (Throwable e) { 535 error(e); 536 537 } 538 } 539 540 /** 541 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#getAliasImportResult(java.lang.String) 542 */ 543 public List<CmsAliasImportResult> getAliasImportResult(String resultKey) { 544 545 return aliasImportResponseTable.getAndRemove(resultKey); 546 } 547 548 /** 549 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#getAliasTable() 550 */ 551 public CmsAliasInitialFetchResult getAliasTable() throws CmsRpcException { 552 553 try { 554 CmsObject cms = getCmsObject(); 555 CmsAliasManager aliasManager = OpenCms.getAliasManager(); 556 List<CmsAlias> aliases = aliasManager.getAliasesForSite(cms, cms.getRequestContext().getSiteRoot()); 557 List<CmsAliasTableRow> rows = new ArrayList<CmsAliasTableRow>(); 558 CmsAliasInitialFetchResult result = new CmsAliasInitialFetchResult(); 559 for (CmsAlias alias : aliases) { 560 CmsAliasTableRow row = createAliasTableEntry(cms, alias); 561 rows.add(row); 562 } 563 result.setRows(rows); 564 565 List<CmsRewriteAlias> rewriteAliases = aliasManager.getRewriteAliases( 566 cms, 567 cms.getRequestContext().getSiteRoot()); 568 569 List<CmsRewriteAliasTableRow> rewriteRows = new ArrayList<CmsRewriteAliasTableRow>(); 570 for (CmsRewriteAlias rewriteAlias : rewriteAliases) { 571 CmsRewriteAliasTableRow rewriteRow = new CmsRewriteAliasTableRow( 572 rewriteAlias.getId(), 573 rewriteAlias.getPatternString(), 574 rewriteAlias.getReplacementString(), 575 rewriteAlias.getMode()); 576 rewriteRows.add(rewriteRow); 577 } 578 result.setRewriteRows(rewriteRows); 579 CmsUser otherLockOwner = aliasEditorLockTable.update(cms, cms.getRequestContext().getSiteRoot()); 580 if (otherLockOwner != null) { 581 result.setAliasLockOwner(otherLockOwner.getName()); 582 } 583 result.setDownloadUrl(OpenCms.getLinkManager().substituteLinkForRootPath(cms, ALIAS_DOWNLOAD_PATH)); 584 return result; 585 } catch (Throwable e) { 586 error(e); 587 return null; 588 } 589 } 590 591 /** 592 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#getCategoryData(java.lang.String) 593 */ 594 public CmsSitemapCategoryData getCategoryData(String entryPoint) throws CmsRpcException { 595 596 CmsObject cms = getCmsObject(); 597 try { 598 CmsResource entryPointResource = cms.readResource(entryPoint); 599 String basePath = CmsStringUtil.joinPaths( 600 entryPointResource.getRootPath(), 601 CmsCategoryService.getInstance().getRepositoryBaseFolderName(getCmsObject())); 602 603 List<CmsCategoryTreeEntry> entries = CmsCoreService.getCategoriesForSitePathStatic( 604 cms, 605 entryPoint, 606 cms.getRequestContext().removeSiteRoot(basePath)); 607 CmsSitemapCategoryData categoryData = new CmsSitemapCategoryData(); 608 for (CmsCategoryTreeEntry entry : entries) { 609 categoryData.add(entry); 610 } 611 612 categoryData.setBasePath(basePath); 613 return categoryData; 614 } catch (Exception e) { 615 error(e); 616 return null; 617 } 618 } 619 620 /** 621 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#getChildren(java.lang.String, org.opencms.util.CmsUUID, int) 622 */ 623 public CmsClientSitemapEntry getChildren(String entryPointUri, CmsUUID entryId, int levels) throws CmsRpcException { 624 625 CmsClientSitemapEntry entry = null; 626 627 try { 628 CmsObject cms = getCmsObject(); 629 630 //ensure that root ends with a '/' if it's a folder 631 CmsResource rootRes = cms.readResource(entryId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 632 String root = cms.getSitePath(rootRes); 633 CmsJspNavElement navElement = getNavBuilder().getNavigationForResource( 634 root, 635 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 636 boolean isRoot = root.equals(entryPointUri); 637 entry = toClientEntry(navElement, isRoot); 638 if ((levels > 0) && (isRoot || (rootRes.isFolder()))) { 639 entry.setSubEntries(getChildren(root, levels, null), null); 640 } 641 } catch (Throwable e) { 642 error(e); 643 } 644 return entry; 645 } 646 647 /** 648 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#getGalleryData(java.lang.String) 649 */ 650 public Map<CmsGalleryType, List<CmsGalleryFolderEntry>> getGalleryData(String entryPointUri) { 651 652 List<String> subSitePaths = OpenCms.getADEManager().getSubSitePaths( 653 getCmsObject(), 654 getCmsObject().getRequestContext().addSiteRoot(entryPointUri)); 655 List<CmsGalleryType> galleryTypes = collectGalleryTypes(); 656 Map<CmsGalleryType, List<CmsGalleryFolderEntry>> result = new HashMap<CmsGalleryType, List<CmsGalleryFolderEntry>>(); 657 for (CmsGalleryType type : galleryTypes) { 658 List<CmsGalleryFolderEntry> galleries = null; 659 try { 660 galleries = getGalleriesForType(entryPointUri, type, subSitePaths); 661 } catch (CmsException e) { 662 log(e.getLocalizedMessage(), e); 663 } 664 result.put(type, galleries); 665 } 666 return result; 667 } 668 669 /** 670 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#getModelInfos(org.opencms.util.CmsUUID) 671 */ 672 public CmsModelInfo getModelInfos(CmsUUID rootId) throws CmsRpcException { 673 674 try { 675 CmsObject cms = getCmsObject(); 676 CmsResource rootResource = cms.readResource(rootId); 677 CmsModelPageHelper modelPageHelper = new CmsModelPageHelper(getCmsObject(), rootResource); 678 return modelPageHelper.getModelInfo(); 679 } catch (Throwable e) { 680 error(e); 681 return null; // will never be reached 682 } 683 684 } 685 686 /** 687 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#getNewElementInfo(java.lang.String) 688 */ 689 public List<CmsNewResourceInfo> getNewElementInfo(String entryPointUri) throws CmsRpcException { 690 691 try { 692 CmsObject cms = getCmsObject(); 693 String rootPath = cms.getRequestContext().addSiteRoot(entryPointUri); 694 CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(cms, rootPath); 695 List<CmsNewResourceInfo> result = getNewResourceInfos(cms, config, getWorkplaceLocale()); 696 return result; 697 } catch (Throwable e) { 698 error(e); 699 return null; 700 } 701 } 702 703 /** 704 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#getResourceLink(org.opencms.util.CmsUUID, java.lang.String) 705 */ 706 public String getResourceLink(CmsUUID baseId, String sitePath) throws CmsRpcException { 707 708 try { 709 CmsObject cms = OpenCms.initCmsObject(getCmsObject()); 710 CmsResource baseResource = cms.readResource(baseId, CmsResourceFilter.IGNORE_EXPIRATION); 711 String contextPath = cms.getSitePath(baseResource); 712 cms.getRequestContext().setUri(contextPath); 713 String result = OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, sitePath); 714 return result; 715 } catch (Exception e) { 716 error(e); 717 } 718 return null; 719 } 720 721 /** 722 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#loadPropertyDataForLocaleCompareView(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID) 723 */ 724 public CmsLocaleComparePropertyData loadPropertyDataForLocaleCompareView(CmsUUID id, CmsUUID rootId) 725 throws CmsRpcException { 726 727 try { 728 CmsLocaleComparePropertyData result = new CmsLocaleComparePropertyData(); 729 CmsObject cms = getCmsObject(); 730 CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION; 731 CmsResource resource = cms.readResource(id, filter); 732 CmsResource defaultFile = cms.readDefaultFile(id.toString()); 733 result.setDefaultFileId(defaultFile != null ? defaultFile.getStructureId() : null); 734 result.setId(id); 735 result.setFolder(resource.isFolder()); 736 List<CmsProperty> props = cms.readPropertyObjects(resource, false); 737 List<CmsProperty> defaultFileProps = cms.readPropertyObjects(defaultFile, false); 738 Map<String, CmsClientProperty> clientProps = createClientProperties(props, true); 739 Map<String, CmsClientProperty> clientDefaultFileProps = createClientProperties(defaultFileProps, true); 740 741 result.setOwnProperties(clientProps); 742 result.setDefaultFileProperties(clientDefaultFileProps); 743 744 CmsResource parent = cms.readParentFolder(resource.getStructureId()); 745 List<CmsResource> resourcesInSameFolder = cms.readResources(parent, CmsResourceFilter.ALL, false); 746 List<String> forbiddenUrlNames = Lists.newArrayList(); 747 for (CmsResource resourceInSameFolder : resourcesInSameFolder) { 748 String otherName = CmsResource.getName(resourceInSameFolder.getRootPath()); 749 forbiddenUrlNames.add(otherName); 750 } 751 result.setForbiddenUrlNames(forbiddenUrlNames); 752 result.setInheritedProperties(createClientProperties(cms.readPropertyObjects(parent, true), true)); 753 result.setPath(resource.getRootPath()); 754 String name = CmsFileUtil.removeTrailingSeparator(CmsResource.getName(resource.getRootPath())); 755 result.setName(name); 756 result.setHasEditableName(!CmsStringUtil.isEmptyOrWhitespaceOnly(name)); 757 return result; 758 } catch (Exception e) { 759 error(e); 760 return null; 761 } 762 } 763 764 /** 765 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#mergeSubSitemap(java.lang.String, org.opencms.util.CmsUUID) 766 */ 767 @SuppressWarnings("deprecation") 768 public CmsSitemapChange mergeSubSitemap(String entryPoint, CmsUUID subSitemapId) throws CmsRpcException { 769 770 CmsObject cms = getCmsObject(); 771 try { 772 ensureSession(); 773 CmsResource subSitemapFolder = cms.readResource(subSitemapId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 774 ensureLock(subSitemapFolder); 775 subSitemapFolder.setType( 776 OpenCms.getResourceManager().getResourceType(CmsResourceTypeFolder.RESOURCE_TYPE_NAME).getTypeId()); 777 cms.writeResource(subSitemapFolder); 778 String sitePath = cms.getSitePath(subSitemapFolder); 779 String sitemapConfigName = CmsStringUtil.joinPaths( 780 sitePath, 781 CmsADEManager.CONTENT_FOLDER_NAME, 782 CmsADEManager.CONFIG_FILE_NAME); 783 if (cms.existsResource(sitemapConfigName)) { 784 cms.deleteResource(sitemapConfigName, CmsResource.DELETE_PRESERVE_SIBLINGS); 785 } 786 tryUnlock(subSitemapFolder); 787 CmsSitemapClipboardData clipboard = getClipboardData(); 788 CmsClientSitemapEntry entry = toClientEntry( 789 getNavBuilder().getNavigationForResource( 790 cms.getSitePath(subSitemapFolder), 791 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED), 792 false); 793 clipboard.addModified(entry); 794 setClipboardData(clipboard); 795 entry = getChildren(entryPoint, subSitemapId, 1); 796 CmsSitemapChange result = new CmsSitemapChange(entry.getId(), entry.getSitePath(), ChangeType.modify); 797 result.setUpdatedEntry(entry); 798 return result; 799 } catch (Exception e) { 800 error(e); 801 } 802 return null; 803 } 804 805 /** 806 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#prefetch(java.lang.String) 807 */ 808 public CmsSitemapData prefetch(String sitemapUri) throws CmsRpcException { 809 810 CmsSitemapData result = null; 811 CmsObject cms = getCmsObject(); 812 813 try { 814 OpenCms.getRoleManager().checkRole(cms, CmsRole.EDITOR); 815 String openPath = getRequest().getParameter(CmsCoreData.PARAM_PATH); 816 if (!isValidOpenPath(cms, openPath)) { 817 // if no path is supplied, start from root 818 openPath = "/"; 819 } 820 CmsQuickLaunchLocationCache.getLocationCache(getRequest().getSession()).setSitemapEditorLocation( 821 cms.getRequestContext().getSiteRoot(), 822 openPath); 823 CmsADEConfigData configData = OpenCms.getADEManager().lookupConfiguration( 824 cms, 825 cms.getRequestContext().addSiteRoot(openPath)); 826 Map<String, CmsXmlContentProperty> propertyConfig = new LinkedHashMap<String, CmsXmlContentProperty>( 827 configData.getPropertyConfigurationAsMap()); 828 829 Map<String, CmsClientProperty> parentProperties = generateParentProperties(configData.getBasePath()); 830 String siteRoot = cms.getRequestContext().getSiteRoot(); 831 String exportRfsPrefix = OpenCms.getStaticExportManager().getDefaultRfsPrefix(); 832 CmsSite site = OpenCms.getSiteManager().getSiteForSiteRoot(siteRoot); 833 boolean isSecure = (site != null) && site.hasSecureServer(); 834 String parentSitemap = null; 835 836 if (configData.getBasePath() != null) { 837 CmsADEConfigData parentConfigData = OpenCms.getADEManager().lookupConfiguration( 838 cms, 839 CmsResource.getParentFolder(configData.getBasePath())); 840 parentSitemap = parentConfigData.getBasePath(); 841 if (parentSitemap != null) { 842 parentSitemap = cms.getRequestContext().removeSiteRoot(parentSitemap); 843 } 844 } 845 String noEdit = ""; 846 CmsNewResourceInfo defaultNewInfo = null; 847 List<CmsNewResourceInfo> newResourceInfos = null; 848 CmsDetailPageTable detailPages = null; 849 List<CmsNewResourceInfo> resourceTypeInfos = null; 850 boolean canEditDetailPages = false; 851 boolean isOnlineProject = CmsProject.isOnlineProject(cms.getRequestContext().getCurrentProject().getUuid()); 852 String defaultGalleryFolder = GALLERIES_FOLDER_NAME; 853 try { 854 CmsObject rootCms = OpenCms.initCmsObject(cms); 855 rootCms.getRequestContext().setSiteRoot(""); 856 CmsResource baseDir = rootCms.readResource( 857 configData.getBasePath(), 858 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 859 CmsProperty galleryFolderProp = cms.readPropertyObject( 860 baseDir, 861 CmsPropertyDefinition.PROPERTY_GALLERIES_FOLDER, 862 true); 863 if (!galleryFolderProp.isNullProperty() 864 && CmsStringUtil.isNotEmptyOrWhitespaceOnly(galleryFolderProp.getValue())) { 865 defaultGalleryFolder = galleryFolderProp.getValue(); 866 } 867 CmsPropertyEditorHelper.updateWysiwygConfig(propertyConfig, cms, baseDir); 868 } catch (CmsException e) { 869 LOG.warn(e.getLocalizedMessage(), e); 870 } 871 872 detailPages = new CmsDetailPageTable(configData.getAllDetailPages()); 873 if (!isOnlineProject) { 874 newResourceInfos = getNewResourceInfos(cms, configData, getWorkplaceLocale()); 875 CmsResource modelResource = null; 876 if (configData.getDefaultModelPage() != null) { 877 if (cms.existsResource(configData.getDefaultModelPage().getResource().getStructureId())) { 878 modelResource = configData.getDefaultModelPage().getResource(); 879 } else { 880 try { 881 modelResource = cms.readResource( 882 cms.getSitePath(configData.getDefaultModelPage().getResource()), 883 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 884 } catch (CmsException e) { 885 LOG.warn(e.getLocalizedMessage(), e); 886 } 887 } 888 } 889 if ((modelResource == null) && !newResourceInfos.isEmpty()) { 890 try { 891 modelResource = cms.readResource(newResourceInfos.get(0).getCopyResourceId()); 892 } catch (CmsException e) { 893 LOG.warn(e.getLocalizedMessage(), e); 894 } 895 } 896 if (modelResource != null) { 897 resourceTypeInfos = getResourceTypeInfos( 898 getCmsObject(), 899 configData.getResourceTypes(), 900 configData.getFunctionReferences(), 901 modelResource, 902 getWorkplaceLocale()); 903 try { 904 defaultNewInfo = createNewResourceInfo(cms, modelResource, getWorkplaceLocale()); 905 } catch (CmsException e) { 906 LOG.warn(e.getLocalizedMessage(), e); 907 } 908 } 909 canEditDetailPages = !(configData.isModuleConfiguration()); 910 } 911 if (isOnlineProject) { 912 noEdit = Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_SITEMAP_NO_EDIT_ONLINE_0); 913 } 914 List<String> allPropNames = getPropertyNames(cms); 915 String returnCode = getRequest().getParameter(CmsCoreData.PARAM_RETURNCODE); 916 if (!isValidReturnCode(returnCode)) { 917 returnCode = null; 918 } 919 cms.getRequestContext().getSiteRoot(); 920 String aliasImportUrl = OpenCms.getLinkManager().substituteLinkForRootPath(cms, ALIAS_IMPORT_PATH); 921 boolean canEditAliases = OpenCms.getAliasManager().hasPermissionsForMassEdit(cms, siteRoot); 922 List<CmsListInfoBean> subsitemapFolderTypeInfos = collectSitemapTypeInfos(cms, configData); 923 924 // evaluate the editor mode 925 EditorMode editorMode = CmsADESessionCache.getCache(getRequest(), getCmsObject()).getSitemapEditorMode(); 926 if ((editorMode == null) || (editorMode == EditorMode.compareLocales)) { 927 editorMode = EditorMode.navigation; 928 } 929 930 String basePath = configData.getBasePath(); 931 932 if (!cms.existsResource( 933 cms.getRequestContext().removeSiteRoot(basePath), 934 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) { 935 basePath = cms.getRequestContext().getSiteRoot(); 936 } 937 Boolean showModelEditConfirm = (Boolean)getRequest().getSession().getAttribute( 938 ATTR_SHOW_MODEL_EDIT_CONFIRM); 939 if (showModelEditConfirm == null) { 940 showModelEditConfirm = Boolean.TRUE; 941 } 942 boolean showLocaleComparison = !(getCmsObject().getRequestContext().getCurrentProject().isOnlineProject()) 943 && (site != null) 944 && (site.getMainTranslationLocale(null) != null); 945 946 result = new CmsSitemapData( 947 (new CmsTemplateFinder(cms)).getTemplates(), 948 propertyConfig, 949 getClipboardData(), 950 CmsCoreService.getContextMenuEntries( 951 cms, 952 configData.getResource().getStructureId(), 953 AdeContext.sitemapeditor), 954 parentProperties, 955 allPropNames, 956 exportRfsPrefix, 957 isSecure, 958 noEdit, 959 isDisplayToolbar(getRequest()), 960 defaultNewInfo, 961 newResourceInfos, 962 createResourceTypeInfo(OpenCms.getResourceManager().getResourceType(RECOURCE_TYPE_NAME_REDIRECT), null), 963 createNavigationLevelTypeInfo(), 964 getSitemapInfo(basePath), 965 parentSitemap, 966 getRootEntry(basePath, CmsResource.getFolderPath(openPath)), 967 openPath, 968 30, 969 detailPages, 970 resourceTypeInfos, 971 returnCode, 972 canEditDetailPages, 973 aliasImportUrl, 974 canEditAliases, 975 OpenCms.getWorkplaceManager().getDefaultUserSettings().getSubsitemapCreationMode() == CmsDefaultUserSettings.SubsitemapCreationMode.createfolder, 976 OpenCms.getRoleManager().hasRole(cms, CmsRole.GALLERY_EDITOR), 977 OpenCms.getRoleManager().hasRole(cms, CmsRole.CATEGORY_EDITOR), 978 subsitemapFolderTypeInfos, 979 editorMode, 980 defaultGalleryFolder, 981 showModelEditConfirm.booleanValue()); 982 983 CmsUUID rootId = cms.readResource("/", CmsResourceFilter.ALL).getStructureId(); 984 result.setSiteRootId(rootId); 985 result.setLocaleComparisonEnabled(showLocaleComparison); 986 } catch (Throwable e) { 987 error(e); 988 } 989 return result; 990 } 991 992 /** 993 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#prepareReloadSitemap(org.opencms.util.CmsUUID, org.opencms.ade.sitemap.shared.CmsSitemapData.EditorMode) 994 */ 995 public String prepareReloadSitemap(CmsUUID rootId, EditorMode mode) throws CmsRpcException { 996 997 try { 998 CmsObject cms = getCmsObject(); 999 CmsResource res = cms.readResource(CmsADEManager.PATH_SITEMAP_EDITOR_JSP); 1000 1001 CmsResource target = cms.readResource(rootId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 1002 String targetRootPath = OpenCms.getADEManager().getSubSiteRoot(cms, target.getRootPath()); 1003 CmsSite targetSite = OpenCms.getSiteManager().getSiteForRootPath(targetRootPath); 1004 CmsADESessionCache.getCache(getRequest(), getCmsObject()).setSitemapEditorMode(mode); 1005 if (targetSite != null) { 1006 cms.getRequestContext().setSiteRoot(targetSite.getSiteRoot()); 1007 String path = cms.getRequestContext().removeSiteRoot(targetRootPath); 1008 String link = OpenCms.getLinkManager().substituteLink(cms, res); 1009 link = link + "?path=" + path; 1010 return link; 1011 } 1012 return null; 1013 } catch (Exception e) { 1014 error(e); 1015 return null; 1016 } 1017 } 1018 1019 /** 1020 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#removeModelPage(java.lang.String, org.opencms.util.CmsUUID) 1021 */ 1022 public void removeModelPage(String entryPointUri, CmsUUID id) throws CmsRpcException { 1023 1024 try { 1025 CmsObject cms = getCmsObject(); 1026 CmsResource rootResource = cms.readResource(entryPointUri); 1027 CmsModelPageHelper helper = new CmsModelPageHelper(getCmsObject(), rootResource); 1028 String configPath = CmsStringUtil.joinPaths(entryPointUri, ".content/.config"); 1029 CmsResource configResource = cms.readResource(configPath); 1030 helper.removeModelPage(configResource, id); 1031 OpenCms.getADEManager().waitForCacheUpdate(false); 1032 } catch (Throwable e) { 1033 error(e); 1034 1035 } 1036 1037 } 1038 1039 /** 1040 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#save(java.lang.String, org.opencms.ade.sitemap.shared.CmsSitemapChange) 1041 */ 1042 public CmsSitemapChange save(String entryPoint, CmsSitemapChange change) throws CmsRpcException { 1043 1044 CmsSitemapChange result = null; 1045 try { 1046 result = saveInternal(entryPoint, change); 1047 } catch (Exception e) { 1048 error(e); 1049 } 1050 return result; 1051 } 1052 1053 /** 1054 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#saveAliases(org.opencms.gwt.shared.alias.CmsAliasSaveValidationRequest) 1055 */ 1056 public CmsAliasEditValidationReply saveAliases(CmsAliasSaveValidationRequest saveRequest) throws CmsRpcException { 1057 1058 CmsObject cms = getCmsObject(); 1059 CmsAliasBulkEditHelper helper = new CmsAliasBulkEditHelper(cms); 1060 try { 1061 return helper.saveAliases(saveRequest); 1062 } catch (Exception e) { 1063 error(e); 1064 return null; 1065 } 1066 } 1067 1068 /** 1069 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#savePropertiesForLocaleCompareMode(org.opencms.util.CmsUUID, java.lang.String, java.util.List, boolean) 1070 */ 1071 public void savePropertiesForLocaleCompareMode( 1072 CmsUUID id, 1073 String newUrlName, 1074 List<CmsPropertyModification> propertyChanges, 1075 boolean editedName) 1076 throws CmsRpcException { 1077 1078 try { 1079 CmsObject cms = getCmsObject(); 1080 CmsResource ownRes = cms.readResource(id, CmsResourceFilter.IGNORE_EXPIRATION); 1081 CmsResource defaultFileRes = cms.readDefaultFile("" + id); 1082 try (AutoCloseable c = CmsLockUtil.withLockedResources(cms, ownRes)) { 1083 updateProperties(cms, ownRes, defaultFileRes, propertyChanges); 1084 if (editedName) { 1085 String parent = CmsResource.getParentFolder(ownRes.getRootPath()); 1086 newUrlName = CmsFileUtil.removeTrailingSeparator(newUrlName); 1087 String newPath = CmsStringUtil.joinPaths(parent, newUrlName); 1088 CmsObject rootCms = OpenCms.initCmsObject(cms); 1089 rootCms.getRequestContext().setSiteRoot(""); 1090 rootCms.moveResource(ownRes.getRootPath(), newPath); 1091 } 1092 } 1093 } catch (Exception e) { 1094 error(e); 1095 } 1096 } 1097 1098 /** 1099 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#setDefaultModel(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID) 1100 */ 1101 public CmsModelInfo setDefaultModel(CmsUUID rootId, CmsUUID modelId) throws CmsRpcException { 1102 1103 CmsModelInfo result = null; 1104 try { 1105 CmsObject cms = getCmsObject(); 1106 CmsResource rootResource = cms.readResource(rootId); 1107 CmsModelPageHelper modelPageHelper = new CmsModelPageHelper(getCmsObject(), rootResource); 1108 CmsResource configFile = OpenCms.getADEManager().lookupConfiguration( 1109 cms, 1110 rootResource.getRootPath()).getResource(); 1111 ensureLock(configFile); 1112 result = modelPageHelper.setDefaultModelPage(configFile, modelId); 1113 tryUnlock(configFile); 1114 } catch (Throwable e) { 1115 error(e); 1116 } 1117 return result; 1118 } 1119 1120 /** 1121 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#setEditorMode(org.opencms.ade.sitemap.shared.CmsSitemapData.EditorMode) 1122 */ 1123 public void setEditorMode(EditorMode editorMode) { 1124 1125 CmsADESessionCache.getCache(getRequest(), getCmsObject()).setSitemapEditorMode(editorMode); 1126 } 1127 1128 /** 1129 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#updateAliasEditorStatus(boolean) 1130 */ 1131 public void updateAliasEditorStatus(boolean editing) { 1132 1133 CmsObject cms = getCmsObject(); 1134 if (editing) { 1135 aliasEditorLockTable.update(cms, cms.getRequestContext().getSiteRoot()); 1136 } else { 1137 aliasEditorLockTable.clear(cms, cms.getRequestContext().getSiteRoot()); 1138 } 1139 } 1140 1141 /** 1142 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#validateAliases(org.opencms.gwt.shared.alias.CmsAliasEditValidationRequest) 1143 */ 1144 public CmsAliasEditValidationReply validateAliases(CmsAliasEditValidationRequest validationRequest) { 1145 1146 CmsObject cms = getCmsObject(); 1147 CmsAliasBulkEditHelper helper = new CmsAliasBulkEditHelper(cms); 1148 return helper.validateAliases(validationRequest); 1149 } 1150 1151 /** 1152 * @see org.opencms.ade.sitemap.shared.rpc.I_CmsSitemapService#validateRewriteAliases(org.opencms.gwt.shared.alias.CmsRewriteAliasValidationRequest) 1153 */ 1154 public CmsRewriteAliasValidationReply validateRewriteAliases(CmsRewriteAliasValidationRequest validationRequest) { 1155 1156 CmsRewriteAliasValidationReply result = new CmsRewriteAliasValidationReply(); 1157 for (CmsRewriteAliasTableRow editedRow : validationRequest.getEditedRewriteAliases()) { 1158 try { 1159 String patternString = editedRow.getPatternString(); 1160 Pattern.compile(patternString); 1161 } catch (PatternSyntaxException e) { 1162 result.addError(editedRow.getId(), "Syntax error in regular expression: " + e.getMessage()); 1163 } 1164 } 1165 return result; 1166 } 1167 1168 /** 1169 * Creates a "broken link" bean based on a resource.<p> 1170 * 1171 * @param resource the resource 1172 * 1173 * @return the "broken link" bean with the data from the resource 1174 * 1175 * @throws CmsException if something goes wrong 1176 */ 1177 protected CmsBrokenLinkBean createSitemapBrokenLinkBean(CmsResource resource) throws CmsException { 1178 1179 CmsObject cms = getCmsObject(); 1180 CmsProperty titleProp = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, true); 1181 String defaultTitle = ""; 1182 String title = titleProp.getValue(defaultTitle); 1183 String path = cms.getSitePath(resource); 1184 String subtitle = path; 1185 return new CmsBrokenLinkBean(resource.getStructureId(), title, subtitle); 1186 1187 } 1188 1189 /** 1190 * Locks the given resource with a temporary, if not already locked by the current user. 1191 * Will throw an exception if the resource could not be locked for the current user.<p> 1192 * 1193 * @param resource the resource to lock 1194 * 1195 * @return the assigned lock 1196 * 1197 * @throws CmsException if the resource could not be locked 1198 */ 1199 protected LockInfo ensureLockAndGetInfo(CmsResource resource) throws CmsException { 1200 1201 CmsObject cms = getCmsObject(); 1202 boolean justLocked = false; 1203 List<CmsResource> blockingResources = cms.getBlockingLockedResources(resource); 1204 if ((blockingResources != null) && !blockingResources.isEmpty()) { 1205 throw new CmsException( 1206 org.opencms.gwt.Messages.get().container( 1207 org.opencms.gwt.Messages.ERR_RESOURCE_HAS_BLOCKING_LOCKED_CHILDREN_1, 1208 cms.getSitePath(resource))); 1209 } 1210 CmsUser user = cms.getRequestContext().getCurrentUser(); 1211 CmsLock lock = cms.getLock(resource); 1212 if (!lock.isOwnedBy(user)) { 1213 cms.lockResourceTemporary(resource); 1214 lock = cms.getLock(resource); 1215 justLocked = true; 1216 } else if (!lock.isOwnedInProjectBy(user, cms.getRequestContext().getCurrentProject())) { 1217 cms.changeLock(resource); 1218 lock = cms.getLock(resource); 1219 justLocked = true; 1220 } 1221 return new LockInfo(lock, justLocked); 1222 } 1223 1224 /** 1225 * Internal method for saving a sitemap.<p> 1226 * 1227 * @param entryPoint the URI of the sitemap to save 1228 * @param change the change to save 1229 * 1230 * @return list of changed sitemap entries 1231 * 1232 * @throws CmsException if something goes wrong 1233 */ 1234 protected CmsSitemapChange saveInternal(String entryPoint, CmsSitemapChange change) throws CmsException { 1235 1236 ensureSession(); 1237 switch (change.getChangeType()) { 1238 case clipboardOnly: 1239 // do nothing 1240 break; 1241 case remove: 1242 change = removeEntryFromNavigation(change); 1243 break; 1244 case undelete: 1245 change = undelete(change); 1246 break; 1247 default: 1248 change = applyChange(entryPoint, change); 1249 } 1250 setClipboardData(change.getClipBoardData()); 1251 return change; 1252 } 1253 1254 /** 1255 * Removes unnecessary locales from a container page.<p> 1256 * 1257 * @param containerPage the container page which should be changed 1258 * @param localeRes the resource used to determine the locale 1259 * 1260 * @throws CmsException if something goes wrong 1261 */ 1262 void ensureSingleLocale(CmsXmlContainerPage containerPage, CmsResource localeRes) throws CmsException { 1263 1264 CmsObject cms = getCmsObject(); 1265 Locale mainLocale = CmsLocaleManager.getMainLocale(cms, localeRes); 1266 OpenCms.getLocaleManager(); 1267 Locale defaultLocale = CmsLocaleManager.getDefaultLocale(); 1268 if (containerPage.hasLocale(mainLocale)) { 1269 removeAllLocalesExcept(containerPage, mainLocale); 1270 // remove other locales 1271 } else if (containerPage.hasLocale(defaultLocale)) { 1272 containerPage.copyLocale(defaultLocale, mainLocale); 1273 removeAllLocalesExcept(containerPage, mainLocale); 1274 } else if (containerPage.getLocales().size() > 0) { 1275 containerPage.copyLocale(containerPage.getLocales().get(0), mainLocale); 1276 removeAllLocalesExcept(containerPage, mainLocale); 1277 } else { 1278 containerPage.addLocale(cms, mainLocale); 1279 } 1280 } 1281 1282 /** 1283 * Gets the properties of a resource as a map of client properties.<p> 1284 * 1285 * @param cms the CMS context to use 1286 * @param res the resource whose properties to read 1287 * @param search true if the inherited properties should be read 1288 * 1289 * @return the client properties as a map 1290 * 1291 * @throws CmsException if something goes wrong 1292 */ 1293 Map<String, CmsClientProperty> getClientProperties(CmsObject cms, CmsResource res, boolean search) 1294 throws CmsException { 1295 1296 List<CmsProperty> props = cms.readPropertyObjects(res, search); 1297 Map<String, CmsClientProperty> result = createClientProperties(props, false); 1298 return result; 1299 } 1300 1301 /** 1302 * Adds a function detail element to a container page.<p> 1303 * 1304 * @param cms the current CMS context 1305 * @param page the container page which should be changed 1306 * @param containerName the name of the container which should be used for function detail elements 1307 * @param elementId the structure id of the element to add 1308 * @param formatterId the structure id of the formatter for the element 1309 * 1310 * @throws CmsException if something goes wrong 1311 */ 1312 private void addFunctionDetailElement( 1313 CmsObject cms, 1314 CmsXmlContainerPage page, 1315 String containerName, 1316 CmsUUID elementId, 1317 CmsUUID formatterId) 1318 throws CmsException { 1319 1320 CmsContainerPageBean bean = page.getContainerPage(cms); 1321 List<CmsContainerBean> containerBeans = new ArrayList<CmsContainerBean>(); 1322 Collection<CmsContainerBean> originalContainers = bean.getContainers().values(); 1323 if ((containerName == null) && !originalContainers.isEmpty()) { 1324 CmsContainerBean firstContainer = originalContainers.iterator().next(); 1325 containerName = firstContainer.getName(); 1326 } 1327 boolean foundContainer = false; 1328 for (CmsContainerBean cntBean : originalContainers) { 1329 boolean isDetailTarget = cntBean.getName().equals(containerName); 1330 if (isDetailTarget && !foundContainer) { 1331 foundContainer = true; 1332 List<CmsContainerElementBean> newElems = new ArrayList<CmsContainerElementBean>(); 1333 newElems.addAll(cntBean.getElements()); 1334 CmsContainerElementBean newElement = new CmsContainerElementBean( 1335 elementId, 1336 formatterId, 1337 new HashMap<String, String>(), 1338 false); 1339 newElems.add(0, newElement); 1340 CmsContainerBean newCntBean = new CmsContainerBean( 1341 cntBean.getName(), 1342 cntBean.getType(), 1343 cntBean.getParentInstanceId(), 1344 cntBean.isRootContainer(), 1345 newElems); 1346 containerBeans.add(newCntBean); 1347 } else { 1348 containerBeans.add(cntBean); 1349 } 1350 } 1351 if (!foundContainer) { 1352 throw new CmsException( 1353 Messages.get().container(Messages.ERR_NO_FUNCTION_DETAIL_CONTAINER_1, page.getFile().getRootPath())); 1354 } 1355 CmsContainerPageBean bean2 = new CmsContainerPageBean(new ArrayList<CmsContainerBean>(containerBeans)); 1356 page.writeContainerPage(cms, bean2); 1357 1358 } 1359 1360 /** 1361 * Applys the given change to the VFS.<p> 1362 * 1363 * @param entryPoint the sitemap entry-point 1364 * @param change the change 1365 * 1366 * @return the updated entry 1367 * 1368 * @throws CmsException if something goes wrong 1369 */ 1370 private CmsSitemapChange applyChange(String entryPoint, CmsSitemapChange change) throws CmsException { 1371 1372 CmsObject cms = getCmsObject(); 1373 CmsResource configFile = null; 1374 // lock the config file first, to avoid half done changes 1375 if (change.hasDetailPageInfos()) { 1376 CmsADEConfigData configData = OpenCms.getADEManager().lookupConfiguration( 1377 cms, 1378 cms.getRequestContext().addSiteRoot(entryPoint)); 1379 if (!configData.isModuleConfiguration() && (configData.getResource() != null)) { 1380 configFile = configData.getResource(); 1381 } 1382 if (configFile != null) { 1383 ensureLock(configFile); 1384 } 1385 } 1386 if (change.isNew()) { 1387 CmsClientSitemapEntry newEntry = createNewEntry(entryPoint, change); 1388 change.setUpdatedEntry(newEntry); 1389 change.setEntryId(newEntry.getId()); 1390 } else if (change.getChangeType() == ChangeType.delete) { 1391 delete(change); 1392 } else if (change.getEntryId() != null) { 1393 modifyEntry(change); 1394 } 1395 if (change.hasDetailPageInfos() && (configFile != null)) { 1396 saveDetailPages(change.getDetailPageInfos(), configFile, change.getEntryId(), change.getUpdatedEntry()); 1397 tryUnlock(configFile); 1398 } 1399 1400 return change; 1401 } 1402 1403 /** 1404 * Changes the navigation for a moved entry and its neighbors.<p> 1405 * 1406 * @param change the sitemap change 1407 * @param entryFolder the moved entry 1408 * 1409 * @throws CmsException if something goes wrong 1410 */ 1411 private void applyNavigationChanges(CmsSitemapChange change, CmsResource entryFolder) throws CmsException { 1412 1413 CmsObject cms = getCmsObject(); 1414 String parentPath = null; 1415 if (change.hasNewParent()) { 1416 CmsResource parent = cms.readResource(change.getParentId()); 1417 parentPath = cms.getSitePath(parent); 1418 } else { 1419 parentPath = CmsResource.getParentFolder(cms.getSitePath(entryFolder)); 1420 } 1421 List<CmsJspNavElement> navElements = getNavBuilder().getNavigationForFolder( 1422 parentPath, 1423 Visibility.all, 1424 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 1425 CmsSitemapNavPosCalculator npc = new CmsSitemapNavPosCalculator(navElements, entryFolder, change.getPosition()); 1426 List<CmsJspNavElement> navs = npc.getNavigationChanges(); 1427 List<CmsResource> needToUnlock = new ArrayList<CmsResource>(); 1428 1429 try { 1430 for (CmsJspNavElement nav : navs) { 1431 LockInfo lockInfo = ensureLockAndGetInfo(nav.getResource()); 1432 if (!nav.getResource().equals(entryFolder) && lockInfo.wasJustLocked()) { 1433 needToUnlock.add(nav.getResource()); 1434 } 1435 } 1436 for (CmsJspNavElement nav : navs) { 1437 CmsProperty property = new CmsProperty( 1438 CmsPropertyDefinition.PROPERTY_NAVPOS, 1439 "" + nav.getNavPosition(), 1440 null); 1441 cms.writePropertyObject(cms.getSitePath(nav.getResource()), property); 1442 } 1443 } finally { 1444 for (CmsResource lockedRes : needToUnlock) { 1445 try { 1446 cms.unlockResource(lockedRes); 1447 } catch (CmsException e) { 1448 // we catch this because we still want to unlock the other resources 1449 LOG.error(e.getLocalizedMessage(), e); 1450 } 1451 } 1452 } 1453 } 1454 1455 /** 1456 * Builds the list info bean for a resource type which can be used as a sub-sitemap folder.<p> 1457 * 1458 * @param sitemapType the sitemap folder type 1459 * 1460 * @return the list info bean for the given type 1461 */ 1462 private CmsListInfoBean buildSitemapTypeInfo(I_CmsResourceType sitemapType) { 1463 1464 CmsListInfoBean result = new CmsListInfoBean(); 1465 CmsWorkplaceManager wm = OpenCms.getWorkplaceManager(); 1466 String typeName = sitemapType.getTypeName(); 1467 Locale wpLocale = wm.getWorkplaceLocale(getCmsObject()); 1468 String title = typeName; 1469 String description = ""; 1470 try { 1471 title = CmsWorkplaceMessages.getResourceTypeName(wpLocale, typeName); 1472 } catch (Throwable e) { 1473 LOG.warn(e.getLocalizedMessage(), e); 1474 } 1475 try { 1476 description = CmsWorkplaceMessages.getResourceTypeDescription(wpLocale, typeName); 1477 } catch (Throwable e) { 1478 LOG.warn(e.getLocalizedMessage(), e); 1479 } 1480 result.setResourceType(typeName); 1481 result.setTitle(title); 1482 result.setSubTitle(description); 1483 return result; 1484 } 1485 1486 /** 1487 * Returns all available gallery folder resource types.<p> 1488 * 1489 * @return the gallery folder resource types 1490 */ 1491 @SuppressWarnings("deprecation") 1492 private List<CmsGalleryType> collectGalleryTypes() { 1493 1494 Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject()); 1495 Map<String, List<String>> galleryContentTypes = new HashMap<String, List<String>>(); 1496 List<CmsGalleryType> result = new ArrayList<CmsGalleryType>(); 1497 for (I_CmsResourceType resourceType : OpenCms.getResourceManager().getResourceTypes()) { 1498 if (resourceType instanceof CmsResourceTypeFolderExtended) { 1499 // found a configured extended folder resource type 1500 CmsResourceTypeFolderExtended galleryType = (CmsResourceTypeFolderExtended)resourceType; 1501 String folderClassName = galleryType.getFolderClassName(); 1502 if (CmsStringUtil.isNotEmpty(folderClassName)) { 1503 // only process this as a gallery if the folder name is not empty 1504 try { 1505 // check, if the folder class is a subclass of A_CmsGallery 1506 if (A_CmsAjaxGallery.class.isAssignableFrom(Class.forName(folderClassName))) { 1507 CmsGalleryType gallery = new CmsGalleryType(); 1508 gallery.setTypeId(resourceType.getTypeId()); 1509 gallery.setResourceType(resourceType.getTypeName()); 1510 gallery.setTitle( 1511 CmsWorkplaceMessages.getResourceTypeName(wpLocale, resourceType.getTypeName())); 1512 gallery.setSubTitle( 1513 CmsWorkplaceMessages.getResourceTypeDescription(wpLocale, resourceType.getTypeName())); 1514 gallery.setBigIconClasses( 1515 CmsIconUtil.getIconClasses(resourceType.getTypeName(), null, false)); 1516 result.add(gallery); 1517 } 1518 } catch (Exception e) { 1519 this.log(e.getLocalizedMessage(), e); 1520 } 1521 } 1522 } else { 1523 List<I_CmsResourceType> galleryTypes = resourceType.getGalleryTypes(); 1524 if ((galleryTypes != null) && !galleryTypes.isEmpty()) { 1525 for (I_CmsResourceType galleryType : galleryTypes) { 1526 List<String> typeList = galleryContentTypes.get(galleryType.getTypeName()); 1527 if (typeList == null) { 1528 typeList = new ArrayList<String>(); 1529 galleryContentTypes.put(galleryType.getTypeName(), typeList); 1530 } 1531 typeList.add(resourceType.getTypeName()); 1532 } 1533 } 1534 } 1535 } 1536 for (CmsGalleryType galleryType : result) { 1537 galleryType.setContentTypeNames(galleryContentTypes.get(galleryType.getResourceType())); 1538 } 1539 return result; 1540 } 1541 1542 /** 1543 * Gets the information for the available sitemap folder types.<p> 1544 * 1545 * @param cms the current CMS context 1546 * @param configData the configuration data for the current subsitemap 1547 * @return the list info beans corresponding to available sitemap folder types 1548 */ 1549 private List<CmsListInfoBean> collectSitemapTypeInfos(CmsObject cms, CmsADEConfigData configData) { 1550 1551 List<CmsListInfoBean> subsitemapFolderTypeInfos = new ArrayList<CmsListInfoBean>(); 1552 List<Integer> sitemapTypeIds = CmsResourceTypeFolderSubSitemap.getSubSitemapResourceTypeIds(); 1553 String checkPath = configData.getBasePath(); 1554 if (checkPath != null) { 1555 checkPath = cms.getRequestContext().removeSiteRoot(checkPath); 1556 } else { 1557 checkPath = "/"; 1558 } 1559 CmsResource checkResource = null; 1560 try { 1561 checkResource = cms.readResource(checkPath); 1562 } catch (CmsException e) { 1563 LOG.warn(e.getLocalizedMessage(), e); 1564 } 1565 1566 for (Integer typeId : sitemapTypeIds) { 1567 try { 1568 I_CmsResourceType sitemapType = OpenCms.getResourceManager().getResourceType(typeId.intValue()); 1569 String typeName = sitemapType.getTypeName(); 1570 CmsExplorerTypeSettings explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(typeName); 1571 1572 // if explorer type and check resource available, perform a permission check 1573 if ((explorerType != null) && (checkResource != null)) { 1574 try { 1575 CmsExplorerTypeAccess access = explorerType.getAccess(); 1576 if (!access.getPermissions(cms, checkResource).requiresControlPermission()) { 1577 continue; 1578 } 1579 } catch (Exception e) { 1580 LOG.error(e.getLocalizedMessage(), e); 1581 } 1582 } 1583 CmsListInfoBean infoBean = buildSitemapTypeInfo(sitemapType); 1584 subsitemapFolderTypeInfos.add(infoBean); 1585 1586 } catch (CmsLoaderException e) { 1587 LOG.warn("Could not read sitemap folder type " + typeId + ": " + e.getLocalizedMessage(), e); 1588 } 1589 } 1590 return subsitemapFolderTypeInfos; 1591 } 1592 1593 /** 1594 * Creates a client alias bean from a server-side alias.<p> 1595 * 1596 * @param cms the current CMS context 1597 * @param alias the alias to convert 1598 * 1599 * @return the alias table row 1600 * 1601 * @throws CmsException if something goes wrong 1602 */ 1603 private CmsAliasTableRow createAliasTableEntry(CmsObject cms, CmsAlias alias) throws CmsException { 1604 1605 CmsResource resource = cms.readResource(alias.getStructureId(), CmsResourceFilter.ALL); 1606 CmsAliasTableRow result = new CmsAliasTableRow(); 1607 result.setStructureId(alias.getStructureId()); 1608 result.setOriginalStructureId(alias.getStructureId()); 1609 result.setAliasPath(alias.getAliasPath()); 1610 result.setResourcePath(cms.getSitePath(resource)); 1611 result.setKey((new CmsUUID()).toString()); 1612 result.setMode(alias.getMode()); 1613 result.setChanged(false); 1614 return result; 1615 } 1616 1617 /** 1618 * Creates a navigation level type info.<p> 1619 * 1620 * @return the navigation level type info bean 1621 * 1622 * @throws CmsException if reading the sub level redirect copy page fails 1623 */ 1624 private CmsNewResourceInfo createNavigationLevelTypeInfo() throws CmsException { 1625 1626 String name = CmsResourceTypeFolder.getStaticTypeName(); 1627 Locale locale = getWorkplaceLocale(); 1628 String subtitle = Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_NAVIGATION_LEVEL_SUBTITLE_0); 1629 if (CmsStringUtil.isEmptyOrWhitespaceOnly(subtitle)) { 1630 subtitle = CmsWorkplaceMessages.getResourceTypeName(locale, name); 1631 } 1632 CmsNewResourceInfo result = new CmsNewResourceInfo( 1633 CmsResourceTypeFolder.getStaticTypeId(), 1634 name, 1635 Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_NAVIGATION_LEVEL_TITLE_0), 1636 subtitle, 1637 getCmsObject().readResource(SUB_LEVEL_REDIRECT_COPY_PAGE).getStructureId(), 1638 false, 1639 subtitle); 1640 result.setBigIconClasses(CmsIconUtil.ICON_NAV_LEVEL_BIG); 1641 result.setCreateParameter(CmsJspNavBuilder.NAVIGATION_LEVEL_FOLDER); 1642 return result; 1643 } 1644 1645 /** 1646 * Creates new content elements if required by the model page.<p> 1647 * 1648 * @param cms the cms context 1649 * @param page the page 1650 * @param sitePath the resource site path 1651 * 1652 * @throws CmsException when unable to create the content elements 1653 */ 1654 private void createNewContainerElements(CmsObject cms, CmsXmlContainerPage page, String sitePath) 1655 throws CmsException { 1656 1657 CmsADEConfigData configData = OpenCms.getADEManager().lookupConfiguration(cms, cms.addSiteRoot(sitePath)); 1658 Locale contentLocale = OpenCms.getLocaleManager().getDefaultLocale(cms, CmsResource.getFolderPath(sitePath)); 1659 CmsObject cloneCms = OpenCms.initCmsObject(cms); 1660 cloneCms.getRequestContext().setLocale(contentLocale); 1661 CmsContainerPageBean pageBean = page.getContainerPage(cms); 1662 boolean needsChanges = false; 1663 List<CmsContainerBean> updatedContainers = new ArrayList<CmsContainerBean>(); 1664 for (CmsContainerBean container : pageBean.getContainers().values()) { 1665 List<CmsContainerElementBean> updatedElements = new ArrayList<CmsContainerElementBean>(); 1666 for (CmsContainerElementBean element : container.getElements()) { 1667 if (element.isCreateNew() && !element.isGroupContainer(cms) && !element.isInheritedContainer(cms)) { 1668 needsChanges = true; 1669 String typeName = OpenCms.getResourceManager().getResourceType(element.getResource()).getTypeName(); 1670 CmsResourceTypeConfig typeConfig = configData.getResourceType(typeName); 1671 if (typeConfig == null) { 1672 throw new IllegalArgumentException( 1673 "Can not copy template model element '" 1674 + element.getResource().getRootPath() 1675 + "' because the resource type '" 1676 + typeName 1677 + "' is not available in this sitemap."); 1678 } 1679 1680 CmsResource newResource = typeConfig.createNewElement( 1681 cloneCms, 1682 element.getResource(), 1683 CmsResource.getParentFolder(cms.getRequestContext().addSiteRoot(sitePath))); 1684 CmsContainerElementBean newBean = new CmsContainerElementBean( 1685 newResource.getStructureId(), 1686 element.getFormatterId(), 1687 element.getIndividualSettings(), 1688 false); 1689 updatedElements.add(newBean); 1690 } else { 1691 updatedElements.add(element); 1692 } 1693 } 1694 1695 CmsContainerBean updatedContainer = new CmsContainerBean( 1696 container.getName(), 1697 container.getType(), 1698 container.getParentInstanceId(), 1699 container.isRootContainer(), 1700 container.getMaxElements(), 1701 updatedElements); 1702 updatedContainers.add(updatedContainer); 1703 } 1704 if (needsChanges) { 1705 CmsContainerPageBean updatedPage = new CmsContainerPageBean(updatedContainers); 1706 page.writeContainerPage(cms, updatedPage); 1707 } 1708 } 1709 1710 /** 1711 * Creates a new page in navigation.<p> 1712 * 1713 * @param entryPoint the site-map entry-point 1714 * @param change the new change 1715 * 1716 * @return the updated entry 1717 * 1718 * @throws CmsException if something goes wrong 1719 */ 1720 @SuppressWarnings("deprecation") 1721 private CmsClientSitemapEntry createNewEntry(String entryPoint, CmsSitemapChange change) throws CmsException { 1722 1723 CmsObject cms = getCmsObject(); 1724 CmsClientSitemapEntry newEntry = null; 1725 if (change.getParentId() != null) { 1726 CmsResource parentFolder = cms.readResource( 1727 change.getParentId(), 1728 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 1729 String entryPath = ""; 1730 CmsResource entryFolder = null; 1731 CmsResource newRes = null; 1732 byte[] content = null; 1733 List<CmsProperty> properties = Collections.emptyList(); 1734 CmsResource copyPage = null; 1735 if (change.getNewCopyResourceId() != null) { 1736 copyPage = cms.readResource(change.getNewCopyResourceId(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 1737 content = cms.readFile(copyPage).getContents(); 1738 properties = cms.readPropertyObjects(copyPage, false); 1739 } 1740 List<CmsProperty> filteredProperties = new ArrayList<CmsProperty>(); 1741 for (CmsProperty property : properties) { 1742 boolean filter = false; 1743 if (FILTER_PROPERTIES.contains(property.getName())) { 1744 filter = true; 1745 1746 } else { 1747 // filter localized versions also 1748 for (String filterProp : FILTER_PROPERTIES) { 1749 if (property.getName().startsWith(filterProp + "_")) { 1750 filter = true; 1751 break; 1752 } 1753 } 1754 } 1755 if (!filter) { 1756 filteredProperties.add(property); 1757 } 1758 } 1759 properties = filteredProperties; 1760 if (isRedirectType(change.getNewResourceTypeId())) { 1761 entryPath = CmsStringUtil.joinPaths(cms.getSitePath(parentFolder), change.getName()); 1762 newRes = cms.createResource( 1763 entryPath, 1764 change.getNewResourceTypeId(), 1765 null, 1766 Collections.singletonList( 1767 new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, change.getName(), null))); 1768 cms.writePropertyObjects(newRes, generateInheritProperties(change, newRes)); 1769 applyNavigationChanges(change, newRes); 1770 } else { 1771 String entryFolderPath = CmsStringUtil.joinPaths(cms.getSitePath(parentFolder), change.getName() + "/"); 1772 boolean idWasNull = change.getEntryId() == null; 1773 // we don't really need to create a folder object here anymore. 1774 if (idWasNull) { 1775 // need this for calculateNavPosition, even though the id will get overwritten 1776 change.setEntryId(new CmsUUID()); 1777 } 1778 1779 boolean isFunctionDetail = false; 1780 boolean isNavigationLevel = false; 1781 if (change.getCreateParameter() != null) { 1782 if (CmsUUID.isValidUUID(change.getCreateParameter())) { 1783 isFunctionDetail = true; 1784 } else if (CmsJspNavBuilder.NAVIGATION_LEVEL_FOLDER.equals(change.getCreateParameter())) { 1785 isNavigationLevel = true; 1786 } 1787 } 1788 String folderType = CmsResourceTypeFolder.getStaticTypeName(); 1789 String createSitemapFolderType = change.getCreateSitemapFolderType(); 1790 if (createSitemapFolderType != null) { 1791 folderType = createSitemapFolderType; 1792 } 1793 1794 int folderTypeId = OpenCms.getResourceManager().getResourceType(folderType).getTypeId(); 1795 entryFolder = new CmsResource( 1796 change.getEntryId(), 1797 new CmsUUID(), 1798 entryFolderPath, 1799 folderTypeId, 1800 true, 1801 0, 1802 cms.getRequestContext().getCurrentProject().getUuid(), 1803 CmsResource.STATE_NEW, 1804 System.currentTimeMillis(), 1805 cms.getRequestContext().getCurrentUser().getId(), 1806 System.currentTimeMillis(), 1807 cms.getRequestContext().getCurrentUser().getId(), 1808 CmsResource.DATE_RELEASED_DEFAULT, 1809 CmsResource.DATE_EXPIRED_DEFAULT, 1810 1, 1811 0, 1812 System.currentTimeMillis(), 1813 0); 1814 List<CmsProperty> folderProperties = generateInheritProperties(change, entryFolder); 1815 if (isNavigationLevel) { 1816 folderProperties.add( 1817 new CmsProperty( 1818 CmsPropertyDefinition.PROPERTY_DEFAULT_FILE, 1819 CmsJspNavBuilder.NAVIGATION_LEVEL_FOLDER, 1820 null)); 1821 } 1822 entryFolder = cms.createResource(entryFolderPath, folderTypeId, null, folderProperties); 1823 if (createSitemapFolderType != null) { 1824 createSitemapContentFolder(cms, entryFolder); 1825 } 1826 if (idWasNull) { 1827 change.setEntryId(entryFolder.getStructureId()); 1828 } 1829 applyNavigationChanges(change, entryFolder); 1830 entryPath = CmsStringUtil.joinPaths(entryFolderPath, "index.html"); 1831 boolean isContainerPage = change.getNewResourceTypeId() == CmsResourceTypeXmlContainerPage.getContainerPageTypeIdSafely(); 1832 if (isContainerPage && (copyPage != null)) { 1833 1834 // do *NOT* get this from the cache, because we perform some destructive operation on the XML content 1835 CmsXmlContainerPage page = CmsXmlContainerPageFactory.unmarshal( 1836 cms, 1837 cms.readFile(copyPage), 1838 true, 1839 true); 1840 ensureSingleLocale(page, entryFolder); 1841 if (isFunctionDetail) { 1842 String functionDetailContainer = getFunctionDetailContainerName(parentFolder); 1843 CmsUUID functionStructureId = new CmsUUID(change.getCreateParameter()); 1844 CmsResource functionRes = cms.readResource( 1845 functionStructureId, 1846 CmsResourceFilter.IGNORE_EXPIRATION); 1847 CmsResource functionFormatter; 1848 if (OpenCms.getResourceManager().matchResourceType( 1849 CmsResourceTypeFunctionConfig.TYPE_NAME, 1850 functionRes.getTypeId())) { 1851 functionFormatter = cms.readResource(CmsResourceTypeFunctionConfig.FORMATTER_PATH); 1852 } else { 1853 functionFormatter = cms.readResource( 1854 CmsResourceTypeFunctionConfig.FORMATTER_PATH, 1855 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 1856 } 1857 addFunctionDetailElement( 1858 cms, 1859 page, 1860 functionDetailContainer, 1861 functionStructureId, 1862 functionFormatter.getStructureId()); 1863 } 1864 createNewContainerElements(cms, page, entryPath); 1865 content = page.marshal(); 1866 } 1867 newRes = cms.createResource( 1868 entryPath, 1869 copyPage != null ? copyPage.getTypeId() : change.getNewResourceTypeId(), 1870 content, 1871 properties); 1872 cms.writePropertyObjects(newRes, generateOwnProperties(change)); 1873 } 1874 1875 if (entryFolder != null) { 1876 tryUnlock(entryFolder); 1877 String sitePath = cms.getSitePath(entryFolder); 1878 newEntry = toClientEntry( 1879 getNavBuilder().getNavigationForResource(sitePath, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED), 1880 false); 1881 newEntry.setSubEntries(getChildren(sitePath, 1, null), null); 1882 newEntry.setChildrenLoadedInitially(true); 1883 } 1884 if (newRes != null) { 1885 tryUnlock(newRes); 1886 } 1887 if (newEntry == null) { 1888 newEntry = toClientEntry( 1889 getNavBuilder().getNavigationForResource( 1890 cms.getSitePath(newRes), 1891 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED), 1892 false); 1893 } 1894 // mark position as not set 1895 newEntry.setPosition(-1); 1896 newEntry.setNew(true); 1897 change.getClipBoardData().getModifications().remove(null); 1898 change.getClipBoardData().getModifications().put(newEntry.getId(), newEntry); 1899 } 1900 return newEntry; 1901 } 1902 1903 /** 1904 * Creates a new resource info to a given model page resource.<p> 1905 * 1906 * @param cms the current CMS context 1907 * @param modelResource the model page resource 1908 * @param locale the locale used for retrieving descriptions/titles 1909 * 1910 * @return the new resource info 1911 * 1912 * @throws CmsException if something goes wrong 1913 */ 1914 private CmsNewResourceInfo createNewResourceInfo(CmsObject cms, CmsResource modelResource, Locale locale) 1915 throws CmsException { 1916 1917 // if model page got overwritten by another resource, reread from site path 1918 if (!cms.existsResource(modelResource.getStructureId(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) { 1919 modelResource = cms.readResource(cms.getSitePath(modelResource), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 1920 } 1921 int typeId = modelResource.getTypeId(); 1922 String name = OpenCms.getResourceManager().getResourceType(typeId).getTypeName(); 1923 String title = cms.readPropertyObject( 1924 modelResource, 1925 CmsPropertyDefinition.PROPERTY_TITLE, 1926 false, 1927 locale).getValue(); 1928 String description = cms.readPropertyObject( 1929 modelResource, 1930 CmsPropertyDefinition.PROPERTY_DESCRIPTION, 1931 false, 1932 locale).getValue(); 1933 1934 boolean editable = false; 1935 try { 1936 CmsResource freshModelResource = cms.readResource( 1937 modelResource.getStructureId(), 1938 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 1939 editable = cms.hasPermissions( 1940 freshModelResource, 1941 CmsPermissionSet.ACCESS_WRITE, 1942 false, 1943 CmsResourceFilter.DEFAULT); 1944 } catch (CmsException e) { 1945 LOG.warn(e.getLocalizedMessage(), e); 1946 } 1947 CmsNewResourceInfo info = new CmsNewResourceInfo( 1948 typeId, 1949 name, 1950 title, 1951 description, 1952 modelResource.getStructureId(), 1953 editable, 1954 description); 1955 info.setBigIconClasses(CmsIconUtil.getIconClasses(name, null, false)); 1956 Float navpos = null; 1957 try { 1958 CmsProperty navposProp = cms.readPropertyObject(modelResource, CmsPropertyDefinition.PROPERTY_NAVPOS, true); 1959 String navposStr = navposProp.getValue(); 1960 if (navposStr != null) { 1961 try { 1962 navpos = Float.valueOf(navposStr); 1963 } catch (NumberFormatException e) { 1964 // noop 1965 } 1966 } 1967 } catch (CmsException e) { 1968 LOG.warn(e.getLocalizedMessage(), e); 1969 } 1970 1971 info.setNavPos(navpos); 1972 info.setDate( 1973 CmsDateUtil.getDate(new Date(modelResource.getDateLastModified()), DateFormat.LONG, getWorkplaceLocale())); 1974 info.setVfsPath(modelResource.getRootPath()); 1975 return info; 1976 } 1977 1978 /** 1979 * Creates a resource type info bean for a given resource type.<p> 1980 * 1981 * @param resType the resource type 1982 * @param copyResource the structure id of the copy resource 1983 * 1984 * @return the resource type info bean 1985 */ 1986 @SuppressWarnings("deprecation") 1987 private CmsNewResourceInfo createResourceTypeInfo(I_CmsResourceType resType, CmsResource copyResource) { 1988 1989 String name = resType.getTypeName(); 1990 Locale locale = getWorkplaceLocale(); 1991 String subtitle = CmsWorkplaceMessages.getResourceTypeDescription(locale, name); 1992 if (CmsStringUtil.isEmptyOrWhitespaceOnly(subtitle)) { 1993 subtitle = CmsWorkplaceMessages.getResourceTypeName(locale, name); 1994 } 1995 if (copyResource != null) { 1996 CmsNewResourceInfo info = new CmsNewResourceInfo( 1997 copyResource.getTypeId(), 1998 name, 1999 CmsWorkplaceMessages.getResourceTypeName(locale, name), 2000 CmsWorkplaceMessages.getResourceTypeDescription(locale, name), 2001 copyResource.getStructureId(), 2002 false, 2003 subtitle); 2004 info.setBigIconClasses(CmsIconUtil.getIconClasses(name, null, false)); 2005 return info; 2006 } else { 2007 CmsNewResourceInfo info = new CmsNewResourceInfo( 2008 resType.getTypeId(), 2009 name, 2010 CmsWorkplaceMessages.getResourceTypeName(locale, name), 2011 CmsWorkplaceMessages.getResourceTypeDescription(locale, name), 2012 null, 2013 false, 2014 subtitle); 2015 info.setBigIconClasses(CmsIconUtil.getIconClasses(name, null, false)); 2016 return info; 2017 } 2018 } 2019 2020 /** 2021 * Helper method for creating the .content folder of a sub-sitemap.<p> 2022 * 2023 * @param cms the current CMS context 2024 * @param subSitemapFolder the sub-sitemap folder in which the .content folder should be created 2025 * 2026 * @throws CmsException if something goes wrong 2027 */ 2028 @SuppressWarnings("deprecation") 2029 private void createSitemapContentFolder(CmsObject cms, CmsResource subSitemapFolder) throws CmsException { 2030 2031 String sitePath = cms.getSitePath(subSitemapFolder); 2032 String folderName = CmsStringUtil.joinPaths(sitePath, CmsADEManager.CONTENT_FOLDER_NAME + "/"); 2033 String sitemapConfigName = CmsStringUtil.joinPaths(folderName, CmsADEManager.CONFIG_FILE_NAME); 2034 if (!cms.existsResource(folderName)) { 2035 cms.createResource( 2036 folderName, 2037 OpenCms.getResourceManager().getResourceType(CmsADEManager.CONFIG_FOLDER_TYPE)); 2038 } 2039 I_CmsResourceType configType = OpenCms.getResourceManager().getResourceType(CmsADEManager.CONFIG_TYPE); 2040 if (cms.existsResource(sitemapConfigName)) { 2041 CmsResource configFile = cms.readResource(sitemapConfigName); 2042 if (configFile.getTypeId() != configType.getTypeId()) { 2043 throw new CmsException( 2044 Messages.get().container( 2045 Messages.ERR_CREATING_SUB_SITEMAP_WRONG_CONFIG_FILE_TYPE_2, 2046 sitemapConfigName, 2047 CmsADEManager.CONFIG_TYPE)); 2048 } 2049 } else { 2050 cms.createResource( 2051 sitemapConfigName, 2052 OpenCms.getResourceManager().getResourceType(CmsADEManager.CONFIG_TYPE)); 2053 } 2054 2055 } 2056 2057 /** 2058 * Deletes a resource according to the change data.<p> 2059 * 2060 * @param change the change data 2061 * 2062 * @return CmsClientSitemapEntry always null 2063 * 2064 * 2065 * @throws CmsException if something goes wrong 2066 */ 2067 private CmsClientSitemapEntry delete(CmsSitemapChange change) throws CmsException { 2068 2069 CmsObject cms = getCmsObject(); 2070 CmsResource resource = cms.readResource(change.getEntryId(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2071 ensureLock(resource); 2072 cms.deleteResource(cms.getSitePath(resource), CmsResource.DELETE_PRESERVE_SIBLINGS); 2073 tryUnlock(resource); 2074 return null; 2075 } 2076 2077 /** 2078 * Generates a client side lock info object representing the current lock state of the given resource.<p> 2079 * 2080 * @param resource the resource 2081 * 2082 * @return the client lock 2083 * 2084 * @throws CmsException if something goes wrong 2085 */ 2086 private CmsClientLock generateClientLock(CmsResource resource) throws CmsException { 2087 2088 CmsObject cms = getCmsObject(); 2089 CmsLock lock = cms.getLock(resource); 2090 CmsClientLock clientLock = new CmsClientLock(); 2091 clientLock.setLockType(CmsClientLock.LockType.valueOf(lock.getType().getMode())); 2092 CmsUUID ownerId = lock.getUserId(); 2093 if (!lock.isUnlocked() && (ownerId != null)) { 2094 clientLock.setLockOwner(cms.readUser(ownerId).getDisplayName(cms, cms.getRequestContext().getLocale())); 2095 clientLock.setOwnedByUser(cms.getRequestContext().getCurrentUser().getId().equals(ownerId)); 2096 } 2097 return clientLock; 2098 } 2099 2100 /** 2101 * Generates a list of property object to save to the sitemap entry folder to apply the given change.<p> 2102 * 2103 * @param change the change 2104 * @param entryFolder the entry folder 2105 * 2106 * @return the property objects 2107 */ 2108 private List<CmsProperty> generateInheritProperties(CmsSitemapChange change, CmsResource entryFolder) { 2109 2110 List<CmsProperty> result = new ArrayList<CmsProperty>(); 2111 Map<String, CmsClientProperty> clientProps = change.getOwnInternalProperties(); 2112 boolean hasTitle = false; 2113 if (clientProps != null) { 2114 for (CmsClientProperty clientProp : clientProps.values()) { 2115 if (CmsPropertyDefinition.PROPERTY_TITLE.equals(clientProp.getName())) { 2116 hasTitle = true; 2117 } 2118 CmsProperty prop = new CmsProperty( 2119 clientProp.getName(), 2120 clientProp.getStructureValue(), 2121 clientProp.getResourceValue()); 2122 result.add(prop); 2123 } 2124 } 2125 if (!hasTitle) { 2126 result.add(new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, change.getName(), null)); 2127 } 2128 return result; 2129 } 2130 2131 /** 2132 * Generates a list of property object to save to the sitemap entry resource to apply the given change.<p> 2133 * 2134 * @param change the change 2135 * 2136 * @return the property objects 2137 */ 2138 private List<CmsProperty> generateOwnProperties(CmsSitemapChange change) { 2139 2140 List<CmsProperty> result = new ArrayList<CmsProperty>(); 2141 2142 Map<String, CmsClientProperty> clientProps = change.getDefaultFileProperties(); 2143 boolean hasTitle = false; 2144 if (clientProps != null) { 2145 for (CmsClientProperty clientProp : clientProps.values()) { 2146 if (CmsPropertyDefinition.PROPERTY_TITLE.equals(clientProp.getName())) { 2147 hasTitle = true; 2148 } 2149 CmsProperty prop = new CmsProperty( 2150 clientProp.getName(), 2151 clientProp.getStructureValue(), 2152 clientProp.getResourceValue()); 2153 result.add(prop); 2154 } 2155 } 2156 if (!hasTitle) { 2157 result.add(new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, change.getName(), null)); 2158 } 2159 return result; 2160 } 2161 2162 /** 2163 * Generates a list of property values inherited to the site-map root entry.<p> 2164 * 2165 * @param rootPath the root entry name 2166 * 2167 * @return the list of property values inherited to the site-map root entry 2168 * 2169 * @throws CmsException if something goes wrong reading the properties 2170 */ 2171 private Map<String, CmsClientProperty> generateParentProperties(String rootPath) throws CmsException { 2172 2173 CmsObject cms = getCmsObject(); 2174 if (rootPath == null) { 2175 rootPath = cms.getRequestContext().addSiteRoot("/"); 2176 } 2177 CmsObject rootCms = OpenCms.initCmsObject(cms); 2178 rootCms.getRequestContext().setSiteRoot(""); 2179 String parentRootPath = CmsResource.getParentFolder(rootPath); 2180 2181 Map<String, CmsClientProperty> result = new HashMap<String, CmsClientProperty>(); 2182 if (parentRootPath != null) { 2183 List<CmsProperty> props = rootCms.readPropertyObjects(parentRootPath, true); 2184 for (CmsProperty prop : props) { 2185 CmsClientProperty clientProp = createClientProperty(prop, true); 2186 result.put(clientProp.getName(), clientProp); 2187 } 2188 } 2189 return result; 2190 } 2191 2192 /** 2193 * Returns the sitemap children for the given path with all descendants up to the given level or to the given target path, ie. 2194 * <dl><dt>levels=1 <dd>only children<dt>levels=2<dd>children and great children</dl> 2195 * and so on.<p> 2196 * 2197 * @param root the site relative root 2198 * @param levels the levels to recurse 2199 * @param targetPath the target path 2200 * 2201 * @return the sitemap children 2202 */ 2203 private List<CmsClientSitemapEntry> getChildren(String root, int levels, String targetPath) { 2204 2205 List<CmsClientSitemapEntry> children = new ArrayList<CmsClientSitemapEntry>(); 2206 int i = 0; 2207 for (CmsJspNavElement navElement : getNavBuilder().getNavigationForFolder( 2208 root, 2209 Visibility.all, 2210 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) { 2211 try { 2212 CmsClientSitemapEntry child = toClientEntry(navElement, false); 2213 if (child != null) { 2214 child.setPosition(i); 2215 children.add(child); 2216 int nextLevels = levels; 2217 if ((nextLevels == 2) && (targetPath != null) && targetPath.startsWith(child.getSitePath())) { 2218 nextLevels = 3; 2219 } 2220 if (child.isFolderType() && ((nextLevels > 1) || (nextLevels == -1)) && !isSubSitemap(navElement)) { 2221 2222 child.setSubEntries(getChildren(child.getSitePath(), nextLevels - 1, targetPath), null); 2223 child.setChildrenLoadedInitially(true); 2224 } 2225 i++; 2226 } 2227 } catch (CmsException e) { 2228 LOG.error("Could not read sitemap entry.", e); 2229 } 2230 } 2231 return children; 2232 } 2233 2234 /** 2235 * Returns the clipboard data from the current user.<p> 2236 * 2237 * @return the clipboard data 2238 */ 2239 private CmsSitemapClipboardData getClipboardData() { 2240 2241 CmsSitemapClipboardData result = new CmsSitemapClipboardData(); 2242 result.setModifications(getModifiedList()); 2243 result.setDeletions(getDeletedList()); 2244 return result; 2245 } 2246 2247 /** 2248 * Returns the deleted list from the current user.<p> 2249 * 2250 * @return the deleted list 2251 */ 2252 private LinkedHashMap<CmsUUID, CmsClientSitemapEntry> getDeletedList() { 2253 2254 CmsObject cms = getCmsObject(); 2255 CmsUser user = cms.getRequestContext().getCurrentUser(); 2256 Object obj = user.getAdditionalInfo(ADDINFO_ADE_DELETED_LIST); 2257 LinkedHashMap<CmsUUID, CmsClientSitemapEntry> result = new LinkedHashMap<CmsUUID, CmsClientSitemapEntry>(); 2258 if (obj instanceof String) { 2259 try { 2260 JSONArray array = new JSONArray((String)obj); 2261 for (int i = 0; i < array.length(); i++) { 2262 try { 2263 CmsUUID delId = new CmsUUID(array.getString(i)); 2264 CmsResource res = cms.readResource(delId, CmsResourceFilter.ALL); 2265 if (res.getState().isDeleted()) { 2266 // make sure resource is still deleted 2267 CmsClientSitemapEntry delEntry = new CmsClientSitemapEntry(); 2268 delEntry.setSitePath(cms.getSitePath(res)); 2269 delEntry.setOwnProperties(getClientProperties(cms, res, false)); 2270 delEntry.setName(res.getName()); 2271 delEntry.setVfsPath(cms.getSitePath(res)); 2272 delEntry.setResourceTypeName( 2273 OpenCms.getResourceManager().getResourceType(res).getTypeName()); 2274 delEntry.setEntryType( 2275 res.isFolder() 2276 ? EntryType.folder 2277 : isRedirectType(res.getTypeId()) ? EntryType.redirect : EntryType.leaf); 2278 delEntry.setNavModeIcon( 2279 CmsIconUtil.getIconClasses( 2280 delEntry.getResourceTypeName(), 2281 delEntry.getVfsPath(), 2282 false)); 2283 delEntry.setId(delId); 2284 result.put(delId, delEntry); 2285 } 2286 } catch (Throwable e) { 2287 // should never happen, catches wrong or no longer existing values 2288 LOG.warn(e.getLocalizedMessage()); 2289 } 2290 } 2291 } catch (Throwable e) { 2292 // should never happen, catches json parsing 2293 LOG.warn(e.getLocalizedMessage()); 2294 } 2295 } 2296 return result; 2297 } 2298 2299 /** 2300 * Gets the container name for function detail elements depending on the parent folder.<p> 2301 * 2302 * @param parent the parent folder 2303 * @return the name of the function detail container 2304 */ 2305 private String getFunctionDetailContainerName(CmsResource parent) { 2306 2307 CmsObject cms = getCmsObject(); 2308 String notFound = null; 2309 String containerInfo = OpenCms.getTemplateContextManager().readPropertyFromTemplate( 2310 cms, 2311 parent, 2312 CmsPropertyDefinition.PROPERTY_CONTAINER_INFO, 2313 notFound); 2314 if (containerInfo == notFound) { 2315 return null; 2316 } 2317 Map<String, String> attrs = CmsStringUtil.splitAsMap(containerInfo, "|", "="); //$NON-NLS-2$ 2318 String functionDetailContainerName = attrs.get(KEY_FUNCTION_DETAIL); 2319 return functionDetailContainerName; 2320 } 2321 2322 /** 2323 * Returns the galleries of the given sub site for the requested gallery type.<p> 2324 * 2325 * @param entryPointUri the sub site entry point 2326 * @param galleryType the gallery type 2327 * @param subSitePaths the sub site paths 2328 * 2329 * @return the gallery folder entries 2330 * 2331 * @throws CmsException if reading the resources fails 2332 */ 2333 private List<CmsGalleryFolderEntry> getGalleriesForType( 2334 String entryPointUri, 2335 CmsGalleryType galleryType, 2336 List<String> subSitePaths) 2337 throws CmsException { 2338 2339 List<CmsGalleryFolderEntry> galleries = new ArrayList<CmsGalleryFolderEntry>(); 2340 @SuppressWarnings("deprecation") 2341 List<CmsResource> galleryFolders = getCmsObject().readResources( 2342 entryPointUri, 2343 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireType(galleryType.getTypeId())); 2344 for (CmsResource folder : galleryFolders) { 2345 try { 2346 if (!isInSubsite(subSitePaths, folder.getRootPath())) { 2347 galleries.add(readGalleryFolderEntry(folder, galleryType.getResourceType())); 2348 } 2349 } catch (CmsException ex) { 2350 log(ex.getLocalizedMessage(), ex); 2351 } 2352 } 2353 // create a tree structure 2354 Collections.sort(galleries, new Comparator<CmsGalleryFolderEntry>() { 2355 2356 public int compare(CmsGalleryFolderEntry o1, CmsGalleryFolderEntry o2) { 2357 2358 return o1.getSitePath().compareTo(o2.getSitePath()); 2359 } 2360 }); 2361 List<CmsGalleryFolderEntry> galleryTree = new ArrayList<CmsGalleryFolderEntry>(); 2362 for (int i = 0; i < galleries.size(); i++) { 2363 boolean isSubGallery = false; 2364 if (i > 0) { 2365 for (int j = i - 1; j >= 0; j--) { 2366 if (galleries.get(i).getSitePath().startsWith(galleries.get(j).getSitePath())) { 2367 galleries.get(j).addSubGallery(galleries.get(i)); 2368 isSubGallery = true; 2369 break; 2370 } 2371 } 2372 } 2373 if (!isSubGallery) { 2374 galleryTree.add(galleries.get(i)); 2375 } 2376 } 2377 return galleryTree; 2378 } 2379 2380 /** 2381 * Returns the modified list from the current user.<p> 2382 * 2383 * @return the modified list 2384 */ 2385 private LinkedHashMap<CmsUUID, CmsClientSitemapEntry> getModifiedList() { 2386 2387 CmsObject cms = getCmsObject(); 2388 CmsUser user = cms.getRequestContext().getCurrentUser(); 2389 Object obj = user.getAdditionalInfo(ADDINFO_ADE_MODIFIED_LIST); 2390 LinkedHashMap<CmsUUID, CmsClientSitemapEntry> result = new LinkedHashMap<CmsUUID, CmsClientSitemapEntry>(); 2391 if (obj instanceof String) { 2392 try { 2393 JSONArray array = new JSONArray((String)obj); 2394 for (int i = 0; i < array.length(); i++) { 2395 try { 2396 CmsUUID modId = new CmsUUID(array.getString(i)); 2397 CmsResource res = cms.readResource(modId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2398 String sitePath = cms.getSitePath(res); 2399 CmsJspNavElement navEntry = getNavBuilder().getNavigationForResource( 2400 sitePath, 2401 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2402 if (navEntry.isInNavigation()) { 2403 CmsClientSitemapEntry modEntry = toClientEntry(navEntry, false); 2404 result.put(modId, modEntry); 2405 } 2406 } catch (Throwable e) { 2407 // should never happen, catches wrong or no longer existing values 2408 LOG.warn(e.getLocalizedMessage()); 2409 } 2410 } 2411 } catch (Throwable e) { 2412 // should never happen, catches json parsing 2413 LOG.warn(e.getLocalizedMessage()); 2414 } 2415 } 2416 return result; 2417 } 2418 2419 /** 2420 * Returns a navigation builder reference.<p> 2421 * 2422 * @return the navigation builder 2423 */ 2424 private CmsJspNavBuilder getNavBuilder() { 2425 2426 if (m_navBuilder == null) { 2427 m_navBuilder = new CmsJspNavBuilder(getCmsObject()); 2428 } 2429 return m_navBuilder; 2430 } 2431 2432 /** 2433 * Returns the new resource infos.<p> 2434 * 2435 * @param cms the current CMS context 2436 * @param configData the configuration data from which the new resource infos should be read 2437 * @param locale locale used for retrieving descriptions/titles 2438 * 2439 * @return the new resource infos 2440 */ 2441 private List<CmsNewResourceInfo> getNewResourceInfos(CmsObject cms, CmsADEConfigData configData, Locale locale) { 2442 2443 List<CmsNewResourceInfo> result = new ArrayList<CmsNewResourceInfo>(); 2444 for (CmsModelPageConfig modelConfig : configData.getModelPages()) { 2445 try { 2446 CmsNewResourceInfo info = createNewResourceInfo(cms, modelConfig.getResource(), locale); 2447 info.setDefault(modelConfig.isDefault()); 2448 result.add(info); 2449 } catch (CmsException e) { 2450 LOG.debug(e.getLocalizedMessage(), e); 2451 } 2452 } 2453 Collections.sort(result, new Comparator<CmsNewResourceInfo>() { 2454 2455 public int compare(CmsNewResourceInfo a, CmsNewResourceInfo b) { 2456 2457 return ComparisonChain.start().compareTrueFirst(a.isDefault(), b.isDefault()).compare( 2458 a.getNavPos(), 2459 b.getNavPos(), 2460 Ordering.natural().nullsLast()).result(); 2461 } 2462 }); 2463 return result; 2464 } 2465 2466 /** 2467 * Gets the names of all available properties.<p> 2468 * 2469 * @param cms the CMS context 2470 * 2471 * @return the list of all property names 2472 * 2473 * @throws CmsException if something goes wrong 2474 */ 2475 private List<String> getPropertyNames(CmsObject cms) throws CmsException { 2476 2477 List<CmsPropertyDefinition> propDefs = cms.readAllPropertyDefinitions(); 2478 List<String> result = new ArrayList<String>(); 2479 for (CmsPropertyDefinition propDef : propDefs) { 2480 result.add(propDef.getName()); 2481 } 2482 return result; 2483 } 2484 2485 /** 2486 * Gets the resource type info beans for types for which new detail pages can be created.<p> 2487 * 2488 * @param cms the current CMS context 2489 * @param resourceTypeConfigs the resource type configurations 2490 * @param functionReferences the function references 2491 * @param modelResource the model resource 2492 * @param locale the locale used for retrieving descriptions/titles 2493 * 2494 * @return the resource type info beans for types for which new detail pages can be created 2495 */ 2496 private List<CmsNewResourceInfo> getResourceTypeInfos( 2497 CmsObject cms, 2498 List<CmsResourceTypeConfig> resourceTypeConfigs, 2499 List<CmsFunctionReference> functionReferences, 2500 CmsResource modelResource, 2501 Locale locale) { 2502 2503 List<CmsNewResourceInfo> result = new ArrayList<CmsNewResourceInfo>(); 2504 CmsNewResourceInfo defaultPageInfo; 2505 if (modelResource != null) { 2506 defaultPageInfo = new CmsNewResourceInfo( 2507 modelResource.getTypeId(), 2508 CmsADEManager.DEFAULT_DETAILPAGE_TYPE, 2509 "Default", 2510 "The default detail page will be used to display detail contents or functions.", 2511 modelResource.getStructureId(), 2512 false, 2513 "The default detail page will be used to display detail contents or functions."); 2514 2515 } else { 2516 defaultPageInfo = new CmsNewResourceInfo( 2517 CmsResourceTypeXmlContainerPage.getContainerPageTypeIdSafely(), 2518 CmsADEManager.DEFAULT_DETAILPAGE_TYPE, 2519 "Default", 2520 "The default detail page will be used to display detail contents or functions.", 2521 null, 2522 false, 2523 "The default detail page will be used to display detail contents or functions."); 2524 } 2525 2526 defaultPageInfo.setBigIconClasses( 2527 CmsIconUtil.getIconClasses(CmsResourceTypeXmlContainerPage.getStaticTypeName(), null, false)); 2528 result.add(defaultPageInfo); 2529 for (CmsResourceTypeConfig typeConfig : resourceTypeConfigs) { 2530 if (typeConfig.isDetailPagesDisabled()) { 2531 continue; 2532 } 2533 String typeName = typeConfig.getTypeName(); 2534 try { 2535 I_CmsResourceType resourceType = OpenCms.getResourceManager().getResourceType(typeName); 2536 result.add(createResourceTypeInfo(resourceType, modelResource)); 2537 } catch (CmsLoaderException e) { 2538 LOG.error(e.getLocalizedMessage(), e); 2539 } 2540 } 2541 for (CmsFunctionReference functionRef : functionReferences) { 2542 try { 2543 CmsResource functionRes = cms.readResource(functionRef.getStructureId()); 2544 String description = cms.readPropertyObject( 2545 functionRes, 2546 CmsPropertyDefinition.PROPERTY_DESCRIPTION, 2547 false).getValue(); 2548 String subtitle = description; 2549 try { 2550 CmsGallerySearchResult searchResult = CmsGallerySearch.searchById( 2551 cms, 2552 functionRef.getStructureId(), 2553 getWorkplaceLocale()); 2554 subtitle = searchResult.getDescription(); 2555 } catch (CmsException e) { 2556 LOG.warn(e.getLocalizedMessage(), e); 2557 } 2558 2559 CmsNewResourceInfo info = new CmsNewResourceInfo( 2560 modelResource.getTypeId(), 2561 CmsDetailPageInfo.FUNCTION_PREFIX + functionRef.getName(), 2562 functionRef.getName(), 2563 description, 2564 modelResource.getStructureId(), 2565 false, 2566 subtitle); 2567 info.setCreateParameter(functionRef.getStructureId().toString()); 2568 info.setIsFunction(true); 2569 info.setBigIconClasses( 2570 CmsIconUtil.getIconClasses(CmsXmlDynamicFunctionHandler.TYPE_FUNCTION, null, false)); 2571 result.add(info); 2572 } catch (CmsVfsResourceNotFoundException e) { 2573 LOG.warn(e.getLocalizedMessage(), e); 2574 } catch (CmsException e) { 2575 LOG.error(e.getLocalizedMessage(), e); 2576 } 2577 } 2578 return result; 2579 } 2580 2581 /** 2582 * Reeds the site root entry.<p> 2583 * 2584 * @param rootPath the root path of the sitemap root 2585 * @param targetPath the target path to open 2586 * 2587 * @return the site root entry 2588 * 2589 * @throws CmsSecurityException in case of insufficient permissions 2590 * @throws CmsException if something goes wrong 2591 */ 2592 private CmsClientSitemapEntry getRootEntry(String rootPath, String targetPath) 2593 throws CmsSecurityException, CmsException { 2594 2595 String sitePath = "/"; 2596 if ((rootPath != null)) { 2597 sitePath = getCmsObject().getRequestContext().removeSiteRoot(rootPath); 2598 } 2599 CmsJspNavElement navElement = getNavBuilder().getNavigationForResource( 2600 sitePath, 2601 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2602 CmsClientSitemapEntry result = toClientEntry(navElement, true); 2603 if (result != null) { 2604 result.setPosition(0); 2605 result.setChildrenLoadedInitially(true); 2606 result.setSubEntries(getChildren(sitePath, 2, targetPath), null); 2607 } 2608 return result; 2609 } 2610 2611 /** 2612 * Returns the sitemap info for the given base path.<p> 2613 * 2614 * @param basePath the base path 2615 * 2616 * @return the sitemap info 2617 * 2618 * @throws CmsException if something goes wrong reading the resources 2619 */ 2620 private CmsSitemapInfo getSitemapInfo(String basePath) throws CmsException { 2621 2622 CmsObject cms = getCmsObject(); 2623 CmsResource baseFolder = null; 2624 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(basePath)) { 2625 baseFolder = cms.readResource( 2626 cms.getRequestContext().removeSiteRoot(basePath), 2627 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2628 } else { 2629 // in case of an empty base path, use base folder of the current site 2630 basePath = "/"; 2631 baseFolder = cms.readResource("/"); 2632 } 2633 CmsResource defaultFile = cms.readDefaultFile(baseFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2634 String title = cms.readPropertyObject(baseFolder, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue(); 2635 if (CmsStringUtil.isEmptyOrWhitespaceOnly(title) && (defaultFile != null)) { 2636 title = cms.readPropertyObject(defaultFile, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue(); 2637 } 2638 String description = cms.readPropertyObject( 2639 baseFolder, 2640 CmsPropertyDefinition.PROPERTY_DESCRIPTION, 2641 false).getValue(); 2642 if (CmsStringUtil.isEmptyOrWhitespaceOnly(description) && (defaultFile != null)) { 2643 description = cms.readPropertyObject( 2644 defaultFile, 2645 CmsPropertyDefinition.PROPERTY_DESCRIPTION, 2646 false).getValue(); 2647 } 2648 return new CmsSitemapInfo( 2649 cms.getRequestContext().getCurrentProject().getName(), 2650 description, 2651 OpenCms.getLocaleManager().getDefaultLocale(cms, baseFolder).toString(), 2652 OpenCms.getSiteManager().getCurrentSite(cms).getUrl() 2653 + OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, basePath), 2654 title); 2655 } 2656 2657 /** 2658 * Gets the default type id for subsitemap folders.<p> 2659 * 2660 * @return the default type id for subsitemap folders 2661 * 2662 * @throws CmsRpcException in case of an error 2663 */ 2664 @SuppressWarnings("deprecation") 2665 private int getSubsitemapType() throws CmsRpcException { 2666 2667 try { 2668 return OpenCms.getResourceManager().getResourceType( 2669 CmsResourceTypeFolderSubSitemap.TYPE_SUBSITEMAP).getTypeId(); 2670 } catch (CmsLoaderException e) { 2671 error(e); 2672 } 2673 return CmsResourceTypeUnknownFolder.getStaticTypeId(); 2674 } 2675 2676 /** 2677 * Returns the workplace locale for the current user.<p> 2678 * 2679 * @return the workplace locale 2680 */ 2681 private Locale getWorkplaceLocale() { 2682 2683 Locale result = OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject()); 2684 if (result == null) { 2685 result = CmsLocaleManager.getDefaultLocale(); 2686 } 2687 if (result == null) { 2688 result = Locale.getDefault(); 2689 } 2690 return result; 2691 } 2692 2693 /** 2694 * Checks whether the sitemap change has default file changes.<p> 2695 * 2696 * @param change a sitemap change 2697 * @return true if the change would change the default file 2698 */ 2699 private boolean hasDefaultFileChanges(CmsSitemapChange change) { 2700 2701 return (change.getDefaultFileId() != null) && !change.isNew(); 2702 } 2703 2704 /** 2705 * Checks whether the sitemap change has changes for the sitemap entry resource.<p> 2706 * 2707 * @param change the sitemap change 2708 * @return true if the change would change the original sitemap entry resource 2709 */ 2710 private boolean hasOwnChanges(CmsSitemapChange change) { 2711 2712 return !change.isNew(); 2713 } 2714 2715 /** 2716 * Checks whether a resource is a default file of a folder.<p> 2717 * 2718 * @param resource the resource to check 2719 * 2720 * @return true if the resource is the default file of a folder 2721 * 2722 * @throws CmsException if something goes wrong 2723 */ 2724 private boolean isDefaultFile(CmsResource resource) throws CmsException { 2725 2726 CmsObject cms = getCmsObject(); 2727 if (resource.isFolder()) { 2728 return false; 2729 } 2730 2731 CmsResource parent = cms.readResource( 2732 CmsResource.getParentFolder(cms.getSitePath(resource)), 2733 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2734 CmsResource defaultFile = cms.readDefaultFile(parent, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2735 return resource.equals(defaultFile); 2736 } 2737 2738 /** 2739 * Checks if the toolbar should be displayed.<p> 2740 * 2741 * @param request the current request to get the default locale from 2742 * 2743 * @return <code>true</code> if the toolbar should be displayed 2744 */ 2745 private boolean isDisplayToolbar(HttpServletRequest request) { 2746 2747 // display the toolbar by default 2748 boolean displayToolbar = true; 2749 if (CmsHistoryResourceHandler.isHistoryRequest(request)) { 2750 // we do not want to display the toolbar in case of an historical request 2751 displayToolbar = false; 2752 } 2753 return displayToolbar; 2754 } 2755 2756 /** 2757 * Returns if the given path is located below one of the given sub site paths.<p> 2758 * 2759 * @param subSitePaths the sub site root paths 2760 * @param path the root path to check 2761 * 2762 * @return <code>true</code> if the given path is located below one of the given sub site paths 2763 */ 2764 private boolean isInSubsite(List<String> subSitePaths, String path) { 2765 2766 boolean result = false; 2767 for (String subSite : subSitePaths) { 2768 if (path.startsWith(subSite)) { 2769 result = true; 2770 break; 2771 } 2772 } 2773 return result; 2774 } 2775 2776 /** 2777 * Returns if the given type id matches the xml-redirect resource type.<p> 2778 * 2779 * @param typeId the resource type id 2780 * 2781 * @return <code>true</code> if the given type id matches the xml-redirect resource type 2782 */ 2783 @SuppressWarnings("deprecation") 2784 private boolean isRedirectType(int typeId) { 2785 2786 try { 2787 return typeId == OpenCms.getResourceManager().getResourceType(RECOURCE_TYPE_NAME_REDIRECT).getTypeId(); 2788 } catch (Exception e) { 2789 return false; 2790 } 2791 } 2792 2793 /** 2794 * Returns if the given nav-element resembles a sub-sitemap entry-point.<p> 2795 * 2796 * @param navElement the nav-element 2797 * 2798 * @return <code>true</code> if the given nav-element resembles a sub-sitemap entry-point.<p> 2799 */ 2800 private boolean isSubSitemap(CmsJspNavElement navElement) { 2801 2802 return CmsResourceTypeFolderSubSitemap.isSubSitemap(navElement.getResource()); 2803 } 2804 2805 /** 2806 * Checks if the given open path is valid.<p> 2807 * 2808 * @param cms the cms context 2809 * @param openPath the open path 2810 * 2811 * @return <code>true</code> if the given open path is valid 2812 */ 2813 private boolean isValidOpenPath(CmsObject cms, String openPath) { 2814 2815 if (CmsStringUtil.isEmptyOrWhitespaceOnly(openPath)) { 2816 return false; 2817 } 2818 if (!cms.existsResource(openPath)) { 2819 // in case of a detail-page check the parent folder 2820 String parent = CmsResource.getParentFolder(openPath); 2821 if (CmsStringUtil.isEmptyOrWhitespaceOnly(parent) || !cms.existsResource(parent)) { 2822 return false; 2823 } 2824 } 2825 return true; 2826 } 2827 2828 /** 2829 * Returns if the given return code is valid.<p> 2830 * 2831 * @param returnCode the return code to check 2832 * 2833 * @return <code>true</code> if the return code is valid 2834 */ 2835 private boolean isValidReturnCode(String returnCode) { 2836 2837 if (CmsStringUtil.isEmptyOrWhitespaceOnly(returnCode)) { 2838 return false; 2839 } 2840 int pos = returnCode.indexOf(":"); 2841 if (pos > 0) { 2842 return CmsUUID.isValidUUID(returnCode.substring(0, pos)) 2843 && CmsUUID.isValidUUID(returnCode.substring(pos + 1)); 2844 } else { 2845 return CmsUUID.isValidUUID(returnCode); 2846 } 2847 } 2848 2849 /** 2850 * Applys the given changes to the entry.<p> 2851 * 2852 * @param change the change to apply 2853 * 2854 * @throws CmsException if something goes wrong 2855 */ 2856 private void modifyEntry(CmsSitemapChange change) throws CmsException { 2857 2858 CmsObject cms = getCmsObject(); 2859 CmsResource entryPage = null; 2860 CmsResource entryFolder = null; 2861 2862 CmsResource ownRes = null; 2863 CmsResource defaultFileRes = null; 2864 try { 2865 // lock all resources necessary first to avoid doing changes only half way through 2866 2867 if (hasOwnChanges(change)) { 2868 ownRes = cms.readResource(change.getEntryId(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2869 ensureLock(ownRes); 2870 } 2871 2872 if (hasDefaultFileChanges(change)) { 2873 defaultFileRes = cms.readResource(change.getDefaultFileId(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2874 ensureLock(defaultFileRes); 2875 } 2876 2877 if ((ownRes != null) && ownRes.isFolder()) { 2878 entryFolder = ownRes; 2879 } 2880 2881 if ((ownRes != null) && ownRes.isFile()) { 2882 entryPage = ownRes; 2883 } 2884 2885 if (defaultFileRes != null) { 2886 entryPage = defaultFileRes; 2887 } 2888 2889 if (change.isLeafType()) { 2890 entryFolder = entryPage; 2891 } 2892 2893 updateProperties(cms, ownRes, defaultFileRes, change.getPropertyChanges()); 2894 if (change.hasChangedPosition()) { 2895 updateNavPos(ownRes, change); 2896 } 2897 2898 if (entryFolder != null) { 2899 if (change.hasNewParent() || change.hasChangedName()) { 2900 String destinationPath; 2901 if (change.hasNewParent()) { 2902 CmsResource futureParent = cms.readResource( 2903 change.getParentId(), 2904 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2905 destinationPath = CmsStringUtil.joinPaths(cms.getSitePath(futureParent), change.getName()); 2906 } else { 2907 destinationPath = CmsStringUtil.joinPaths( 2908 CmsResource.getParentFolder(cms.getSitePath(entryFolder)), 2909 change.getName()); 2910 } 2911 if (change.isLeafType() && destinationPath.endsWith("/")) { 2912 destinationPath = destinationPath.substring(0, destinationPath.length() - 1); 2913 } 2914 // only if the site-path has really changed 2915 if (!cms.getSitePath(entryFolder).equals(destinationPath)) { 2916 cms.moveResource(cms.getSitePath(entryFolder), destinationPath); 2917 } 2918 entryFolder = cms.readResource( 2919 entryFolder.getStructureId(), 2920 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2921 } 2922 } 2923 } finally { 2924 if (entryPage != null) { 2925 tryUnlock(entryPage); 2926 } 2927 if (entryFolder != null) { 2928 tryUnlock(entryFolder); 2929 } 2930 } 2931 } 2932 2933 /** 2934 * Reads the gallery folder properties.<p> 2935 * 2936 * @param folder the folder resource 2937 * @param typeName the resource type name 2938 * 2939 * @return the folder entry data 2940 * 2941 * @throws CmsException if the folder properties can not be read 2942 */ 2943 private CmsGalleryFolderEntry readGalleryFolderEntry(CmsResource folder, String typeName) throws CmsException { 2944 2945 CmsObject cms = getCmsObject(); 2946 CmsGalleryFolderEntry folderEntry = new CmsGalleryFolderEntry(); 2947 folderEntry.setResourceType(typeName); 2948 folderEntry.setSitePath(cms.getSitePath(folder)); 2949 folderEntry.setStructureId(folder.getStructureId()); 2950 folderEntry.setOwnProperties(getClientProperties(cms, folder, false)); 2951 folderEntry.setIconClasses(CmsIconUtil.getIconClasses(typeName, null, false)); 2952 return folderEntry; 2953 } 2954 2955 /** 2956 * Helper method for removing all locales except one from a container page.<p> 2957 * 2958 * @param page the container page to proces 2959 * @param localeToKeep the locale which should be kept 2960 * 2961 * @throws CmsXmlException if something goes wrong 2962 */ 2963 private void removeAllLocalesExcept(CmsXmlContainerPage page, Locale localeToKeep) throws CmsXmlException { 2964 2965 List<Locale> locales = page.getLocales(); 2966 for (Locale locale : locales) { 2967 if (!locale.equals(localeToKeep)) { 2968 page.removeLocale(locale); 2969 } 2970 } 2971 } 2972 2973 /** 2974 * Applys the given remove change.<p> 2975 * 2976 * @param change the change to apply 2977 * 2978 * @return the changed client sitemap entry or <code>null</code> 2979 * 2980 * @throws CmsException if something goes wrong 2981 */ 2982 private CmsSitemapChange removeEntryFromNavigation(CmsSitemapChange change) throws CmsException { 2983 2984 CmsObject cms = getCmsObject(); 2985 CmsResource entryFolder = cms.readResource(change.getEntryId(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 2986 ensureLock(entryFolder); 2987 List<CmsProperty> properties = new ArrayList<CmsProperty>(); 2988 properties.add( 2989 new CmsProperty( 2990 CmsPropertyDefinition.PROPERTY_NAVTEXT, 2991 CmsProperty.DELETE_VALUE, 2992 CmsProperty.DELETE_VALUE)); 2993 properties.add( 2994 new CmsProperty(CmsPropertyDefinition.PROPERTY_NAVPOS, CmsProperty.DELETE_VALUE, CmsProperty.DELETE_VALUE)); 2995 cms.writePropertyObjects(cms.getSitePath(entryFolder), properties); 2996 tryUnlock(entryFolder); 2997 return change; 2998 } 2999 3000 /** 3001 * Saves the detail page information of a sitemap to the sitemap's configuration file.<p> 3002 * 3003 * @param detailPages saves the detailpage configuration 3004 * @param resource the configuration file resource 3005 * @param newId the structure id to use for new detail page entries 3006 * @param updateEntry the new detail page entry 3007 * 3008 * @throws CmsException if something goes wrong 3009 */ 3010 private void saveDetailPages( 3011 List<CmsDetailPageInfo> detailPages, 3012 CmsResource resource, 3013 CmsUUID newId, 3014 CmsClientSitemapEntry updateEntry) 3015 throws CmsException { 3016 3017 CmsObject cms = getCmsObject(); 3018 if (updateEntry != null) { 3019 for (CmsDetailPageInfo info : detailPages) { 3020 if (info.getId() == null) { 3021 updateEntry.setDetailpageTypeName(info.getType()); 3022 break; 3023 } 3024 } 3025 } 3026 CmsDetailPageConfigurationWriter writer = new CmsDetailPageConfigurationWriter(cms, resource); 3027 writer.updateAndSave(detailPages, newId); 3028 } 3029 3030 /** 3031 * Saves the given clipboard data to the session.<p> 3032 * 3033 * @param clipboardData the clipboard data to save 3034 * 3035 * @throws CmsException if something goes wrong writing the user 3036 */ 3037 private void setClipboardData(CmsSitemapClipboardData clipboardData) throws CmsException { 3038 3039 CmsObject cms = getCmsObject(); 3040 CmsUser user = cms.getRequestContext().getCurrentUser(); 3041 if (clipboardData != null) { 3042 JSONArray modified = new JSONArray(); 3043 if (clipboardData.getModifications() != null) { 3044 for (CmsUUID id : clipboardData.getModifications().keySet()) { 3045 if (id != null) { 3046 modified.put(id.toString()); 3047 } 3048 } 3049 } 3050 user.setAdditionalInfo(ADDINFO_ADE_MODIFIED_LIST, modified.toString()); 3051 JSONArray deleted = new JSONArray(); 3052 if (clipboardData.getDeletions() != null) { 3053 for (CmsUUID id : clipboardData.getDeletions().keySet()) { 3054 if (id != null) { 3055 deleted.put(id.toString()); 3056 } 3057 } 3058 } 3059 user.setAdditionalInfo(ADDINFO_ADE_DELETED_LIST, deleted.toString()); 3060 cms.writeUser(user); 3061 } 3062 } 3063 3064 /** 3065 * Determines if the title property of the default file should be changed.<p> 3066 * 3067 * @param properties the current default file properties 3068 * @param folderNavtext the 'NavText' property of the folder 3069 * 3070 * @return <code>true</code> if the title property should be changed 3071 */ 3072 private boolean shouldChangeDefaultFileTitle(Map<String, CmsProperty> properties, CmsProperty folderNavtext) { 3073 3074 return (properties == null) 3075 || (properties.get(CmsPropertyDefinition.PROPERTY_TITLE) == null) 3076 || (properties.get(CmsPropertyDefinition.PROPERTY_TITLE).getValue() == null) 3077 || ((folderNavtext != null) 3078 && properties.get(CmsPropertyDefinition.PROPERTY_TITLE).getValue().equals(folderNavtext.getValue())); 3079 } 3080 3081 /** 3082 * Determines if the title property should be changed in case of a 'NavText' change.<p> 3083 * 3084 * @param properties the current resource properties 3085 * 3086 * @return <code>true</code> if the title property should be changed in case of a 'NavText' change 3087 */ 3088 private boolean shouldChangeTitle(Map<String, CmsProperty> properties) { 3089 3090 return (properties == null) 3091 || (properties.get(CmsPropertyDefinition.PROPERTY_TITLE) == null) 3092 || (properties.get(CmsPropertyDefinition.PROPERTY_TITLE).getValue() == null) 3093 || ((properties.get(CmsPropertyDefinition.PROPERTY_NAVTEXT) != null) 3094 && properties.get(CmsPropertyDefinition.PROPERTY_TITLE).getValue().equals( 3095 properties.get(CmsPropertyDefinition.PROPERTY_NAVTEXT).getValue())); 3096 } 3097 3098 /** 3099 * Converts a jsp navigation element into a client sitemap entry.<p> 3100 * 3101 * @param navElement the jsp navigation element 3102 * @param isRoot true if the entry is a root entry 3103 * 3104 * @return the client sitemap entry 3105 * 3106 * @throws CmsException if something goes wrong 3107 */ 3108 private CmsClientSitemapEntry toClientEntry(CmsJspNavElement navElement, boolean isRoot) throws CmsException { 3109 3110 CmsResource entryPage = null; 3111 CmsObject cms = getCmsObject(); 3112 CmsClientSitemapEntry clientEntry = new CmsClientSitemapEntry(); 3113 CmsResource entryFolder = null; 3114 3115 CmsResource ownResource = navElement.getResource(); 3116 clientEntry.setResourceState(ownResource.getState()); 3117 CmsResource defaultFileResource = null; 3118 if (ownResource.isFolder() && !navElement.isNavigationLevel()) { 3119 defaultFileResource = cms.readDefaultFile(ownResource, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 3120 } 3121 3122 Map<String, CmsClientProperty> ownProps = getClientProperties(cms, ownResource, false); 3123 3124 Map<String, CmsClientProperty> defaultFileProps = null; 3125 if (defaultFileResource != null) { 3126 defaultFileProps = getClientProperties(cms, defaultFileResource, false); 3127 clientEntry.setDefaultFileId(defaultFileResource.getStructureId()); 3128 clientEntry.setDefaultFileType( 3129 OpenCms.getResourceManager().getResourceType(defaultFileResource.getTypeId()).getTypeName()); 3130 clientEntry.setDefaultFileReleased(defaultFileResource.isReleasedAndNotExpired(System.currentTimeMillis())); 3131 } else { 3132 defaultFileProps = new HashMap<String, CmsClientProperty>(); 3133 } 3134 boolean isDefault = isDefaultFile(ownResource); 3135 clientEntry.setId(ownResource.getStructureId()); 3136 clientEntry.setResourceTypeId(ownResource.getTypeId()); 3137 clientEntry.setFolderDefaultPage(isDefault); 3138 if (navElement.getResource().isFolder()) { 3139 entryFolder = navElement.getResource(); 3140 entryPage = defaultFileResource; 3141 clientEntry.setName(entryFolder.getName()); 3142 if (entryPage == null) { 3143 entryPage = entryFolder; 3144 } 3145 if (!isRoot && isSubSitemap(navElement)) { 3146 clientEntry.setEntryType(EntryType.subSitemap); 3147 clientEntry.setDefaultFileType(null); 3148 } else if (navElement.isNavigationLevel()) { 3149 clientEntry.setEntryType(EntryType.navigationLevel); 3150 } 3151 CmsLock folderLock = cms.getLock(entryFolder); 3152 clientEntry.setHasForeignFolderLock( 3153 !folderLock.isUnlocked() && !folderLock.isOwnedBy(cms.getRequestContext().getCurrentUser())); 3154 if (!cms.getRequestContext().getCurrentProject().isOnlineProject()) { 3155 List<CmsResource> blockingChildren = cms.getBlockingLockedResources(entryFolder); 3156 clientEntry.setBlockingLockedChildren((blockingChildren != null) && !blockingChildren.isEmpty()); 3157 } 3158 } else { 3159 entryPage = navElement.getResource(); 3160 clientEntry.setName(entryPage.getName()); 3161 if (isRedirectType(entryPage.getTypeId())) { 3162 clientEntry.setEntryType(EntryType.redirect); 3163 CmsFile file = getCmsObject().readFile(entryPage); 3164 I_CmsXmlDocument content = CmsXmlContentFactory.unmarshal(getCmsObject(), file); 3165 I_CmsXmlContentValue linkValue = content.getValue( 3166 REDIRECT_LINK_TARGET_XPATH, 3167 getCmsObject().getRequestContext().getLocale()); 3168 String link = linkValue != null 3169 ? linkValue.getStringValue(getCmsObject()) 3170 : Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_REDIRECT_SUB_LEVEL_0); 3171 clientEntry.setRedirectTarget(link); 3172 } else { 3173 clientEntry.setEntryType(EntryType.leaf); 3174 } 3175 } 3176 if (entryPage.isFile()) { 3177 List<CmsAlias> aliases = OpenCms.getAliasManager().getAliasesForStructureId( 3178 getCmsObject(), 3179 entryPage.getStructureId()); 3180 if (!aliases.isEmpty()) { 3181 List<String> aliasList = new ArrayList<String>(); 3182 for (CmsAlias alias : aliases) { 3183 String aliasPath = alias.getAliasPath(); 3184 aliasList.add(aliasPath); 3185 } 3186 clientEntry.setAliases(aliasList); 3187 } 3188 } 3189 long dateExpired = navElement.getResource().getDateExpired(); 3190 if (dateExpired != CmsResource.DATE_EXPIRED_DEFAULT) { 3191 clientEntry.setDateExpired( 3192 CmsDateUtil.getDate(new Date(dateExpired), DateFormat.SHORT, getWorkplaceLocale())); 3193 } 3194 long dateReleased = navElement.getResource().getDateReleased(); 3195 if (dateReleased != CmsResource.DATE_RELEASED_DEFAULT) { 3196 clientEntry.setDateReleased( 3197 CmsDateUtil.getDate(new Date(dateReleased), DateFormat.SHORT, getWorkplaceLocale())); 3198 } 3199 clientEntry.setResleasedAndNotExpired( 3200 navElement.getResource().isReleasedAndNotExpired(System.currentTimeMillis())); 3201 String path = cms.getSitePath(entryPage); 3202 clientEntry.setVfsPath(path); 3203 clientEntry.setOwnProperties(ownProps); 3204 clientEntry.setDefaultFileProperties(defaultFileProps); 3205 clientEntry.setSitePath(entryFolder != null ? cms.getSitePath(entryFolder) : path); 3206 clientEntry.setLock(generateClientLock(entryPage)); 3207 clientEntry.setInNavigation(isRoot || navElement.isInNavigation()); 3208 String type = OpenCms.getResourceManager().getResourceType(ownResource).getTypeName(); 3209 clientEntry.setResourceTypeName(type); 3210 clientEntry.setVfsModeIcon(CmsIconUtil.getIconClasses(type, ownResource.getName(), false)); 3211 3212 if (!clientEntry.isSubSitemapType()) { 3213 if (clientEntry.isNavigationLevelType()) { 3214 clientEntry.setNavModeIcon(CmsIconUtil.ICON_NAV_LEVEL_BIG); 3215 } else if (defaultFileResource != null) { 3216 clientEntry.setNavModeIcon( 3217 CmsIconUtil.getIconClasses(clientEntry.getDefaultFileType(), defaultFileResource.getName(), false)); 3218 } 3219 } 3220 clientEntry.setPermissionInfo(OpenCms.getADEManager().getPermissionInfo(cms, ownResource, null)); 3221 return clientEntry; 3222 } 3223 3224 /** 3225 * Un-deletes a resource according to the change data.<p> 3226 * 3227 * @param change the change data 3228 * 3229 * @return the changed entry or <code>null</code> 3230 * 3231 * @throws CmsException if something goes wrong 3232 */ 3233 private CmsSitemapChange undelete(CmsSitemapChange change) throws CmsException { 3234 3235 CmsObject cms = getCmsObject(); 3236 CmsResource deleted = cms.readResource(change.getEntryId(), CmsResourceFilter.ALL); 3237 if (deleted.getState().isDeleted()) { 3238 ensureLock(deleted); 3239 cms.undeleteResource(getCmsObject().getSitePath(deleted), true); 3240 tryUnlock(deleted); 3241 } 3242 String parentPath = CmsResource.getParentFolder(cms.getSitePath(deleted)); 3243 CmsJspNavElement navElement = getNavBuilder().getNavigationForResource( 3244 parentPath, 3245 CmsResourceFilter.ONLY_VISIBLE_NO_DELETED); 3246 CmsClientSitemapEntry entry = toClientEntry(navElement, navElement.isInNavigation()); 3247 entry.setSubEntries(getChildren(parentPath, 2, null), null); 3248 change.setUpdatedEntry(entry); 3249 change.setParentId(cms.readParentFolder(deleted.getStructureId()).getStructureId()); 3250 return change; 3251 } 3252 3253 /** 3254 * Updates the navigation position for a resource.<p> 3255 * 3256 * @param res the resource for which to update the navigation position 3257 * @param change the sitemap change 3258 * 3259 * @throws CmsException if something goes wrong 3260 */ 3261 private void updateNavPos(CmsResource res, CmsSitemapChange change) throws CmsException { 3262 3263 if (change.hasChangedPosition()) { 3264 applyNavigationChanges(change, res); 3265 } 3266 } 3267 3268 /** 3269 * Updates properties for a resource and possibly its detail page.<p> 3270 * 3271 * @param cms the CMS context 3272 * @param ownRes the resource 3273 * @param defaultFileRes the default file resource (possibly null) 3274 * @param propertyModifications the property modifications 3275 * 3276 * @throws CmsException if something goes wrong 3277 */ 3278 private void updateProperties( 3279 CmsObject cms, 3280 CmsResource ownRes, 3281 CmsResource defaultFileRes, 3282 List<CmsPropertyModification> propertyModifications) 3283 throws CmsException { 3284 3285 Map<String, CmsProperty> ownProps = getPropertiesByName(cms.readPropertyObjects(ownRes, false)); 3286 // determine if the title property should be changed in case of a 'NavText' change 3287 boolean changeOwnTitle = shouldChangeTitle(ownProps); 3288 3289 boolean changeDefaultFileTitle = false; 3290 Map<String, CmsProperty> defaultFileProps = Maps.newHashMap(); 3291 if (defaultFileRes != null) { 3292 defaultFileProps = getPropertiesByName(cms.readPropertyObjects(defaultFileRes, false)); 3293 // determine if the title property of the default file should be changed 3294 changeDefaultFileTitle = shouldChangeDefaultFileTitle( 3295 defaultFileProps, 3296 ownProps.get(CmsPropertyDefinition.PROPERTY_NAVTEXT)); 3297 } 3298 String hasNavTextChange = null; 3299 List<CmsProperty> ownPropertyChanges = new ArrayList<CmsProperty>(); 3300 List<CmsProperty> defaultFilePropertyChanges = new ArrayList<CmsProperty>(); 3301 for (CmsPropertyModification propMod : propertyModifications) { 3302 CmsProperty propToModify = null; 3303 if (ownRes.getStructureId().equals(propMod.getId())) { 3304 3305 if (CmsPropertyDefinition.PROPERTY_NAVTEXT.equals(propMod.getName())) { 3306 hasNavTextChange = propMod.getValue(); 3307 } else if (CmsPropertyDefinition.PROPERTY_TITLE.equals(propMod.getName())) { 3308 changeOwnTitle = false; 3309 } 3310 propToModify = ownProps.get(propMod.getName()); 3311 if (propToModify == null) { 3312 propToModify = new CmsProperty(propMod.getName(), null, null); 3313 } 3314 ownPropertyChanges.add(propToModify); 3315 } else { 3316 if (CmsPropertyDefinition.PROPERTY_TITLE.equals(propMod.getName())) { 3317 changeDefaultFileTitle = false; 3318 } 3319 propToModify = defaultFileProps.get(propMod.getName()); 3320 if (propToModify == null) { 3321 propToModify = new CmsProperty(propMod.getName(), null, null); 3322 } 3323 defaultFilePropertyChanges.add(propToModify); 3324 } 3325 3326 String newValue = propMod.getValue(); 3327 if (newValue == null) { 3328 newValue = ""; 3329 } 3330 if (propMod.isStructureValue()) { 3331 propToModify.setStructureValue(newValue); 3332 } else { 3333 propToModify.setResourceValue(newValue); 3334 } 3335 } 3336 if (hasNavTextChange != null) { 3337 if (changeOwnTitle) { 3338 CmsProperty titleProp = ownProps.get(CmsPropertyDefinition.PROPERTY_TITLE); 3339 if (titleProp == null) { 3340 titleProp = new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, null, null); 3341 } 3342 titleProp.setStructureValue(hasNavTextChange); 3343 ownPropertyChanges.add(titleProp); 3344 } 3345 if (changeDefaultFileTitle) { 3346 CmsProperty titleProp = defaultFileProps.get(CmsPropertyDefinition.PROPERTY_TITLE); 3347 if (titleProp == null) { 3348 titleProp = new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, null, null); 3349 } 3350 titleProp.setStructureValue(hasNavTextChange); 3351 defaultFilePropertyChanges.add(titleProp); 3352 } 3353 } 3354 if (!ownPropertyChanges.isEmpty()) { 3355 cms.writePropertyObjects(ownRes, ownPropertyChanges); 3356 } 3357 if (!defaultFilePropertyChanges.isEmpty() && (defaultFileRes != null)) { 3358 cms.writePropertyObjects(defaultFileRes, defaultFilePropertyChanges); 3359 } 3360 } 3361 3362}