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