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