001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.db; 029 030import org.opencms.ade.publish.CmsTooManyPublishResourcesException; 031import org.opencms.configuration.CmsConfigurationManager; 032import org.opencms.configuration.CmsParameterConfiguration; 033import org.opencms.configuration.CmsSystemConfiguration; 034import org.opencms.db.generic.CmsPublishHistoryCleanupFilter; 035import org.opencms.db.generic.CmsUserDriver; 036import org.opencms.db.log.CmsLogEntry; 037import org.opencms.db.log.CmsLogEntryType; 038import org.opencms.db.log.CmsLogFilter; 039import org.opencms.db.timing.CmsDefaultProfilingHandler; 040import org.opencms.db.timing.CmsProfilingInvocationHandler; 041import org.opencms.db.urlname.CmsUrlNameMappingEntry; 042import org.opencms.db.urlname.CmsUrlNameMappingFilter; 043import org.opencms.db.userpublishlist.A_CmsLogPublishListConverter; 044import org.opencms.db.userpublishlist.CmsLogPublishListConverterAllUsers; 045import org.opencms.db.userpublishlist.CmsLogPublishListConverterCurrentUser; 046import org.opencms.file.CmsDataAccessException; 047import org.opencms.file.CmsFile; 048import org.opencms.file.CmsFolder; 049import org.opencms.file.CmsGroup; 050import org.opencms.file.CmsObject; 051import org.opencms.file.CmsProject; 052import org.opencms.file.CmsProperty; 053import org.opencms.file.CmsPropertyDefinition; 054import org.opencms.file.CmsRequestContext; 055import org.opencms.file.CmsResource; 056import org.opencms.file.CmsResourceFilter; 057import org.opencms.file.CmsUser; 058import org.opencms.file.CmsUserSearchParameters; 059import org.opencms.file.CmsVfsException; 060import org.opencms.file.CmsVfsResourceAlreadyExistsException; 061import org.opencms.file.CmsVfsResourceNotFoundException; 062import org.opencms.file.I_CmsResource; 063import org.opencms.file.history.CmsHistoryFile; 064import org.opencms.file.history.CmsHistoryFolder; 065import org.opencms.file.history.CmsHistoryPrincipal; 066import org.opencms.file.history.CmsHistoryProject; 067import org.opencms.file.history.I_CmsHistoryResource; 068import org.opencms.file.types.CmsResourceTypeFolder; 069import org.opencms.file.types.CmsResourceTypeJsp; 070import org.opencms.file.types.I_CmsResourceType; 071import org.opencms.flex.CmsFlexRequestContextInfo; 072import org.opencms.gwt.shared.alias.CmsAliasImportResult; 073import org.opencms.gwt.shared.alias.CmsAliasImportStatus; 074import org.opencms.gwt.shared.alias.CmsAliasMode; 075import org.opencms.i18n.CmsLocaleManager; 076import org.opencms.i18n.CmsMessageContainer; 077import org.opencms.jsp.CmsJspNavBuilder; 078import org.opencms.lock.CmsLock; 079import org.opencms.lock.CmsLockException; 080import org.opencms.lock.CmsLockFilter; 081import org.opencms.lock.CmsLockManager; 082import org.opencms.lock.CmsLockType; 083import org.opencms.main.CmsEvent; 084import org.opencms.main.CmsException; 085import org.opencms.main.CmsIllegalArgumentException; 086import org.opencms.main.CmsIllegalStateException; 087import org.opencms.main.CmsInitException; 088import org.opencms.main.CmsLog; 089import org.opencms.main.CmsMultiException; 090import org.opencms.main.I_CmsEventListener; 091import org.opencms.main.OpenCms; 092import org.opencms.module.CmsModule; 093import org.opencms.monitor.CmsMemoryMonitor; 094import org.opencms.monitor.CmsMemoryMonitor.CacheType; 095import org.opencms.publish.CmsPublishEngine; 096import org.opencms.publish.CmsPublishJobInfoBean; 097import org.opencms.publish.CmsPublishReport; 098import org.opencms.relations.CmsCategoryService; 099import org.opencms.relations.CmsLink; 100import org.opencms.relations.CmsRelation; 101import org.opencms.relations.CmsRelationFilter; 102import org.opencms.relations.CmsRelationSystemValidator; 103import org.opencms.relations.CmsRelationType; 104import org.opencms.relations.CmsRelationType.CopyBehavior; 105import org.opencms.relations.I_CmsLinkParseable; 106import org.opencms.report.CmsLogReport; 107import org.opencms.report.I_CmsReport; 108import org.opencms.security.CmsAccessControlEntry; 109import org.opencms.security.CmsAccessControlList; 110import org.opencms.security.CmsAuthentificationException; 111import org.opencms.security.CmsOrganizationalUnit; 112import org.opencms.security.CmsPasswordEncryptionException; 113import org.opencms.security.CmsPermissionSet; 114import org.opencms.security.CmsPermissionSetCustom; 115import org.opencms.security.CmsPrincipal; 116import org.opencms.security.CmsRole; 117import org.opencms.security.CmsSecurityException; 118import org.opencms.security.I_CmsPermissionHandler; 119import org.opencms.security.I_CmsPermissionHandler.LockCheck; 120import org.opencms.security.I_CmsPrincipal; 121import org.opencms.security.twofactor.CmsSecondFactorInfo; 122import org.opencms.security.twofactor.CmsSecondFactorSetupException; 123import org.opencms.security.twofactor.CmsTwoFactorAuthenticationHandler; 124import org.opencms.site.CmsSiteMatcher; 125import org.opencms.util.CmsFileUtil; 126import org.opencms.util.CmsPath; 127import org.opencms.util.CmsStringUtil; 128import org.opencms.util.CmsUUID; 129import org.opencms.util.PrintfFormat; 130import org.opencms.workflow.CmsDefaultWorkflowManager; 131import org.opencms.workplace.threads.A_CmsProgressThread; 132 133import java.lang.reflect.Proxy; 134import java.util.ArrayList; 135import java.util.Collection; 136import java.util.Collections; 137import java.util.Comparator; 138import java.util.Date; 139import java.util.HashMap; 140import java.util.HashSet; 141import java.util.Iterator; 142import java.util.List; 143import java.util.ListIterator; 144import java.util.Locale; 145import java.util.Map; 146import java.util.Map.Entry; 147import java.util.Set; 148import java.util.TreeSet; 149import java.util.concurrent.ConcurrentMap; 150import java.util.concurrent.ExecutionException; 151import java.util.function.Predicate; 152import java.util.regex.Pattern; 153import java.util.regex.PatternSyntaxException; 154import java.util.stream.Collectors; 155 156import org.apache.commons.logging.Log; 157 158import com.google.common.collect.ArrayListMultimap; 159import com.google.common.collect.Maps; 160import com.google.common.collect.Multimap; 161 162/** 163 * The OpenCms driver manager.<p> 164 * 165 * @since 6.0.0 166 */ 167public final class CmsDriverManager implements I_CmsEventListener { 168 169 /** 170 * Enum for distinguishing between login modes. 171 */ 172 public static enum LoginUserMode { 173 /** Check mode, where the user is not logged in, but the password check and other checks are still done (however not the second factor check for 2FA). */ 174 checkOnly, 175 176 /** Normal login process. */ 177 standard 178 } 179 180 /** 181 * Special key class for caching the resource OU data with a Guava LoadingCache.<p> 182 * 183 * In principle, the actual cache key is just the current project, but because of how cache loaders work, 184 * the key must contain everything that varies between calls and is required to load the value. So we also store the DB context 185 * for use by the cache loader. The project (offline/online) must still be stored, because the DB context gets invalidated 186 * eventually, i.e. its project id gets nulled. 187 */ 188 public static class ResourceOUCacheKey { 189 190 /** The actual cache key. */ 191 private String m_actualKey; 192 193 /** The DB context. */ 194 private CmsDbContext m_dbc; 195 196 /** The driver manager to use. */ 197 private CmsDriverManager m_driverManager; 198 199 /** 200 * Creates a new instance. 201 * 202 * @param driverManager the driver manager to use 203 * @param dbc the current DB context 204 */ 205 public ResourceOUCacheKey(CmsDriverManager driverManager, CmsDbContext dbc) { 206 207 m_dbc = dbc; 208 m_driverManager = driverManager; 209 m_actualKey = CmsProject.ONLINE_PROJECT_ID.equals(dbc.currentProject().getId()) ? "ONLINE" : "OFFLINE"; 210 } 211 212 /** 213 * @see java.lang.Object#equals(java.lang.Object) 214 */ 215 @Override 216 public boolean equals(Object obj) { 217 218 return (obj instanceof ResourceOUCacheKey) 219 && ((ResourceOUCacheKey)obj).getActualKey().equals(getActualKey()); 220 } 221 222 /** 223 * Gets the stored DB context.<p> 224 * 225 * Note that the DB contex returned by this may have been invalidated! 226 * 227 * @return the stored DB context 228 */ 229 public CmsDbContext getDbContext() { 230 231 return m_dbc; 232 } 233 234 /** 235 * Gets the current driver manager. 236 * 237 * @return the driver manager to use 238 **/ 239 public CmsDriverManager getDriverManager() { 240 241 return m_driverManager; 242 } 243 244 /** 245 * @see java.lang.Object#hashCode() 246 */ 247 @Override 248 public int hashCode() { 249 250 return getActualKey().hashCode(); 251 } 252 253 /** 254 * Gets the actual key data. 255 * 256 * @return the actual key data 257 */ 258 private String getActualKey() { 259 260 return m_actualKey; 261 } 262 263 } 264 265 /** 266 * Helper class used to store information about resources assigned to OUs in a cache. 267 */ 268 public static class ResourceOUMap { 269 270 /** Multimap from the paths of resources to the OUs to which they are assigned as OU resources. */ 271 private Multimap<CmsPath, CmsOrganizationalUnit> m_ousByAssignedResourcePaths = ArrayListMultimap.create(); 272 273 /** The organizational units, with their UUIDs as keys. */ 274 private Map<CmsUUID, CmsOrganizationalUnit> m_ousById = new HashMap<>(); 275 276 /** 277 * Gets the list of organizational units to which a given root path belongs, according to the cached 278 * OU resource assignments. 279 * 280 * @param rootPath the root path 281 * @return the organizational units to which the path belongs 282 */ 283 public List<CmsOrganizationalUnit> getResourceOrgUnits(String rootPath) { 284 285 Set<CmsOrganizationalUnit> result = new HashSet<>(); 286 String currentPath = rootPath; 287 while (currentPath != null) { 288 result.addAll(m_ousByAssignedResourcePaths.get(new CmsPath(currentPath))); 289 currentPath = CmsResource.getParentFolder(currentPath); 290 } 291 return new ArrayList<>(result); 292 } 293 294 /** 295 * Reads the OU resource data from the VFS and initializes this instance with it. 296 * 297 * @param driverManager the driver manager to use 298 * @param dbc the current DB context 299 * @throws CmsException if something goes wrong 300 */ 301 public void init(CmsDriverManager driverManager, CmsDbContext dbc) throws CmsException { 302 303 List<CmsRelation> relations = driverManager.getRelationsForResource( 304 dbc, 305 null, 306 CmsRelationFilter.ALL.filterType(CmsRelationType.OU_RESOURCE)); 307 CmsOrganizationalUnit root = driverManager.readOrganizationalUnit(dbc, ""); 308 List<CmsOrganizationalUnit> children = driverManager.getOrganizationalUnits(dbc, root, true); 309 310 Set<CmsOrganizationalUnit> ous = new HashSet<>(); 311 ous.add(root); 312 ous.addAll(children); 313 init(relations, ous); 314 315 } 316 317 /** 318 * Initializes the OU resource data. 319 * 320 * @param ouRelations the current list of OU relations 321 * @param ous the current list of OUs 322 */ 323 public void init(Collection<CmsRelation> ouRelations, Collection<CmsOrganizationalUnit> ous) { 324 325 m_ousById.clear(); 326 m_ousByAssignedResourcePaths.clear(); 327 for (CmsOrganizationalUnit ou : ous) { 328 m_ousById.put(ou.getId(), ou); 329 } 330 for (CmsRelation rel : ouRelations) { 331 CmsOrganizationalUnit ou = m_ousById.get(rel.getSourceId()); 332 if (ou != null) { 333 m_ousByAssignedResourcePaths.put(new CmsPath(rel.getTargetPath()), ou); 334 } 335 } 336 } 337 } 338 339 /** 340 * The comparator used for comparing url name mapping entries by date.<p> 341 */ 342 class UrlNameMappingComparator implements Comparator<CmsUrlNameMappingEntry> { 343 344 /** 345 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) 346 */ 347 public int compare(CmsUrlNameMappingEntry o1, CmsUrlNameMappingEntry o2) { 348 349 long date1 = o1.getDateChanged(); 350 long date2 = o2.getDateChanged(); 351 if (date1 < date2) { 352 return -1; 353 } 354 if (date1 > date2) { 355 return +1; 356 } 357 return 0; 358 } 359 } 360 361 /** 362 * Enumeration class for the mode parameter in the 363 * {@link CmsDriverManager#readChangedResourcesInsideProject(CmsDbContext, CmsUUID, CmsReadChangedProjectResourceMode)} 364 * method.<p> 365 */ 366 private static class CmsReadChangedProjectResourceMode { 367 368 /** 369 * Default constructor.<p> 370 */ 371 protected CmsReadChangedProjectResourceMode() { 372 373 // noop 374 } 375 } 376 377 /** Attribute for signaling to the user driver that a specific OU should be initialized by fillDefaults. */ 378 public static final String ATTR_INIT_OU = "INIT_OU"; 379 380 /** Attribute login. */ 381 public static final String ATTRIBUTE_LOGIN = "A_LOGIN"; 382 383 /** Cache key for all properties. */ 384 public static final String CACHE_ALL_PROPERTIES = "_CAP_"; 385 386 /** 387 * Values indicating changes of a resource, 388 * ordered according to the scope of the change. 389 */ 390 /** Value to indicate a change in access control entries of a resource. */ 391 public static final int CHANGED_ACCESSCONTROL = 1; 392 393 /** Value to indicate a content change. */ 394 public static final int CHANGED_CONTENT = 16; 395 396 /** Value to indicate a change in the lastmodified settings of a resource. */ 397 public static final int CHANGED_LASTMODIFIED = 4; 398 399 /** Value to indicate a project change. */ 400 public static final int CHANGED_PROJECT = 32; 401 402 /** Value to indicate a change in the resource data. */ 403 public static final int CHANGED_RESOURCE = 8; 404 405 /** Value to indicate a change in the availability timeframe. */ 406 public static final int CHANGED_TIMEFRAME = 2; 407 408 /** "cache" string in the configuration-file. */ 409 public static final String CONFIGURATION_CACHE = "cache"; 410 411 /** "db" string in the configuration-file. */ 412 public static final String CONFIGURATION_DB = "db"; 413 414 /** "driver.history" string in the configuration-file. */ 415 public static final String CONFIGURATION_HISTORY = "driver.history"; 416 417 /** "driver.project" string in the configuration-file. */ 418 public static final String CONFIGURATION_PROJECT = "driver.project"; 419 420 /** "subscription.vfs" string in the configuration file. */ 421 public static final String CONFIGURATION_SUBSCRIPTION = "driver.subscription"; 422 423 /** "driver.user" string in the configuration-file. */ 424 public static final String CONFIGURATION_USER = "driver.user"; 425 426 /** "driver.vfs" string in the configuration-file. */ 427 public static final String CONFIGURATION_VFS = "driver.vfs"; 428 429 /** DBC attribute key needed to fix publishing behavior involving siblings. */ 430 public static final String KEY_CHANGED_AND_DELETED = "changedAndDeleted"; 431 432 /** The vfs path of the loast and found folder. */ 433 public static final String LOST_AND_FOUND_FOLDER = "/system/lost-found"; 434 435 /** The maximum length of a VFS resource path. */ 436 public static final int MAX_VFS_RESOURCE_PATH_LENGTH = 512; 437 438 /** Key for indicating no changes. */ 439 public static final int NOTHING_CHANGED = 0; 440 441 /** Name of the configuration parameter to enable/disable logging to the CMS_LOG table. */ 442 public static final String PARAM_LOG_TABLE_ENABLED = "log.table.enabled"; 443 444 /** Indicates to ignore the resource path when matching resources. */ 445 public static final String READ_IGNORE_PARENT = null; 446 447 /** Indicates to ignore the time value. */ 448 public static final long READ_IGNORE_TIME = 0L; 449 450 /** Indicates to ignore the resource type when matching resources. */ 451 public static final int READ_IGNORE_TYPE = -1; 452 453 /** Indicates to match resources NOT having the given state. */ 454 public static final int READMODE_EXCLUDE_STATE = 8; 455 456 /** Indicates to match immediate children only. */ 457 public static final int READMODE_EXCLUDE_TREE = 1; 458 459 /** Indicates to match resources NOT having the given type. */ 460 public static final int READMODE_EXCLUDE_TYPE = 4; 461 462 /** Mode for reading project resources from the db. */ 463 public static final int READMODE_IGNORESTATE = 0; 464 465 /** Indicates to match resources in given project only. */ 466 public static final int READMODE_INCLUDE_PROJECT = 2; 467 468 /** Indicates to match all successors. */ 469 public static final int READMODE_INCLUDE_TREE = 0; 470 471 /** Mode for reading project resources from the db. */ 472 public static final int READMODE_MATCHSTATE = 1; 473 474 /** Indicates if only file resources should be read. */ 475 public static final int READMODE_ONLY_FILES = 128; 476 477 /** Indicates if only folder resources should be read. */ 478 public static final int READMODE_ONLY_FOLDERS = 64; 479 480 /** Mode for reading project resources from the db. */ 481 public static final int READMODE_UNMATCHSTATE = 2; 482 483 /** Flag that can be used to disable the resource OU caching if necessary. */ 484 public static boolean resourceOrgUnitCachingEnabled = true; 485 486 /** Prefix char for temporary files in the VFS. */ 487 public static final String TEMP_FILE_PREFIX = "~"; 488 489 /** Key to indicate complete update. */ 490 public static final int UPDATE_ALL = 3; 491 492 /** Key to indicate update of resource record. */ 493 public static final int UPDATE_RESOURCE = 4; 494 495 /** Key to indicate update of last modified project reference. */ 496 public static final int UPDATE_RESOURCE_PROJECT = 6; 497 498 /** Key to indicate update of resource state. */ 499 public static final int UPDATE_RESOURCE_STATE = 1; 500 501 /** Key to indicate update of resource state including the content date. */ 502 public static final int UPDATE_RESOURCE_STATE_CONTENT = 7; 503 504 /** Key to indicate update of structure record. */ 505 public static final int UPDATE_STRUCTURE = 5; 506 507 /** Key to indicate update of structure state. */ 508 public static final int UPDATE_STRUCTURE_STATE = 2; 509 510 /** Map of pools defined in opencms.properties. */ 511 protected static ConcurrentMap<String, CmsDbPoolV11> m_pools = Maps.newConcurrentMap(); 512 513 /** The log object for this class. */ 514 private static final Log LOG = CmsLog.getLog(CmsDriverManager.class); 515 516 /** Constant mode parameter to read all files and folders in the {@link #readChangedResourcesInsideProject(CmsDbContext, CmsUUID, CmsReadChangedProjectResourceMode)}} method. */ 517 private static final CmsReadChangedProjectResourceMode RCPRM_FILES_AND_FOLDERS_MODE = new CmsReadChangedProjectResourceMode(); 518 519 /** Constant mode parameter to read all files and folders in the {@link #readChangedResourcesInsideProject(CmsDbContext, CmsUUID, CmsReadChangedProjectResourceMode)}} method. */ 520 private static final CmsReadChangedProjectResourceMode RCPRM_FILES_ONLY_MODE = new CmsReadChangedProjectResourceMode(); 521 522 /** Constant mode parameter to read all files and folders in the {@link #readChangedResourcesInsideProject(CmsDbContext, CmsUUID, CmsReadChangedProjectResourceMode)}} method. */ 523 private static final CmsReadChangedProjectResourceMode RCPRM_FOLDERS_ONLY_MODE = new CmsReadChangedProjectResourceMode(); 524 525 /** The history driver. */ 526 private I_CmsHistoryDriver m_historyDriver; 527 528 /** The HTML link validator. */ 529 private CmsRelationSystemValidator m_htmlLinkValidator; 530 531 /** The class used for cache key generation. */ 532 private I_CmsCacheKey m_keyGenerator; 533 534 /** The lock manager. */ 535 private CmsLockManager m_lockManager; 536 537 /** The log entry cache. */ 538 private List<CmsLogEntry> m_log = new ArrayList<CmsLogEntry>(); 539 540 /** Local reference to the memory monitor to avoid multiple lookups through the OpenCms singleton. */ 541 private CmsMemoryMonitor m_monitor; 542 543 /** The project driver. */ 544 private I_CmsProjectDriver m_projectDriver; 545 546 /** The the configuration read from the <code>opencms.properties</code> file. */ 547 private CmsParameterConfiguration m_propertyConfiguration; 548 549 /** the publish engine. */ 550 private CmsPublishEngine m_publishEngine; 551 552 /** Object used for synchronizing updates to the user publish list. */ 553 private Object m_publishListUpdateLock = new Object(); 554 555 /** The security manager (for access checks). */ 556 private CmsSecurityManager m_securityManager; 557 558 /** The sql manager. */ 559 private CmsSqlManager m_sqlManager; 560 561 /** The subscription driver. */ 562 private I_CmsSubscriptionDriver m_subscriptionDriver; 563 564 /** The user driver. */ 565 private I_CmsUserDriver m_userDriver; 566 567 /** The VFS driver. */ 568 private I_CmsVfsDriver m_vfsDriver; 569 570 /** 571 * Private constructor, initializes some required member variables.<p> 572 */ 573 private CmsDriverManager() { 574 575 // intentionally left blank 576 } 577 578 /** 579 * Reads the required configurations from the opencms.properties file and creates 580 * the various drivers to access the cms resources.<p> 581 * 582 * The initialization process of the driver manager and its drivers is split into 583 * the following phases: 584 * <ul> 585 * <li>the database pool configuration is read</li> 586 * <li>a plain and empty driver manager instance is created</li> 587 * <li>an instance of each driver is created</li> 588 * <li>the driver manager is passed to each driver during initialization</li> 589 * <li>finally, the driver instances are passed to the driver manager during initialization</li> 590 * </ul> 591 * 592 * @param configurationManager the configuration manager 593 * @param securityManager the security manager 594 * @param runtimeInfoFactory the initialized OpenCms runtime info factory 595 * @param publishEngine the publish engine 596 * 597 * @return CmsDriverManager the instantiated driver manager 598 * @throws CmsInitException if the driver manager couldn't be instantiated 599 */ 600 public static CmsDriverManager newInstance( 601 CmsConfigurationManager configurationManager, 602 CmsSecurityManager securityManager, 603 I_CmsDbContextFactory runtimeInfoFactory, 604 CmsPublishEngine publishEngine) 605 throws CmsInitException { 606 607 // read the opencms.properties from the configuration 608 CmsParameterConfiguration config = configurationManager.getConfiguration(); 609 610 CmsDriverManager driverManager = null; 611 try { 612 // create a driver manager instance 613 driverManager = new CmsDriverManager(); 614 if (CmsLog.INIT.isInfoEnabled()) { 615 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_PHASE1_0)); 616 } 617 if (runtimeInfoFactory == null) { 618 throw new CmsInitException( 619 org.opencms.main.Messages.get().container(org.opencms.main.Messages.ERR_CRITICAL_NO_DB_CONTEXT_0)); 620 } 621 } catch (Exception exc) { 622 CmsMessageContainer message = Messages.get().container(Messages.LOG_ERR_DRIVER_MANAGER_START_0); 623 if (LOG.isFatalEnabled()) { 624 LOG.fatal(message.key(), exc); 625 } 626 throw new CmsInitException(message, exc); 627 } 628 629 // store the configuration 630 driverManager.m_propertyConfiguration = config; 631 632 // set the security manager 633 driverManager.m_securityManager = securityManager; 634 635 // set the lock manager 636 driverManager.m_lockManager = new CmsLockManager(driverManager); 637 638 // create and set the sql manager 639 driverManager.m_sqlManager = new CmsSqlManager(driverManager); 640 641 // set the publish engine 642 driverManager.m_publishEngine = publishEngine; 643 644 if (CmsLog.INIT.isInfoEnabled()) { 645 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_PHASE2_0)); 646 } 647 648 // read the pool names to initialize 649 List<String> driverPoolNames = config.getList(CmsDriverManager.CONFIGURATION_DB + ".pools"); 650 if (CmsLog.INIT.isInfoEnabled()) { 651 String names = ""; 652 for (String name : driverPoolNames) { 653 names += name + " "; 654 } 655 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_POOLS_1, names)); 656 } 657 658 // initialize each pool 659 for (String name : driverPoolNames) { 660 driverManager.newPoolInstance(config, name); 661 } 662 663 // initialize the runtime info factory with the generated driver manager 664 runtimeInfoFactory.initialize(driverManager); 665 666 if (CmsLog.INIT.isInfoEnabled()) { 667 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_PHASE3_0)); 668 } 669 670 // store the access objects 671 CmsDbContext dbc = runtimeInfoFactory.getDbContext(); 672 driverManager.m_vfsDriver = (I_CmsVfsDriver)driverManager.createDriver( 673 dbc, 674 configurationManager, 675 config, 676 CONFIGURATION_VFS, 677 ".vfs.driver"); 678 dbc.clear(); 679 680 dbc = runtimeInfoFactory.getDbContext(); 681 driverManager.m_userDriver = (I_CmsUserDriver)driverManager.createDriver( 682 dbc, 683 configurationManager, 684 config, 685 CONFIGURATION_USER, 686 ".user.driver"); 687 dbc.clear(); 688 689 dbc = runtimeInfoFactory.getDbContext(); 690 driverManager.m_projectDriver = (I_CmsProjectDriver)driverManager.createDriver( 691 dbc, 692 configurationManager, 693 config, 694 CONFIGURATION_PROJECT, 695 ".project.driver"); 696 dbc.clear(); 697 698 dbc = runtimeInfoFactory.getDbContext(); 699 driverManager.m_historyDriver = (I_CmsHistoryDriver)driverManager.createDriver( 700 dbc, 701 configurationManager, 702 config, 703 CONFIGURATION_HISTORY, 704 ".history.driver"); 705 dbc.clear(); 706 707 dbc = runtimeInfoFactory.getDbContext(); 708 try { 709 // we wrap this in a try-catch because otherwise it would fail during the update 710 // process, since the subscription driver configuration does not exist at that point. 711 driverManager.m_subscriptionDriver = (I_CmsSubscriptionDriver)driverManager.createDriver( 712 dbc, 713 configurationManager, 714 config, 715 CONFIGURATION_SUBSCRIPTION, 716 ".subscription.driver"); 717 } catch (IndexOutOfBoundsException npe) { 718 LOG.warn("Could not instantiate subscription driver!"); 719 LOG.warn(npe.getLocalizedMessage(), npe); 720 } 721 dbc.clear(); 722 723 // register the driver manager for required events 724 org.opencms.main.OpenCms.addCmsEventListener( 725 driverManager, 726 new int[] { 727 I_CmsEventListener.EVENT_UPDATE_EXPORTS, 728 I_CmsEventListener.EVENT_CLEAR_CACHES, 729 I_CmsEventListener.EVENT_CLEAR_PRINCIPAL_CACHES, 730 I_CmsEventListener.EVENT_USER_MODIFIED, 731 I_CmsEventListener.EVENT_PUBLISH_PROJECT}); 732 733 // return the configured driver manager 734 return driverManager; 735 } 736 737 /** 738 * Adds an alias entry.<p> 739 * 740 * @param dbc the database context 741 * @param project the current project 742 * @param alias the alias to add 743 * 744 * @throws CmsException if something goes wrong 745 */ 746 public void addAlias(CmsDbContext dbc, CmsProject project, CmsAlias alias) throws CmsException { 747 748 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 749 vfsDriver.insertAlias(dbc, project, alias); 750 } 751 752 /** 753 * Adds a new relation to the given resource.<p> 754 * 755 * @param dbc the database context 756 * @param resource the resource to add the relation to 757 * @param target the target of the relation 758 * @param type the type of the relation 759 * @param importCase if importing relations 760 * 761 * @throws CmsException if something goes wrong 762 */ 763 public void addRelationToResource( 764 CmsDbContext dbc, 765 CmsResource resource, 766 CmsResource target, 767 CmsRelationType type, 768 boolean importCase) 769 throws CmsException { 770 771 if (type.isDefinedInContent()) { 772 throw new CmsIllegalArgumentException( 773 Messages.get().container( 774 Messages.ERR_ADD_RELATION_IN_CONTENT_3, 775 dbc.removeSiteRoot(resource.getRootPath()), 776 dbc.removeSiteRoot(target.getRootPath()), 777 type.getLocalizedName(dbc.getRequestContext().getLocale()))); 778 } 779 CmsRelation relation = new CmsRelation(resource, target, type); 780 getVfsDriver(dbc).createRelation(dbc, dbc.currentProject().getUuid(), relation); 781 if (!importCase) { 782 // log it 783 log( 784 dbc, 785 new CmsLogEntry( 786 dbc, 787 resource.getStructureId(), 788 CmsLogEntryType.RESOURCE_ADD_RELATION, 789 new String[] {relation.getSourcePath(), relation.getTargetPath()}), 790 false); 791 // touch the resource 792 setDateLastModified(dbc, resource, System.currentTimeMillis()); 793 } 794 } 795 796 /** 797 * Adds a resource to the given organizational unit.<p> 798 * 799 * @param dbc the current db context 800 * @param orgUnit the organizational unit to add the resource to 801 * @param resource the resource that is to be added to the organizational unit 802 * 803 * @throws CmsException if something goes wrong 804 * 805 * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String) 806 * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String) 807 */ 808 public void addResourceToOrgUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, CmsResource resource) 809 throws CmsException { 810 811 m_monitor.flushCache(CmsMemoryMonitor.CacheType.HAS_ROLE, CmsMemoryMonitor.CacheType.ROLE_LIST); 812 getUserDriver(dbc).addResourceToOrganizationalUnit(dbc, orgUnit, resource); 813 } 814 815 /** 816 * Adds a user to a group.<p> 817 * 818 * @param dbc the current database context 819 * @param username the name of the user that is to be added to the group 820 * @param groupname the name of the group 821 * @param readRoles if reading roles or groups 822 * 823 * @throws CmsException if operation was not successful 824 * @throws CmsDbEntryNotFoundException if the given user or the given group was not found 825 * 826 * @see #removeUserFromGroup(CmsDbContext, String, String, boolean) 827 */ 828 public void addUserToGroup(CmsDbContext dbc, String username, String groupname, boolean readRoles) 829 throws CmsException, CmsDbEntryNotFoundException { 830 831 //check if group exists 832 CmsGroup group = readGroup(dbc, groupname); 833 if (group == null) { 834 // the group does not exists 835 throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, groupname)); 836 } 837 if (group.isVirtual() && !readRoles) { 838 String roleName = CmsRole.valueOf(group).getGroupName(); 839 if (!userInGroup(dbc, username, roleName, true)) { 840 addUserToGroup(dbc, username, roleName, true); 841 return; 842 } 843 } 844 if (group.isVirtual()) { 845 // this is an hack to prevent unlimited recursive calls 846 readRoles = false; 847 } 848 if ((readRoles && !group.isRole()) || (!readRoles && group.isRole())) { 849 // we want a role but we got a group, or the other way 850 throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, groupname)); 851 } 852 if (userInGroup(dbc, username, groupname, readRoles)) { 853 // the user is already member of the group 854 return; 855 } 856 //check if the user exists 857 CmsUser user = readUser(dbc, username); 858 if (user == null) { 859 // the user does not exists 860 throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_USER_1, username)); 861 } 862 863 // if adding an user to a role 864 if (readRoles) { 865 CmsRole role = CmsRole.valueOf(group); 866 // a role can only be set if the user has the given role 867 m_securityManager.checkRole(dbc, role); 868 // now we check if we already have the role 869 if (m_securityManager.hasRole(dbc, user, role)) { 870 // do nothing 871 return; 872 } 873 // and now we need to remove all possible child-roles 874 List<CmsRole> children = role.getChildren(true); 875 Iterator<CmsGroup> itUserGroups = getGroupsOfUser( 876 dbc, 877 username, 878 group.getOuFqn(), 879 true, 880 true, 881 true, 882 dbc.getRequestContext().getRemoteAddress()).iterator(); 883 while (itUserGroups.hasNext()) { 884 CmsGroup roleGroup = itUserGroups.next(); 885 if (children.contains(CmsRole.valueOf(roleGroup))) { 886 // remove only child roles 887 removeUserFromGroup(dbc, username, roleGroup.getName(), true); 888 } 889 } 890 // update virtual groups 891 Iterator<CmsGroup> it = getVirtualGroupsForRole(dbc, role).iterator(); 892 while (it.hasNext()) { 893 CmsGroup virtualGroup = it.next(); 894 // here we say readroles = true, to prevent an unlimited recursive calls 895 addUserToGroup(dbc, username, virtualGroup.getName(), true); 896 } 897 } 898 899 //add this user to the group 900 getUserDriver(dbc).createUserInGroup(dbc, user.getId(), group.getId()); 901 902 // flush the cache 903 if (readRoles) { 904 m_monitor.flushCache(CmsMemoryMonitor.CacheType.HAS_ROLE, CmsMemoryMonitor.CacheType.ROLE_LIST); 905 } 906 m_monitor.flushUserGroups(user.getId()); 907 m_monitor.flushCache(CmsMemoryMonitor.CacheType.USER_LIST); 908 909 if (!dbc.getProjectId().isNullUUID() && !CmsProject.ONLINE_PROJECT_ID.equals(dbc.getProjectId())) { 910 // user modified event is not needed 911 return; 912 } 913 // fire user modified event 914 Map<String, Object> eventData = new HashMap<String, Object>(); 915 eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); 916 eventData.put(I_CmsEventListener.KEY_USER_NAME, user.getName()); 917 eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); 918 eventData.put(I_CmsEventListener.KEY_GROUP_NAME, group.getName()); 919 eventData.put( 920 I_CmsEventListener.KEY_USER_ACTION, 921 I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_ADD_USER_TO_GROUP); 922 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); 923 } 924 925 /** 926 * Changes the lock of a resource to the current user, 927 * that is "steals" the lock from another user.<p> 928 * 929 * @param dbc the current database context 930 * @param resource the resource to change the lock for 931 * @param lockType the new lock type to set 932 * 933 * @throws CmsException if something goes wrong 934 * @throws CmsSecurityException if something goes wrong 935 * 936 * 937 * @see CmsObject#changeLock(String) 938 * @see I_CmsResourceType#changeLock(CmsObject, CmsSecurityManager, CmsResource) 939 * 940 * @see CmsSecurityManager#hasPermissions(CmsRequestContext, CmsResource, CmsPermissionSet, boolean, CmsResourceFilter) 941 */ 942 public void changeLock(CmsDbContext dbc, CmsResource resource, CmsLockType lockType) 943 throws CmsException, CmsSecurityException { 944 945 // get the current lock 946 CmsLock currentLock = getLock(dbc, resource); 947 // check if the resource is locked at all 948 if (currentLock.getEditionLock().isUnlocked() && currentLock.getSystemLock().isUnlocked()) { 949 throw new CmsLockException( 950 Messages.get().container( 951 Messages.ERR_CHANGE_LOCK_UNLOCKED_RESOURCE_1, 952 dbc.getRequestContext().getSitePath(resource))); 953 } else if ((lockType == CmsLockType.EXCLUSIVE) 954 && currentLock.isExclusiveOwnedInProjectBy(dbc.currentUser(), dbc.currentProject())) { 955 // the current lock requires no change 956 return; 957 } 958 959 // duplicate logic from CmsSecurityManager#hasPermissions() because lock state can't be ignored 960 // if another user has locked the file, the current user can never get WRITE permissions with the default check 961 int denied = 0; 962 963 // check if the current user is vfs manager 964 boolean canIgnorePermissions = m_securityManager.hasRoleForResource( 965 dbc, 966 dbc.currentUser(), 967 CmsRole.VFS_MANAGER, 968 resource); 969 // if the resource type is jsp 970 // write is only allowed for developers 971 if (!canIgnorePermissions && (CmsResourceTypeJsp.isJsp(resource))) { 972 if (!m_securityManager.hasRoleForResource(dbc, dbc.currentUser(), CmsRole.VFS_MANAGER, resource)) { 973 denied |= CmsPermissionSet.PERMISSION_WRITE; 974 } 975 } 976 CmsPermissionSetCustom permissions; 977 if (canIgnorePermissions) { 978 // if the current user is administrator, anything is allowed 979 permissions = new CmsPermissionSetCustom(~0); 980 } else { 981 // otherwise, get the permissions from the access control list 982 permissions = getPermissions(dbc, resource, dbc.currentUser()); 983 } 984 // revoke the denied permissions 985 permissions.denyPermissions(denied); 986 // now check if write permission is granted 987 if ((CmsPermissionSet.ACCESS_WRITE.getPermissions() 988 & permissions.getPermissions()) != CmsPermissionSet.ACCESS_WRITE.getPermissions()) { 989 // check failed, throw exception 990 m_securityManager.checkPermissions( 991 dbc.getRequestContext(), 992 resource, 993 CmsPermissionSet.ACCESS_WRITE, 994 I_CmsPermissionHandler.PERM_DENIED); 995 } 996 // if we got here write permission is granted on the target 997 998 // remove the old lock 999 m_lockManager.removeResource(dbc, resource, true, lockType.isSystem()); 1000 // apply the new lock 1001 lockResource(dbc, resource, lockType); 1002 } 1003 1004 /** 1005 * Returns a list with all sub resources of a given folder that have set the given property, 1006 * matching the current property's value with the given old value and replacing it by a given new value.<p> 1007 * 1008 * @param dbc the current database context 1009 * @param resource the resource on which property definition values are changed 1010 * @param propertyDefinition the name of the propertydefinition to change the value 1011 * @param oldValue the old value of the propertydefinition 1012 * @param newValue the new value of the propertydefinition 1013 * @param recursive if true, change the property value on the resource and recursively all property values on 1014 * sub-resources (only for folders) 1015 * @return a list with the <code>{@link CmsResource}</code>'s where the property value has been changed 1016 * 1017 * @throws CmsVfsException for now only when the search for the oldvalue failed. 1018 * @throws CmsException if operation was not successful 1019 */ 1020 public List<CmsResource> changeResourcesInFolderWithProperty( 1021 CmsDbContext dbc, 1022 CmsResource resource, 1023 String propertyDefinition, 1024 String oldValue, 1025 String newValue, 1026 boolean recursive) 1027 throws CmsVfsException, CmsException { 1028 1029 CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION; 1030 // collect the resources to look up 1031 List<CmsResource> resources = new ArrayList<CmsResource>(); 1032 if (recursive) { 1033 // read the files in the folder 1034 resources = readResourcesWithProperty(dbc, resource, propertyDefinition, null, filter); 1035 // add the folder itself 1036 resources.add(resource); 1037 } else { 1038 resources.add(resource); 1039 } 1040 1041 Pattern oldPattern; 1042 try { 1043 // remove the place holder if available 1044 String tmpOldValue = oldValue; 1045 if (tmpOldValue.contains(CmsStringUtil.PLACEHOLDER_START) 1046 && tmpOldValue.contains(CmsStringUtil.PLACEHOLDER_END)) { 1047 tmpOldValue = tmpOldValue.replace(CmsStringUtil.PLACEHOLDER_START, ""); 1048 tmpOldValue = tmpOldValue.replace(CmsStringUtil.PLACEHOLDER_END, ""); 1049 } 1050 // compile regular expression pattern 1051 oldPattern = Pattern.compile(tmpOldValue); 1052 } catch (PatternSyntaxException e) { 1053 throw new CmsVfsException( 1054 Messages.get().container( 1055 Messages.ERR_CHANGE_RESOURCES_IN_FOLDER_WITH_PROP_4, 1056 new Object[] {propertyDefinition, oldValue, newValue, resource.getRootPath()}), 1057 e); 1058 } 1059 1060 List<CmsResource> changedResources = new ArrayList<CmsResource>(resources.size()); 1061 // create permission set and filter to check each resource 1062 CmsPermissionSet perm = CmsPermissionSet.ACCESS_WRITE; 1063 for (int i = 0; i < resources.size(); i++) { 1064 // loop through found resources and check property values 1065 CmsResource res = resources.get(i); 1066 // check resource state and permissions 1067 try { 1068 m_securityManager.checkPermissions(dbc, res, perm, true, filter); 1069 } catch (Exception e) { 1070 // resource is deleted or not writable for current user 1071 continue; 1072 } 1073 CmsProperty property = readPropertyObject(dbc, res, propertyDefinition, false); 1074 String propertyValue = property.getValue(); 1075 boolean changed = false; 1076 if ((propertyValue != null) && oldPattern.matcher(propertyValue).matches()) { 1077 // apply the place holder content 1078 String tmpNewValue = CmsStringUtil.transformValues(oldValue, newValue, propertyValue); 1079 // change structure value 1080 property.setStructureValue(tmpNewValue); 1081 changed = true; 1082 } 1083 if (changed) { 1084 // write property object if something has changed 1085 writePropertyObject(dbc, res, property); 1086 changedResources.add(res); 1087 } 1088 } 1089 return changedResources; 1090 } 1091 1092 /** 1093 * Changes the resource flags of a resource.<p> 1094 * 1095 * The resource flags are used to indicate various "special" conditions 1096 * for a resource. Most notably, the "internal only" setting which signals 1097 * that a resource can not be directly requested with it's URL.<p> 1098 * 1099 * @param dbc the current database context 1100 * @param resource the resource to change the flags for 1101 * @param flags the new resource flags for this resource 1102 * 1103 * @throws CmsException if something goes wrong 1104 * 1105 * @see CmsObject#chflags(String, int) 1106 * @see I_CmsResourceType#chflags(CmsObject, CmsSecurityManager, CmsResource, int) 1107 */ 1108 public void chflags(CmsDbContext dbc, CmsResource resource, int flags) throws CmsException { 1109 1110 // must operate on a clone to ensure resource is not modified in case permissions are not granted 1111 CmsResource clone = (CmsResource)resource.clone(); 1112 clone.setFlags(flags); 1113 // log it 1114 log( 1115 dbc, 1116 new CmsLogEntry( 1117 dbc, 1118 resource.getStructureId(), 1119 CmsLogEntryType.RESOURCE_FLAGS, 1120 new String[] {resource.getRootPath()}), 1121 false); 1122 // write it 1123 writeResource(dbc, clone); 1124 } 1125 1126 /** 1127 * Changes the resource type of a resource.<p> 1128 * 1129 * OpenCms handles resources according to the resource type, 1130 * not the file suffix. This is e.g. why a JSP in OpenCms can have the 1131 * suffix ".html" instead of ".jsp" only. Changing the resource type 1132 * makes sense e.g. if you want to make a plain text file a JSP resource, 1133 * or a binary file an image, etc.<p> 1134 * 1135 * @param dbc the current database context 1136 * @param resource the resource to change the type for 1137 * @param type the new resource type for this resource 1138 * 1139 * @throws CmsException if something goes wrong 1140 * 1141 * @see CmsObject#chtype(String, int) 1142 * @see I_CmsResourceType#chtype(CmsObject, CmsSecurityManager, CmsResource, int) 1143 */ 1144 @SuppressWarnings({"javadoc", "deprecation"}) 1145 public void chtype(CmsDbContext dbc, CmsResource resource, int type) throws CmsException { 1146 1147 // must operate on a clone to ensure resource is not modified in case permissions are not granted 1148 CmsResource clone = (CmsResource)resource.clone(); 1149 I_CmsResourceType newType = OpenCms.getResourceManager().getResourceType(type); 1150 clone.setType(newType.getTypeId()); 1151 // log it 1152 log( 1153 dbc, 1154 new CmsLogEntry( 1155 dbc, 1156 resource.getStructureId(), 1157 CmsLogEntryType.RESOURCE_TYPE, 1158 new String[] {resource.getRootPath()}), 1159 false); 1160 // write it 1161 writeResource(dbc, clone); 1162 } 1163 1164 /** 1165 * Cleans up the publish history entries according to the given filter. 1166 * 1167 * @param dbc the database context 1168 * @param filter the filter 1169 * @return the number of cleaned up rows 1170 * @throws CmsDataAccessException if something goes wrong 1171 */ 1172 public int cleanupPublishHistory(CmsDbContext dbc, CmsPublishHistoryCleanupFilter filter) 1173 throws CmsDataAccessException { 1174 1175 int result = m_projectDriver.cleanupPublishHistory(dbc, filter); 1176 if (filter.getMode() == CmsPublishHistoryCleanupFilter.Mode.single) { 1177 OpenCms.getMemoryMonitor().cachePublishedResources(filter.getHistoryId().toString(), null); 1178 } else { 1179 OpenCms.getMemoryMonitor().flushCache(CmsMemoryMonitor.CacheType.PUBLISHED_RESOURCES); 1180 } 1181 return result; 1182 } 1183 1184 /** 1185 * @see org.opencms.main.I_CmsEventListener#cmsEvent(org.opencms.main.CmsEvent) 1186 */ 1187 public void cmsEvent(CmsEvent event) { 1188 1189 if (LOG.isDebugEnabled()) { 1190 LOG.debug(Messages.get().getBundle().key(Messages.LOG_CMS_EVENT_1, new Integer(event.getType()))); 1191 } 1192 1193 I_CmsReport report; 1194 CmsDbContext dbc; 1195 1196 switch (event.getType()) { 1197 1198 case I_CmsEventListener.EVENT_UPDATE_EXPORTS: 1199 dbc = (CmsDbContext)event.getData().get(I_CmsEventListener.KEY_DBCONTEXT); 1200 updateExportPoints(dbc); 1201 break; 1202 1203 case I_CmsEventListener.EVENT_PUBLISH_PROJECT: 1204 CmsUUID publishHistoryId = new CmsUUID((String)event.getData().get(I_CmsEventListener.KEY_PUBLISHID)); 1205 report = (I_CmsReport)event.getData().get(I_CmsEventListener.KEY_REPORT); 1206 dbc = (CmsDbContext)event.getData().get(I_CmsEventListener.KEY_DBCONTEXT); 1207 m_monitor.clearCacheForPublishing(); 1208 writeExportPoints(dbc, report, publishHistoryId); 1209 break; 1210 1211 case I_CmsEventListener.EVENT_CLEAR_CACHES: 1212 m_monitor.clearCache(); 1213 break; 1214 case I_CmsEventListener.EVENT_CLEAR_PRINCIPAL_CACHES: 1215 m_monitor.clearPrincipalsCache(); 1216 break; 1217 case I_CmsEventListener.EVENT_USER_MODIFIED: 1218 String action = (String)event.getData().get(I_CmsEventListener.KEY_USER_ACTION); 1219 m_monitor.flushCache( 1220 CacheType.USER, 1221 CacheType.GROUP, 1222 CacheType.ORG_UNIT, 1223 CacheType.ACL, 1224 CacheType.PERMISSION, 1225 CacheType.USER_LIST); 1226 if (I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_ADD_USER_TO_GROUP.equals(action) 1227 || I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_REMOVE_USER_FROM_GROUP.equals(action) 1228 || I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_SET_OU.equals(action)) { 1229 1230 Object userIdObj = event.getData().get(I_CmsEventListener.KEY_USER_ID); 1231 if (userIdObj != null) { 1232 CmsUUID userId = null; 1233 if (userIdObj instanceof CmsUUID) { 1234 userId = (CmsUUID)userIdObj; 1235 } else if (userIdObj instanceof String) { 1236 try { 1237 userId = new CmsUUID(userIdObj.toString()); 1238 } catch (Exception e) { 1239 LOG.error(e.getLocalizedMessage(), e); 1240 } 1241 } 1242 if (userId != null) { 1243 m_monitor.flushUserGroups(userId); 1244 } 1245 } else { 1246 m_monitor.flushCache(CacheType.USERGROUPS); 1247 } 1248 m_monitor.flushCache(CacheType.HAS_ROLE, CacheType.ROLE_LIST); 1249 } 1250 break; 1251 default: 1252 // noop 1253 } 1254 } 1255 1256 /** 1257 * Copies the access control entries of a given resource to a destination resource.<p> 1258 * 1259 * Already existing access control entries of the destination resource are removed.<p> 1260 * 1261 * @param dbc the current database context 1262 * @param source the resource to copy the access control entries from 1263 * @param destination the resource to which the access control entries are copied 1264 * @param updateLastModifiedInfo if true, user and date "last modified" information on the target resource will be updated 1265 * 1266 * @throws CmsException if something goes wrong 1267 */ 1268 public void copyAccessControlEntries( 1269 CmsDbContext dbc, 1270 CmsResource source, 1271 CmsResource destination, 1272 boolean updateLastModifiedInfo) 1273 throws CmsException { 1274 1275 // get the entries to copy 1276 ListIterator<CmsAccessControlEntry> aceList = getUserDriver( 1277 dbc).readAccessControlEntries(dbc, dbc.currentProject(), source.getResourceId(), false).listIterator(); 1278 1279 // remove the current entries from the destination 1280 getUserDriver(dbc).removeAccessControlEntries(dbc, dbc.currentProject(), destination.getResourceId()); 1281 1282 // now write the new entries 1283 while (aceList.hasNext()) { 1284 CmsAccessControlEntry ace = aceList.next(); 1285 getUserDriver(dbc).createAccessControlEntry( 1286 dbc, 1287 dbc.currentProject(), 1288 destination.getResourceId(), 1289 ace.getPrincipal(), 1290 ace.getPermissions().getAllowedPermissions(), 1291 ace.getPermissions().getDeniedPermissions(), 1292 ace.getFlags()); 1293 } 1294 1295 // log it 1296 log( 1297 dbc, 1298 new CmsLogEntry( 1299 dbc, 1300 destination.getStructureId(), 1301 CmsLogEntryType.RESOURCE_PERMISSIONS, 1302 new String[] {destination.getRootPath()}), 1303 false); 1304 1305 // update the "last modified" information 1306 if (updateLastModifiedInfo) { 1307 setDateLastModified(dbc, destination, destination.getDateLastModified()); 1308 } 1309 1310 // clear the cache 1311 m_monitor.clearAccessControlListCache(); 1312 1313 // fire a resource modification event 1314 Map<String, Object> data = new HashMap<String, Object>(2); 1315 data.put(I_CmsEventListener.KEY_RESOURCE, destination); 1316 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_ACCESSCONTROL)); 1317 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 1318 } 1319 1320 /** 1321 * Copies a resource.<p> 1322 * 1323 * You must ensure that the destination path is an absolute, valid and 1324 * existing VFS path. Relative paths from the source are currently not supported.<p> 1325 * 1326 * In case the target resource already exists, it is overwritten with the 1327 * source resource.<p> 1328 * 1329 * The <code>siblingMode</code> parameter controls how to handle siblings 1330 * during the copy operation. 1331 * Possible values for this parameter are: 1332 * <ul> 1333 * <li><code>{@link org.opencms.file.CmsResource#COPY_AS_NEW}</code></li> 1334 * <li><code>{@link org.opencms.file.CmsResource#COPY_AS_SIBLING}</code></li> 1335 * <li><code>{@link org.opencms.file.CmsResource#COPY_PRESERVE_SIBLING}</code></li> 1336 * </ul><p> 1337 * 1338 * @param dbc the current database context 1339 * @param source the resource to copy 1340 * @param destination the name of the copy destination with complete path 1341 * @param siblingMode indicates how to handle siblings during copy 1342 * 1343 * @throws CmsException if something goes wrong 1344 * @throws CmsIllegalArgumentException if the <code>source</code> argument is <code>null</code> 1345 * 1346 * @see CmsObject#copyResource(String, String, CmsResource.CmsResourceCopyMode) 1347 * @see I_CmsResourceType#copyResource(CmsObject, CmsSecurityManager, CmsResource, String, CmsResource.CmsResourceCopyMode) 1348 */ 1349 public void copyResource( 1350 CmsDbContext dbc, 1351 CmsResource source, 1352 String destination, 1353 CmsResource.CmsResourceCopyMode siblingMode) 1354 throws CmsException, CmsIllegalArgumentException { 1355 1356 // check the sibling mode to see if this resource has to be copied as a sibling 1357 boolean copyAsSibling = false; 1358 1359 // siblings of folders are not supported 1360 if (!source.isFolder()) { 1361 // if the "copy as sibling" mode is used, set the flag to true 1362 if (siblingMode == CmsResource.COPY_AS_SIBLING) { 1363 copyAsSibling = true; 1364 } 1365 // if the mode is "preserve siblings", we have to check the sibling counter 1366 if (siblingMode == CmsResource.COPY_PRESERVE_SIBLING) { 1367 if (source.getSiblingCount() > 1) { 1368 copyAsSibling = true; 1369 } 1370 } 1371 } 1372 1373 // read the source properties 1374 List<CmsProperty> properties = readPropertyObjects(dbc, source, false); 1375 1376 if (copyAsSibling) { 1377 // create a sibling of the source file at the destination 1378 createSibling(dbc, source, destination, properties); 1379 // after the sibling is created the copy operation is finished 1380 return; 1381 } 1382 1383 // prepare the content if required 1384 byte[] content = null; 1385 if (source.isFile()) { 1386 if (source instanceof CmsFile) { 1387 // resource already is a file 1388 content = ((CmsFile)source).getContents(); 1389 } 1390 if ((content == null) || (content.length < 1)) { 1391 // no known content yet - read from database 1392 content = getVfsDriver(dbc).readContent(dbc, dbc.currentProject().getUuid(), source.getResourceId()); 1393 } 1394 } 1395 1396 // determine destination folder 1397 String destinationFoldername = CmsResource.getParentFolder(destination); 1398 1399 // read the destination folder (will also check read permissions) 1400 CmsFolder destinationFolder = m_securityManager.readFolder( 1401 dbc, 1402 destinationFoldername, 1403 CmsResourceFilter.IGNORE_EXPIRATION); 1404 1405 // no further permission check required here, will be done in createResource() 1406 1407 // set user and creation time stamps 1408 long currentTime = System.currentTimeMillis(); 1409 long dateLastModified; 1410 CmsUUID userLastModified; 1411 if (source.isFolder()) { 1412 // folders always get a new date and user when they are copied 1413 dateLastModified = currentTime; 1414 userLastModified = dbc.currentUser().getId(); 1415 } else { 1416 // files keep the date and user last modified from the source 1417 dateLastModified = source.getDateLastModified(); 1418 userLastModified = source.getUserLastModified(); 1419 } 1420 1421 // check the resource flags 1422 int flags = source.getFlags(); 1423 if (source.isLabeled()) { 1424 // reset "labeled" link flag for new resource 1425 flags &= ~CmsResource.FLAG_LABELED; 1426 } 1427 1428 // create the new resource 1429 CmsResource newResource = new CmsResource( 1430 new CmsUUID(), 1431 new CmsUUID(), 1432 destination, 1433 source.getTypeId(), 1434 source.isFolder(), 1435 flags, 1436 dbc.currentProject().getUuid(), 1437 CmsResource.STATE_NEW, 1438 currentTime, 1439 dbc.currentUser().getId(), 1440 dateLastModified, 1441 userLastModified, 1442 source.getDateReleased(), 1443 source.getDateExpired(), 1444 1, 1445 source.getLength(), 1446 source.getDateContent(), 1447 source.getVersion()); // version number does not matter since it will be computed later 1448 1449 // trigger "is touched" state on resource (will ensure modification date is kept unchanged) 1450 newResource.setDateLastModified(dateLastModified); 1451 1452 // log it 1453 log( 1454 dbc, 1455 new CmsLogEntry( 1456 dbc, 1457 newResource.getStructureId(), 1458 CmsLogEntryType.RESOURCE_COPIED, 1459 new String[] {newResource.getRootPath()}), 1460 false); 1461 1462 // create the resource 1463 newResource = createResource(dbc, destination, newResource, content, properties, false); 1464 // copy relations 1465 copyRelations(dbc, source, newResource); 1466 1467 // copy the access control entries to the created resource 1468 copyAccessControlEntries(dbc, source, newResource, false); 1469 1470 // clear the cache 1471 m_monitor.clearAccessControlListCache(); 1472 1473 List<CmsResource> modifiedResources = new ArrayList<CmsResource>(); 1474 modifiedResources.add(source); 1475 modifiedResources.add(newResource); 1476 modifiedResources.add(destinationFolder); 1477 OpenCms.fireCmsEvent( 1478 new CmsEvent( 1479 I_CmsEventListener.EVENT_RESOURCE_COPIED, 1480 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCES, modifiedResources))); 1481 } 1482 1483 /** 1484 * Copies a resource to the current project of the user.<p> 1485 * 1486 * @param dbc the current database context 1487 * @param resource the resource to apply this operation to 1488 * 1489 * @throws CmsException if something goes wrong 1490 * 1491 * @see CmsObject#copyResourceToProject(String) 1492 * @see I_CmsResourceType#copyResourceToProject(CmsObject, CmsSecurityManager, CmsResource) 1493 */ 1494 public void copyResourceToProject(CmsDbContext dbc, CmsResource resource) throws CmsException { 1495 1496 // copy the resource to the project only if the resource is not already in the project 1497 if (!isInsideCurrentProject(dbc, resource.getRootPath())) { 1498 // check if there are already any subfolders of this resource 1499 I_CmsProjectDriver projectDriver = getProjectDriver(dbc); 1500 if (resource.isFolder()) { 1501 List<String> projectResources = projectDriver.readProjectResources(dbc, dbc.currentProject()); 1502 for (int i = 0; i < projectResources.size(); i++) { 1503 String resname = projectResources.get(i); 1504 if (resname.startsWith(resource.getRootPath())) { 1505 // delete the existing project resource first 1506 projectDriver.deleteProjectResource(dbc, dbc.currentProject().getUuid(), resname); 1507 } 1508 } 1509 } 1510 try { 1511 projectDriver.createProjectResource(dbc, dbc.currentProject().getUuid(), resource.getRootPath()); 1512 } catch (CmsException exc) { 1513 // if the subfolder exists already - all is ok 1514 } finally { 1515 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROJECT_RESOURCES); 1516 1517 OpenCms.fireCmsEvent( 1518 new CmsEvent( 1519 I_CmsEventListener.EVENT_PROJECT_MODIFIED, 1520 Collections.<String, Object> singletonMap("project", dbc.currentProject()))); 1521 } 1522 } 1523 } 1524 1525 /** 1526 * Counts the locked resources in this project.<p> 1527 * 1528 * @param project the project to count the locked resources in 1529 * 1530 * @return the amount of locked resources in this project 1531 */ 1532 public int countLockedResources(CmsProject project) { 1533 1534 // count locks 1535 return m_lockManager.countExclusiveLocksInProject(project); 1536 } 1537 1538 /** 1539 * Add a new group to the Cms.<p> 1540 * 1541 * Only the admin can do this. 1542 * Only users, which are in the group "administrators" are granted.<p> 1543 * 1544 * @param dbc the current database context 1545 * @param id the id of the new group 1546 * @param name the name of the new group 1547 * @param description the description for the new group 1548 * @param flags the flags for the new group 1549 * @param parent the name of the parent group (or <code>null</code>) 1550 * 1551 * @return new created group 1552 * 1553 * @throws CmsException if the creation of the group failed 1554 * @throws CmsIllegalArgumentException if the length of the given name was below 1 1555 */ 1556 public CmsGroup createGroup(CmsDbContext dbc, CmsUUID id, String name, String description, int flags, String parent) 1557 throws CmsIllegalArgumentException, CmsException { 1558 1559 // check the group name 1560 OpenCms.getValidationHandler().checkGroupName(CmsOrganizationalUnit.getSimpleName(name)); 1561 // trim the name 1562 name = name.trim(); 1563 1564 // check the OU 1565 readOrganizationalUnit(dbc, CmsOrganizationalUnit.getParentFqn(name)); 1566 1567 // get the id of the parent group if necessary 1568 if (CmsStringUtil.isNotEmpty(parent)) { 1569 CmsGroup parentGroup = readGroup(dbc, parent); 1570 if (!parentGroup.isRole() 1571 && !CmsOrganizationalUnit.getParentFqn(parent).equals(CmsOrganizationalUnit.getParentFqn(name))) { 1572 throw new CmsDataAccessException( 1573 Messages.get().container( 1574 Messages.ERR_PARENT_GROUP_MUST_BE_IN_SAME_OU_3, 1575 CmsOrganizationalUnit.getSimpleName(name), 1576 CmsOrganizationalUnit.getParentFqn(name), 1577 parent)); 1578 } 1579 } 1580 1581 // create the group 1582 CmsGroup group = getUserDriver(dbc).createGroup(dbc, id, name, description, flags, parent); 1583 1584 // if the group is in fact a role, initialize it 1585 if (group.isVirtual()) { 1586 // get all users that have the given role 1587 String groupname = CmsRole.valueOf(group).getGroupName(); 1588 Iterator<CmsUser> it = getUsersOfGroup(dbc, groupname, true, false, true).iterator(); 1589 while (it.hasNext()) { 1590 CmsUser user = it.next(); 1591 // put them in the new group 1592 addUserToGroup(dbc, user.getName(), group.getName(), true); 1593 } 1594 } 1595 1596 // put it into the cache 1597 m_monitor.cacheGroup(group); 1598 1599 if (!dbc.getProjectId().isNullUUID()) { 1600 // group modified event is not needed 1601 return group; 1602 } 1603 // fire group modified event 1604 Map<String, Object> eventData = new HashMap<String, Object>(); 1605 eventData.put(I_CmsEventListener.KEY_GROUP_NAME, group.getName()); 1606 eventData.put(I_CmsEventListener.KEY_GROUP_ID, group.getId().toString()); 1607 eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_GROUP_MODIFIED_ACTION_CREATE); 1608 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_GROUP_MODIFIED, eventData)); 1609 1610 // return it 1611 return group; 1612 } 1613 1614 /** 1615 * Creates a new organizational unit.<p> 1616 * 1617 * @param dbc the current db context 1618 * @param ouFqn the fully qualified name of the new organizational unit 1619 * @param description the description of the new organizational unit 1620 * @param flags the flags for the new organizational unit 1621 * @param resource the first associated resource 1622 * 1623 * @return a <code>{@link CmsOrganizationalUnit}</code> object representing 1624 * the newly created organizational unit 1625 * 1626 * @throws CmsException if operation was not successful 1627 * 1628 * @see org.opencms.security.CmsOrgUnitManager#createOrganizationalUnit(CmsObject, String, String, int, String) 1629 */ 1630 public CmsOrganizationalUnit createOrganizationalUnit( 1631 CmsDbContext dbc, 1632 String ouFqn, 1633 String description, 1634 int flags, 1635 CmsResource resource) 1636 throws CmsException { 1637 1638 // normal case 1639 CmsOrganizationalUnit parent = readOrganizationalUnit(dbc, CmsOrganizationalUnit.getParentFqn(ouFqn)); 1640 String name = CmsOrganizationalUnit.getSimpleName(ouFqn); 1641 if (name.endsWith(CmsOrganizationalUnit.SEPARATOR)) { 1642 name = name.substring(0, name.length() - 1); 1643 } 1644 1645 // check the name 1646 CmsResource.checkResourceName(name); 1647 1648 // trim the name 1649 name = name.trim(); 1650 1651 // check the description 1652 if (CmsStringUtil.isEmptyOrWhitespaceOnly(description)) { 1653 throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_BAD_OU_DESCRIPTION_EMPTY_0)); 1654 } 1655 1656 // create the organizational unit 1657 CmsOrganizationalUnit orgUnit = getUserDriver(dbc).createOrganizationalUnit( 1658 dbc, 1659 name, 1660 description, 1661 flags, 1662 parent, 1663 resource != null ? resource.getRootPath() : null); 1664 // put the new created org unit into the cache 1665 m_monitor.cacheOrgUnit(orgUnit); 1666 1667 // flush relevant caches 1668 m_monitor.clearPrincipalsCache(); 1669 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); 1670 1671 // create a publish list for the 'virtual' publish event 1672 CmsResource ouRes = readResource( 1673 dbc, 1674 CmsUserDriver.ORGUNIT_BASE_FOLDER + orgUnit.getName(), 1675 CmsResourceFilter.DEFAULT); 1676 CmsPublishList pl = new CmsPublishList(ouRes, false); 1677 pl.add(ouRes, false); 1678 1679 getProjectDriver(dbc).writePublishHistory( 1680 dbc, 1681 pl.getPublishHistoryId(), 1682 new CmsPublishedResource(ouRes, -1, CmsResourceState.STATE_NEW)); 1683 1684 // fire the 'virtual' publish event 1685 Map<String, Object> eventData = new HashMap<String, Object>(); 1686 eventData.put(I_CmsEventListener.KEY_PUBLISHID, pl.getPublishHistoryId().toString()); 1687 eventData.put(I_CmsEventListener.KEY_PROJECTID, dbc.currentProject().getUuid()); 1688 eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); 1689 CmsEvent afterPublishEvent = new CmsEvent(I_CmsEventListener.EVENT_PUBLISH_PROJECT, eventData); 1690 OpenCms.fireCmsEvent(afterPublishEvent); 1691 1692 if (!dbc.getProjectId().isNullUUID()) { 1693 // OU modified event is not needed 1694 return orgUnit; 1695 } 1696 1697 // fire OU modified event 1698 Map<String, Object> event2Data = new HashMap<String, Object>(); 1699 event2Data.put(I_CmsEventListener.KEY_OU_NAME, orgUnit.getName()); 1700 event2Data.put(I_CmsEventListener.KEY_OU_ID, orgUnit.getId().toString()); 1701 event2Data.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_OU_MODIFIED_ACTION_CREATE); 1702 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_OU_MODIFIED, event2Data)); 1703 1704 // return it 1705 return orgUnit; 1706 } 1707 1708 /** 1709 * Creates a project.<p> 1710 * 1711 * @param dbc the current database context 1712 * @param name the name of the project to create 1713 * @param description the description of the project 1714 * @param groupname the project user group to be set 1715 * @param managergroupname the project manager group to be set 1716 * @param projecttype the type of the project 1717 * 1718 * @return the created project 1719 * 1720 * @throws CmsIllegalArgumentException if the chosen <code>name</code> is already used 1721 * by the online project, or if the name is not valid 1722 * @throws CmsException if something goes wrong 1723 */ 1724 public CmsProject createProject( 1725 CmsDbContext dbc, 1726 String name, 1727 String description, 1728 String groupname, 1729 String managergroupname, 1730 CmsProject.CmsProjectType projecttype) 1731 throws CmsIllegalArgumentException, CmsException { 1732 1733 if (CmsProject.ONLINE_PROJECT_NAME.equals(name)) { 1734 throw new CmsIllegalArgumentException( 1735 Messages.get().container( 1736 Messages.ERR_CREATE_PROJECT_ONLINE_PROJECT_NAME_1, 1737 CmsProject.ONLINE_PROJECT_NAME)); 1738 } 1739 // check the name 1740 CmsProject.checkProjectName(CmsOrganizationalUnit.getSimpleName(name)); 1741 // check the ou 1742 readOrganizationalUnit(dbc, CmsOrganizationalUnit.getParentFqn(name)); 1743 // read the needed groups from the cms 1744 CmsGroup group = readGroup(dbc, groupname); 1745 CmsGroup managergroup = readGroup(dbc, managergroupname); 1746 1747 return getProjectDriver(dbc).createProject( 1748 dbc, 1749 new CmsUUID(), 1750 dbc.currentUser(), 1751 group, 1752 managergroup, 1753 name, 1754 description, 1755 projecttype.getDefaultFlags(), 1756 projecttype); 1757 } 1758 1759 /** 1760 * Creates a property definition.<p> 1761 * 1762 * Property definitions are valid for all resource types.<p> 1763 * 1764 * @param dbc the current database context 1765 * @param name the name of the property definition to create 1766 * 1767 * @return the created property definition 1768 * 1769 * @throws CmsException if something goes wrong 1770 */ 1771 public CmsPropertyDefinition createPropertyDefinition(CmsDbContext dbc, String name) throws CmsException { 1772 1773 CmsPropertyDefinition propertyDefinition = null; 1774 1775 name = name.trim(); 1776 // validate the property name 1777 CmsPropertyDefinition.checkPropertyName(name); 1778 // TODO: make the type a parameter 1779 try { 1780 try { 1781 propertyDefinition = getVfsDriver(dbc).readPropertyDefinition( 1782 dbc, 1783 name, 1784 dbc.currentProject().getUuid()); 1785 } catch (CmsException e) { 1786 propertyDefinition = getVfsDriver(dbc).createPropertyDefinition( 1787 dbc, 1788 dbc.currentProject().getUuid(), 1789 name, 1790 CmsPropertyDefinition.TYPE_NORMAL); 1791 } 1792 1793 try { 1794 getVfsDriver(dbc).readPropertyDefinition(dbc, name, CmsProject.ONLINE_PROJECT_ID); 1795 } catch (CmsException e) { 1796 getVfsDriver(dbc).createPropertyDefinition( 1797 dbc, 1798 CmsProject.ONLINE_PROJECT_ID, 1799 name, 1800 CmsPropertyDefinition.TYPE_NORMAL); 1801 } 1802 1803 try { 1804 getHistoryDriver(dbc).readPropertyDefinition(dbc, name); 1805 } catch (CmsException e) { 1806 getHistoryDriver(dbc).createPropertyDefinition(dbc, name, CmsPropertyDefinition.TYPE_NORMAL); 1807 } 1808 } finally { 1809 1810 // fire an event that a property of a resource has been deleted 1811 OpenCms.fireCmsEvent( 1812 new CmsEvent( 1813 I_CmsEventListener.EVENT_PROPERTY_DEFINITION_CREATED, 1814 Collections.<String, Object> singletonMap("propertyDefinition", propertyDefinition))); 1815 1816 } 1817 1818 return propertyDefinition; 1819 } 1820 1821 /** 1822 * Creates a new publish job.<p> 1823 * 1824 * @param dbc the current database context 1825 * @param publishJob the publish job to create 1826 * 1827 * @throws CmsException if something goes wrong 1828 */ 1829 public void createPublishJob(CmsDbContext dbc, CmsPublishJobInfoBean publishJob) throws CmsException { 1830 1831 getProjectDriver(dbc).createPublishJob(dbc, publishJob); 1832 } 1833 1834 /** 1835 * Creates a new resource with the provided content and properties.<p> 1836 * 1837 * The <code>content</code> parameter may be <code>null</code> if the resource id 1838 * already exists. If so, the created resource will be a sibling of the existing 1839 * resource, the existing content will remain unchanged.<p> 1840 * 1841 * This is used during file import for import of siblings as the 1842 * <code>manifest.xml</code> only contains one binary copy per file.<p> 1843 * 1844 * If the resource id exists but the <code>content</code> is not <code>null</code>, 1845 * the created resource will be made a sibling of the existing resource, 1846 * and both will share the new content.<p> 1847 * 1848 * @param dbc the current database context 1849 * @param resourcePath the name of the resource to create (full path) 1850 * @param resource the new resource to create 1851 * @param content the content for the new resource 1852 * @param properties the properties for the new resource 1853 * @param importCase if <code>true</code>, signals that this operation is done while 1854 * importing resource, causing different lock behavior and 1855 * potential "lost and found" usage 1856 * 1857 * @return the created resource 1858 * 1859 * @throws CmsException if something goes wrong 1860 */ 1861 public CmsResource createResource( 1862 CmsDbContext dbc, 1863 String resourcePath, 1864 CmsResource resource, 1865 byte[] content, 1866 List<CmsProperty> properties, 1867 boolean importCase) 1868 throws CmsException { 1869 1870 CmsResource newResource = null; 1871 if (resource.isFolder()) { 1872 resourcePath = CmsFileUtil.addTrailingSeparator(resourcePath); 1873 } 1874 1875 try { 1876 synchronized (this) { 1877 // need to provide the parent folder id for resource creation 1878 String parentFolderName = CmsResource.getParentFolder(resourcePath); 1879 CmsResource parentFolder = readFolder(dbc, parentFolderName, CmsResourceFilter.IGNORE_EXPIRATION); 1880 1881 CmsLock parentLock = getLock(dbc, parentFolder); 1882 // it is not allowed to create a resource in a folder locked by other user 1883 if (!parentLock.isUnlocked() && !parentLock.isOwnedBy(dbc.currentUser())) { 1884 // one exception is if the admin user tries to create a temporary resource 1885 if (!CmsResource.getName(resourcePath).startsWith(TEMP_FILE_PREFIX) 1886 || !m_securityManager.hasRole(dbc, dbc.currentUser(), CmsRole.ROOT_ADMIN)) { 1887 throw new CmsLockException( 1888 Messages.get().container( 1889 Messages.ERR_CREATE_RESOURCE_PARENT_LOCK_1, 1890 dbc.removeSiteRoot(resourcePath))); 1891 } 1892 } 1893 if (CmsResourceTypeJsp.isJsp(resource)) { 1894 // security check when trying to create a new jsp file 1895 m_securityManager.checkRoleForResource(dbc, CmsRole.VFS_MANAGER, parentFolder); 1896 } 1897 1898 // check import configuration of "lost and found" folder 1899 boolean useLostAndFound = importCase && !OpenCms.getImportExportManager().overwriteCollidingResources(); 1900 1901 // check if the resource already exists by name 1902 CmsResource currentResourceByName = null; 1903 try { 1904 currentResourceByName = readResource(dbc, resourcePath, CmsResourceFilter.ALL); 1905 } catch (CmsVfsResourceNotFoundException e) { 1906 // if the resource does exist, we have to check the id later to decide what to do 1907 } 1908 1909 // check if the resource already exists by id 1910 try { 1911 CmsResource currentResourceById = readResource( 1912 dbc, 1913 resource.getStructureId(), 1914 CmsResourceFilter.ALL); 1915 // it is not allowed to import resources when there is already a resource with the same id but different path 1916 if (!currentResourceById.getRootPath().equals(resourcePath)) { 1917 throw new CmsVfsResourceAlreadyExistsException( 1918 Messages.get().container( 1919 Messages.ERR_RESOURCE_WITH_ID_ALREADY_EXISTS_3, 1920 dbc.removeSiteRoot(resourcePath), 1921 dbc.removeSiteRoot(currentResourceById.getRootPath()), 1922 currentResourceById.getStructureId())); 1923 } 1924 } catch (CmsVfsResourceNotFoundException e) { 1925 // if the resource does exist, we have to check the id later to decide what to do 1926 } 1927 1928 // check the permissions 1929 if (currentResourceByName == null) { 1930 // resource does not exist - check parent folder 1931 m_securityManager.checkPermissions( 1932 dbc, 1933 parentFolder, 1934 CmsPermissionSet.ACCESS_WRITE, 1935 false, 1936 CmsResourceFilter.IGNORE_EXPIRATION); 1937 } else { 1938 // resource already exists - check existing resource 1939 m_securityManager.checkPermissions( 1940 dbc, 1941 currentResourceByName, 1942 CmsPermissionSet.ACCESS_WRITE, 1943 !importCase, 1944 CmsResourceFilter.ALL); 1945 } 1946 1947 // now look for the resource by name 1948 if (currentResourceByName != null) { 1949 boolean overwrite = true; 1950 if (currentResourceByName.getState().isDeleted()) { 1951 if (!currentResourceByName.isFolder()) { 1952 // if a non-folder resource was deleted it's treated like a new resource 1953 overwrite = false; 1954 } 1955 } else { 1956 if (!importCase) { 1957 // direct "overwrite" of a resource is possible only during import, 1958 // or if the resource has been deleted 1959 throw new CmsVfsResourceAlreadyExistsException( 1960 org.opencms.db.generic.Messages.get().container( 1961 org.opencms.db.generic.Messages.ERR_RESOURCE_WITH_NAME_ALREADY_EXISTS_1, 1962 dbc.removeSiteRoot(resource.getRootPath()))); 1963 } 1964 // the resource already exists 1965 if (!resource.isFolder() 1966 && useLostAndFound 1967 && (!currentResourceByName.getResourceId().equals(resource.getResourceId()))) { 1968 // semantic change: the current resource is moved to L&F and the imported resource will overwrite the old one 1969 // will leave the resource with state deleted, 1970 // but it does not matter, since the state will be set later again 1971 moveToLostAndFound(dbc, currentResourceByName, false); 1972 } 1973 } 1974 if (!overwrite) { 1975 // lock the resource, will throw an exception if not lockable 1976 lockResource(dbc, currentResourceByName, CmsLockType.EXCLUSIVE); 1977 1978 // trigger createResource instead of writeResource 1979 currentResourceByName = null; 1980 } 1981 } 1982 // if null, create new resource, if not null write resource 1983 CmsResource overwrittenResource = currentResourceByName; 1984 1985 // extract the name (without path) 1986 String targetName = CmsResource.getName(resourcePath); 1987 1988 int contentLength; 1989 1990 // modify target name and content length in case of folder creation 1991 if (resource.isFolder()) { 1992 // folders never have any content 1993 contentLength = -1; 1994 // must cut of trailing '/' for folder creation (or name check fails) 1995 if (CmsResource.isFolder(targetName)) { 1996 targetName = targetName.substring(0, targetName.length() - 1); 1997 } 1998 } else { 1999 // otherwise ensure content and content length are set correctly 2000 if (content != null) { 2001 // if a content is provided, in each case the length is the length of this content 2002 contentLength = content.length; 2003 } else if (overwrittenResource != null) { 2004 // we have no content, but an already existing resource - length remains unchanged 2005 contentLength = overwrittenResource.getLength(); 2006 } else { 2007 // we have no content - length is used as set in the resource 2008 contentLength = resource.getLength(); 2009 } 2010 } 2011 2012 // check if the target name is valid (forbidden chars etc.), 2013 // if not throw an exception 2014 // must do this here since targetName is modified in folder case (see above) 2015 CmsResource.checkResourceName(targetName); 2016 2017 // set structure and resource ids as given 2018 CmsUUID structureId = resource.getStructureId(); 2019 CmsUUID resourceId = resource.getResourceId(); 2020 2021 // decide which structure id to use 2022 if (overwrittenResource != null) { 2023 // resource exists, re-use existing ids 2024 structureId = overwrittenResource.getStructureId(); 2025 } 2026 if (structureId.isNullUUID()) { 2027 // need a new structure id 2028 structureId = new CmsUUID(); 2029 } 2030 2031 // decide which resource id to use 2032 if (overwrittenResource != null) { 2033 // if we are overwriting we have to assure the resource id is the same 2034 resourceId = overwrittenResource.getResourceId(); 2035 } 2036 if (resourceId.isNullUUID()) { 2037 // need a new resource id 2038 resourceId = new CmsUUID(); 2039 } 2040 2041 try { 2042 // check online resource 2043 CmsResource onlineResource = getVfsDriver( 2044 dbc).readResource(dbc, CmsProject.ONLINE_PROJECT_ID, resourcePath, true); 2045 // only allow to overwrite with different id if importing (createResource will set the right id) 2046 try { 2047 CmsResource offlineResource = getVfsDriver(dbc).readResource( 2048 dbc, 2049 dbc.currentProject().getUuid(), 2050 onlineResource.getStructureId(), 2051 true); 2052 if (!offlineResource.getRootPath().equals(onlineResource.getRootPath())) { 2053 throw new CmsVfsOnlineResourceAlreadyExistsException( 2054 Messages.get().container( 2055 Messages.ERR_ONLINE_RESOURCE_EXISTS_2, 2056 dbc.removeSiteRoot(resourcePath), 2057 dbc.removeSiteRoot(offlineResource.getRootPath()))); 2058 } 2059 } catch (CmsVfsResourceNotFoundException e) { 2060 // there is no problem for now 2061 // but should never happen 2062 if (LOG.isErrorEnabled()) { 2063 LOG.error(e.getLocalizedMessage(), e); 2064 } 2065 } 2066 } catch (CmsVfsResourceNotFoundException e) { 2067 // ok, there is no online entry to worry about 2068 } 2069 2070 // now create a resource object with all informations 2071 newResource = new CmsResource( 2072 structureId, 2073 resourceId, 2074 resourcePath, 2075 resource.getTypeId(), 2076 resource.isFolder(), 2077 resource.getFlags(), 2078 dbc.currentProject().getUuid(), 2079 resource.getState(), 2080 resource.getDateCreated(), 2081 resource.getUserCreated(), 2082 resource.getDateLastModified(), 2083 resource.getUserLastModified(), 2084 resource.getDateReleased(), 2085 resource.getDateExpired(), 2086 1, 2087 contentLength, 2088 resource.getDateContent(), 2089 resource.getVersion()); // version number does not matter since it will be computed later 2090 2091 // ensure date is updated only if required 2092 if (resource.isTouched()) { 2093 // this will trigger the internal "is touched" state on the new resource 2094 newResource.setDateLastModified(resource.getDateLastModified()); 2095 } 2096 2097 if (resource.isFile()) { 2098 // check if a sibling to the imported resource lies in a marked site 2099 if (labelResource(dbc, resource, resourcePath, 2)) { 2100 int flags = resource.getFlags(); 2101 flags |= CmsResource.FLAG_LABELED; 2102 resource.setFlags(flags); 2103 } 2104 // ensure siblings don't overwrite existing resource records 2105 if (content == null) { 2106 newResource.setState(CmsResource.STATE_KEEP); 2107 } 2108 } 2109 2110 // delete all relations for the resource, before writing the content 2111 getVfsDriver( 2112 dbc).deleteRelations(dbc, dbc.currentProject().getUuid(), newResource, CmsRelationFilter.TARGETS); 2113 if (overwrittenResource == null) { 2114 CmsLock lock = getLock(dbc, newResource); 2115 if (lock.getEditionLock().isExclusive()) { 2116 unlockResource(dbc, newResource, true, false); 2117 } 2118 // resource does not exist. 2119 newResource = getVfsDriver( 2120 dbc).createResource(dbc, dbc.currentProject().getUuid(), newResource, content); 2121 } else { 2122 // resource already exists. 2123 // probably the resource is a merged page file that gets overwritten during import, or it gets 2124 // overwritten by a copy operation. if so, the structure & resource state are not modified to changed. 2125 int updateStates = (overwrittenResource.getState().isNew() 2126 ? CmsDriverManager.NOTHING_CHANGED 2127 : CmsDriverManager.UPDATE_ALL); 2128 getVfsDriver(dbc).writeResource(dbc, dbc.currentProject().getUuid(), newResource, updateStates); 2129 2130 if ((content != null) && resource.isFile()) { 2131 // also update file content if required 2132 getVfsDriver(dbc).writeContent(dbc, newResource.getResourceId(), content); 2133 } 2134 } 2135 2136 // write the properties (internal operation, no events or duplicate permission checks) 2137 writePropertyObjects(dbc, newResource, properties, false); 2138 2139 // lock the created resource 2140 try { 2141 // if it is locked by another user (copied or moved resource) this lock should be preserved and 2142 // the exception is OK: locks on created resources are a slave feature to original locks 2143 lockResource(dbc, newResource, CmsLockType.EXCLUSIVE); 2144 } catch (CmsLockException cle) { 2145 if (LOG.isDebugEnabled()) { 2146 LOG.debug( 2147 Messages.get().getBundle().key( 2148 Messages.ERR_CREATE_RESOURCE_LOCK_1, 2149 new Object[] {dbc.removeSiteRoot(newResource.getRootPath())})); 2150 } 2151 } 2152 2153 if (!importCase) { 2154 log( 2155 dbc, 2156 new CmsLogEntry( 2157 dbc, 2158 newResource.getStructureId(), 2159 CmsLogEntryType.RESOURCE_CREATED, 2160 new String[] {resource.getRootPath()}), 2161 false); 2162 } else { 2163 log( 2164 dbc, 2165 new CmsLogEntry( 2166 dbc, 2167 newResource.getStructureId(), 2168 CmsLogEntryType.RESOURCE_IMPORTED, 2169 new String[] {resource.getRootPath()}), 2170 false); 2171 } 2172 } 2173 } finally { 2174 // clear the internal caches 2175 m_monitor.clearAccessControlListCache(); 2176 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); 2177 2178 if (newResource != null) { 2179 // fire an event that a new resource has been created 2180 OpenCms.fireCmsEvent( 2181 new CmsEvent( 2182 I_CmsEventListener.EVENT_RESOURCE_CREATED, 2183 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, newResource))); 2184 } 2185 } 2186 return newResource; 2187 } 2188 2189 /** 2190 * Creates a new resource of the given resource type 2191 * with the provided content and properties.<p> 2192 * 2193 * If the provided content is null and the resource is not a folder, 2194 * the content will be set to an empty byte array.<p> 2195 * 2196 * @param dbc the current database context 2197 * @param resourcename the name of the resource to create (full path) 2198 * @param type the type of the resource to create 2199 * @param content the content for the new resource 2200 * @param properties the properties for the new resource 2201 * 2202 * @return the created resource 2203 * 2204 * @throws CmsException if something goes wrong 2205 * @throws CmsIllegalArgumentException if the <code>resourcename</code> argument is null or of length 0 2206 * 2207 * @see CmsObject#createResource(String, int, byte[], List) 2208 * @see CmsObject#createResource(String, int) 2209 * @see I_CmsResourceType#createResource(CmsObject, CmsSecurityManager, String, byte[], List) 2210 */ 2211 @SuppressWarnings("javadoc") 2212 public CmsResource createResource( 2213 CmsDbContext dbc, 2214 String resourcename, 2215 int type, 2216 byte[] content, 2217 List<CmsProperty> properties) 2218 throws CmsException, CmsIllegalArgumentException { 2219 2220 String targetName = resourcename; 2221 2222 if (content == null) { 2223 // name based resource creation MUST have a content 2224 content = new byte[0]; 2225 } 2226 int size; 2227 2228 if (CmsFolder.isFolderType(type)) { 2229 // must cut of trailing '/' for folder creation 2230 if (CmsResource.isFolder(targetName)) { 2231 targetName = targetName.substring(0, targetName.length() - 1); 2232 } 2233 size = -1; 2234 } else { 2235 size = content.length; 2236 } 2237 2238 // create a new resource 2239 CmsResource newResource = new CmsResource( 2240 CmsUUID.getNullUUID(), // uuids will be "corrected" later 2241 CmsUUID.getNullUUID(), 2242 targetName, 2243 type, 2244 CmsFolder.isFolderType(type), 2245 0, 2246 dbc.currentProject().getUuid(), 2247 CmsResource.STATE_NEW, 2248 0, 2249 dbc.currentUser().getId(), 2250 0, 2251 dbc.currentUser().getId(), 2252 CmsResource.DATE_RELEASED_DEFAULT, 2253 CmsResource.DATE_EXPIRED_DEFAULT, 2254 1, 2255 size, 2256 0, // version number does not matter since it will be computed later 2257 0); // content time will be corrected later 2258 2259 return createResource(dbc, targetName, newResource, content, properties, false); 2260 } 2261 2262 /** 2263 * Creates a new sibling of the source resource.<p> 2264 * 2265 * @param dbc the current database context 2266 * @param source the resource to create a sibling for 2267 * @param destination the name of the sibling to create with complete path 2268 * @param properties the individual properties for the new sibling 2269 * 2270 * @return the new created sibling 2271 * 2272 * @throws CmsException if something goes wrong 2273 * 2274 * @see CmsObject#createSibling(String, String, List) 2275 * @see I_CmsResourceType#createSibling(CmsObject, CmsSecurityManager, CmsResource, String, List) 2276 */ 2277 public CmsResource createSibling( 2278 CmsDbContext dbc, 2279 CmsResource source, 2280 String destination, 2281 List<CmsProperty> properties) 2282 throws CmsException { 2283 2284 if (source.isFolder()) { 2285 throw new CmsVfsException(Messages.get().container(Messages.ERR_VFS_FOLDERS_DONT_SUPPORT_SIBLINGS_0)); 2286 } 2287 2288 // determine destination folder and resource name 2289 String destinationFoldername = CmsResource.getParentFolder(destination); 2290 2291 // read the destination folder (will also check read permissions) 2292 CmsFolder destinationFolder = readFolder(dbc, destinationFoldername, CmsResourceFilter.IGNORE_EXPIRATION); 2293 2294 // no further permission check required here, will be done in createResource() 2295 2296 // check the resource flags 2297 int flags = source.getFlags(); 2298 if (labelResource(dbc, source, destination, 1)) { 2299 // set "labeled" link flag for new resource 2300 flags |= CmsResource.FLAG_LABELED; 2301 } 2302 2303 // create the new resource 2304 CmsResource newResource = new CmsResource( 2305 new CmsUUID(), 2306 source.getResourceId(), 2307 destination, 2308 source.getTypeId(), 2309 source.isFolder(), 2310 flags, 2311 dbc.currentProject().getUuid(), 2312 CmsResource.STATE_KEEP, 2313 source.getDateCreated(), // ensures current resource record remains untouched 2314 source.getUserCreated(), 2315 source.getDateLastModified(), 2316 source.getUserLastModified(), 2317 source.getDateReleased(), 2318 source.getDateExpired(), 2319 source.getSiblingCount() + 1, 2320 source.getLength(), 2321 source.getDateContent(), 2322 source.getVersion()); // version number does not matter since it will be computed later 2323 2324 // trigger "is touched" state on resource (will ensure modification date is kept unchanged) 2325 newResource.setDateLastModified(newResource.getDateLastModified()); 2326 2327 log( 2328 dbc, 2329 new CmsLogEntry( 2330 dbc, 2331 newResource.getStructureId(), 2332 CmsLogEntryType.RESOURCE_CLONED, 2333 new String[] {newResource.getRootPath()}), 2334 false); 2335 // create the resource (null content signals creation of sibling) 2336 newResource = createResource(dbc, destination, newResource, null, properties, false); 2337 2338 // copy relations 2339 copyRelations(dbc, source, newResource); 2340 2341 // clear the caches 2342 m_monitor.clearAccessControlListCache(); 2343 2344 List<CmsResource> modifiedResources = new ArrayList<CmsResource>(); 2345 modifiedResources.add(source); 2346 modifiedResources.add(newResource); 2347 modifiedResources.add(destinationFolder); 2348 Map<String, Object> eventData = new HashMap<>(); 2349 eventData.put(I_CmsEventListener.KEY_RESOURCES, modifiedResources); 2350 eventData.put(I_CmsEventListener.KEY_CHANGE, I_CmsEventListener.VALUE_CREATE_SIBLING); 2351 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCES_AND_PROPERTIES_MODIFIED, eventData)); 2352 2353 return newResource; 2354 } 2355 2356 /** 2357 * Creates the project for the temporary workplace files.<p> 2358 * 2359 * @param dbc the current database context 2360 * 2361 * @return the created project for the temporary workplace files 2362 * 2363 * @throws CmsException if something goes wrong 2364 */ 2365 public CmsProject createTempfileProject(CmsDbContext dbc) throws CmsException { 2366 2367 // read the needed groups from the cms 2368 CmsGroup projectUserGroup = readGroup(dbc, dbc.currentProject().getGroupId()); 2369 CmsGroup projectManagerGroup = readGroup(dbc, dbc.currentProject().getManagerGroupId()); 2370 2371 CmsProject tempProject = getProjectDriver(dbc).createProject( 2372 dbc, 2373 new CmsUUID(), 2374 dbc.currentUser(), 2375 projectUserGroup, 2376 projectManagerGroup, 2377 I_CmsProjectDriver.TEMP_FILE_PROJECT_NAME, 2378 Messages.get().getBundle(dbc.getRequestContext().getLocale()).key( 2379 Messages.GUI_WORKPLACE_TEMPFILE_PROJECT_DESC_0), 2380 CmsProject.PROJECT_FLAG_HIDDEN, 2381 CmsProject.PROJECT_TYPE_NORMAL); 2382 getProjectDriver(dbc).createProjectResource(dbc, tempProject.getUuid(), "/"); 2383 2384 OpenCms.fireCmsEvent( 2385 new CmsEvent( 2386 I_CmsEventListener.EVENT_PROJECT_MODIFIED, 2387 Collections.<String, Object> singletonMap("project", tempProject))); 2388 2389 return tempProject; 2390 } 2391 2392 /** 2393 * Creates a new user.<p> 2394 * 2395 * @param dbc the current database context 2396 * @param name the name for the new user 2397 * @param password the password for the new user 2398 * @param description the description for the new user 2399 * @param additionalInfos the additional infos for the user 2400 * 2401 * @return the created user 2402 * 2403 * @see CmsObject#createUser(String, String, String, Map) 2404 * 2405 * @throws CmsException if something goes wrong 2406 * @throws CmsIllegalArgumentException if the name for the user is not valid 2407 */ 2408 public CmsUser createUser( 2409 CmsDbContext dbc, 2410 String name, 2411 String password, 2412 String description, 2413 Map<String, Object> additionalInfos) 2414 throws CmsException, CmsIllegalArgumentException { 2415 2416 // no space before or after the name 2417 name = name.trim(); 2418 // check the user name 2419 String userName = CmsOrganizationalUnit.getSimpleName(name); 2420 OpenCms.getValidationHandler().checkUserName(userName); 2421 if (CmsStringUtil.isEmptyOrWhitespaceOnly(userName)) { 2422 throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_BAD_USER_1, userName)); 2423 } 2424 // check the ou 2425 CmsOrganizationalUnit ou = readOrganizationalUnit(dbc, CmsOrganizationalUnit.getParentFqn(name)); 2426 // check the password 2427 validatePassword(password); 2428 2429 Map<String, Object> info = new HashMap<String, Object>(); 2430 if (additionalInfos != null) { 2431 info.putAll(additionalInfos); 2432 } 2433 if (description != null) { 2434 info.put(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION, description); 2435 } 2436 int flags = 0; 2437 if (ou.hasFlagWebuser()) { 2438 flags += I_CmsPrincipal.FLAG_USER_WEBUSER; 2439 } 2440 CmsUser user = getUserDriver(dbc).createUser( 2441 dbc, 2442 new CmsUUID(), 2443 name, 2444 OpenCms.getPasswordHandler().digest(password), 2445 " ", 2446 " ", 2447 " ", 2448 0, 2449 I_CmsPrincipal.FLAG_ENABLED + flags, 2450 0, 2451 info); 2452 2453 if (!dbc.getProjectId().isNullUUID()) { 2454 // user modified event is not needed 2455 return user; 2456 } 2457 // fire user modified event 2458 Map<String, Object> eventData = new HashMap<String, Object>(); 2459 eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); 2460 eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_CREATE_USER); 2461 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); 2462 return user; 2463 } 2464 2465 /** 2466 * Deletes aliases indicated by a filter.<p> 2467 * 2468 * @param dbc the current database context 2469 * @param project the current project 2470 * @param filter the filter which describes which aliases to delete 2471 * 2472 * @throws CmsException if something goes wrong 2473 */ 2474 public void deleteAliases(CmsDbContext dbc, CmsProject project, CmsAliasFilter filter) throws CmsException { 2475 2476 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 2477 vfsDriver.deleteAliases(dbc, project, filter); 2478 } 2479 2480 /** 2481 * Deletes all property values of a file or folder.<p> 2482 * 2483 * If there are no other siblings than the specified resource, 2484 * both the structure and resource property values get deleted. 2485 * If the specified resource has siblings, only the structure 2486 * property values get deleted.<p> 2487 * 2488 * @param dbc the current database context 2489 * @param resourcename the name of the resource for which all properties should be deleted 2490 * 2491 * @throws CmsException if operation was not successful 2492 */ 2493 public void deleteAllProperties(CmsDbContext dbc, String resourcename) throws CmsException { 2494 2495 CmsResource resource = null; 2496 List<CmsResource> resources = new ArrayList<CmsResource>(); 2497 2498 try { 2499 // read the resource 2500 resource = readResource(dbc, resourcename, CmsResourceFilter.IGNORE_EXPIRATION); 2501 2502 // check the security 2503 m_securityManager.checkPermissions( 2504 dbc, 2505 resource, 2506 CmsPermissionSet.ACCESS_WRITE, 2507 false, 2508 CmsResourceFilter.ALL); 2509 2510 // delete the property values 2511 if (resource.getSiblingCount() > 1) { 2512 // the resource has siblings- delete only the (structure) properties of this sibling 2513 getVfsDriver(dbc).deletePropertyObjects( 2514 dbc, 2515 dbc.currentProject().getUuid(), 2516 resource, 2517 CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_VALUES); 2518 resources.addAll(readSiblings(dbc, resource, CmsResourceFilter.ALL)); 2519 2520 } else { 2521 // the resource has no other siblings- delete all (structure+resource) properties 2522 getVfsDriver(dbc).deletePropertyObjects( 2523 dbc, 2524 dbc.currentProject().getUuid(), 2525 resource, 2526 CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES); 2527 resources.add(resource); 2528 } 2529 } finally { 2530 // clear the driver manager cache 2531 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); 2532 2533 // fire an event that all properties of a resource have been deleted 2534 OpenCms.fireCmsEvent( 2535 new CmsEvent( 2536 I_CmsEventListener.EVENT_RESOURCES_AND_PROPERTIES_MODIFIED, 2537 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCES, resources))); 2538 } 2539 } 2540 2541 /** 2542 * Deletes all entries in the published resource table.<p> 2543 * 2544 * @param dbc the current database context 2545 * @param linkType the type of resource deleted (0= non-paramter, 1=parameter) 2546 * 2547 * @throws CmsException if something goes wrong 2548 */ 2549 public void deleteAllStaticExportPublishedResources(CmsDbContext dbc, int linkType) throws CmsException { 2550 2551 getProjectDriver(dbc).deleteAllStaticExportPublishedResources(dbc, linkType); 2552 } 2553 2554 /** 2555 * Deletes a group, where all permissions, users and children of the group 2556 * are transfered to a replacement group.<p> 2557 * 2558 * @param dbc the current request context 2559 * @param group the id of the group to be deleted 2560 * @param replacementId the id of the group to be transfered, can be <code>null</code> 2561 * 2562 * @throws CmsException if operation was not successful 2563 * @throws CmsDataAccessException if group to be deleted contains user 2564 */ 2565 public void deleteGroup(CmsDbContext dbc, CmsGroup group, CmsUUID replacementId) 2566 throws CmsDataAccessException, CmsException { 2567 2568 CmsGroup replacementGroup = null; 2569 if (replacementId != null) { 2570 replacementGroup = readGroup(dbc, replacementId); 2571 } 2572 // get all child groups of the group 2573 List<CmsGroup> children = getChildren(dbc, group, false); 2574 // get all users in this group 2575 List<CmsUser> users = getUsersOfGroup(dbc, group.getName(), true, true, group.isRole()); 2576 // get online project 2577 CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); 2578 if (replacementGroup == null) { 2579 // remove users 2580 Iterator<CmsUser> itUsers = users.iterator(); 2581 while (itUsers.hasNext()) { 2582 CmsUser user = itUsers.next(); 2583 if (userInGroup(dbc, user.getName(), group.getName(), group.isRole())) { 2584 removeUserFromGroup(dbc, user.getName(), group.getName(), group.isRole()); 2585 } 2586 } 2587 // transfer children to grandfather if possible 2588 CmsUUID parentId = group.getParentId(); 2589 if (parentId == null) { 2590 parentId = CmsUUID.getNullUUID(); 2591 } 2592 Iterator<CmsGroup> itChildren = children.iterator(); 2593 while (itChildren.hasNext()) { 2594 CmsGroup child = itChildren.next(); 2595 child.setParentId(parentId); 2596 writeGroup(dbc, child); 2597 } 2598 } else { 2599 // move children 2600 Iterator<CmsGroup> itChildren = children.iterator(); 2601 while (itChildren.hasNext()) { 2602 CmsGroup child = itChildren.next(); 2603 child.setParentId(replacementId); 2604 writeGroup(dbc, child); 2605 } 2606 // move users 2607 Iterator<CmsUser> itUsers = users.iterator(); 2608 while (itUsers.hasNext()) { 2609 CmsUser user = itUsers.next(); 2610 addUserToGroup(dbc, user.getName(), replacementGroup.getName(), group.isRole()); 2611 removeUserFromGroup(dbc, user.getName(), group.getName(), group.isRole()); 2612 } 2613 // transfer for offline 2614 transferPrincipalResources(dbc, dbc.currentProject(), group.getId(), replacementId, true); 2615 // transfer for online 2616 transferPrincipalResources(dbc, onlineProject, group.getId(), replacementId, true); 2617 } 2618 // remove the group 2619 getUserDriver( 2620 dbc).removeAccessControlEntriesForPrincipal(dbc, dbc.currentProject(), onlineProject, group.getId()); 2621 getUserDriver(dbc).deleteGroup(dbc, group.getName()); 2622 // backup the group 2623 getHistoryDriver(dbc).writePrincipal(dbc, group); 2624 if (OpenCms.getSubscriptionManager().isEnabled()) { 2625 // delete all subscribed resources for group 2626 unsubscribeAllResourcesFor(dbc, OpenCms.getSubscriptionManager().getPoolName(), group); 2627 } 2628 2629 // clear the relevant caches 2630 m_monitor.uncacheGroup(group); 2631 m_monitor.flushCache( 2632 CmsMemoryMonitor.CacheType.USERGROUPS, 2633 CmsMemoryMonitor.CacheType.USER_LIST, 2634 CmsMemoryMonitor.CacheType.ACL); 2635 2636 if (!dbc.getProjectId().isNullUUID()) { 2637 // group modified event is not needed 2638 return; 2639 } 2640 // fire group modified event 2641 Map<String, Object> eventData = new HashMap<String, Object>(); 2642 eventData.put(I_CmsEventListener.KEY_GROUP_ID, group.getId().toString()); 2643 eventData.put(I_CmsEventListener.KEY_GROUP_NAME, group.getName()); 2644 eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_GROUP_MODIFIED_ACTION_DELETE); 2645 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_GROUP_MODIFIED, eventData)); 2646 } 2647 2648 /** 2649 * Deletes the versions from the history tables, keeping the given number of versions per resource.<p> 2650 * 2651 * if the <code>cleanUp</code> option is set, additionally versions of deleted resources will be removed.<p> 2652 * 2653 * @param dbc the current database context 2654 * @param versionsToKeep number of versions to keep, is ignored if negative 2655 * @param versionsDeleted number of versions to keep for deleted resources, is ignored if negative 2656 * @param timeDeleted deleted resources older than this will also be deleted, is ignored if negative 2657 * @param report the report for output logging 2658 * 2659 * @throws CmsException if operation was not successful 2660 */ 2661 public void deleteHistoricalVersions( 2662 CmsDbContext dbc, 2663 int versionsToKeep, 2664 int versionsDeleted, 2665 long timeDeleted, 2666 I_CmsReport report) 2667 throws CmsException { 2668 2669 report.println(Messages.get().container(Messages.RPT_START_DELETE_VERSIONS_0), I_CmsReport.FORMAT_HEADLINE); 2670 if (versionsToKeep >= 0) { 2671 report.println( 2672 Messages.get().container(Messages.RPT_START_DELETE_ACT_VERSIONS_1, new Integer(versionsToKeep)), 2673 I_CmsReport.FORMAT_HEADLINE); 2674 2675 List<I_CmsHistoryResource> resources = getHistoryDriver(dbc).getAllNotDeletedEntries(dbc); 2676 if (resources.isEmpty()) { 2677 report.println(Messages.get().container(Messages.RPT_DELETE_NOTHING_0), I_CmsReport.FORMAT_OK); 2678 } 2679 int n = resources.size(); 2680 int m = 1; 2681 Iterator<I_CmsHistoryResource> itResources = resources.iterator(); 2682 while (itResources.hasNext()) { 2683 I_CmsHistoryResource histResource = itResources.next(); 2684 2685 report.print( 2686 org.opencms.report.Messages.get().container( 2687 org.opencms.report.Messages.RPT_SUCCESSION_2, 2688 String.valueOf(m), 2689 String.valueOf(n)), 2690 I_CmsReport.FORMAT_NOTE); 2691 report.print( 2692 org.opencms.report.Messages.get().container( 2693 org.opencms.report.Messages.RPT_ARGUMENT_1, 2694 dbc.removeSiteRoot(histResource.getRootPath()))); 2695 report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); 2696 2697 try { 2698 int deleted = getHistoryDriver(dbc).deleteEntries(dbc, histResource, versionsToKeep, -1); 2699 2700 report.print( 2701 Messages.get().container(Messages.RPT_VERSION_DELETING_1, new Integer(deleted)), 2702 I_CmsReport.FORMAT_NOTE); 2703 report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); 2704 report.println( 2705 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), 2706 I_CmsReport.FORMAT_OK); 2707 } catch (CmsDataAccessException e) { 2708 report.println( 2709 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_ERROR_0), 2710 I_CmsReport.FORMAT_ERROR); 2711 2712 if (LOG.isDebugEnabled()) { 2713 LOG.debug(e.getLocalizedMessage(), e); 2714 } 2715 } 2716 2717 m++; 2718 } 2719 2720 report.println( 2721 Messages.get().container(Messages.RPT_END_DELETE_ACT_VERSIONS_0), 2722 I_CmsReport.FORMAT_HEADLINE); 2723 } 2724 if ((versionsDeleted >= 0) || (timeDeleted >= 0)) { 2725 if (timeDeleted >= 0) { 2726 report.println( 2727 Messages.get().container( 2728 Messages.RPT_START_DELETE_DEL_VERSIONS_2, 2729 new Integer(versionsDeleted), 2730 new Date(timeDeleted)), 2731 I_CmsReport.FORMAT_HEADLINE); 2732 } else { 2733 report.println( 2734 Messages.get().container(Messages.RPT_START_DELETE_DEL_VERSIONS_1, new Integer(versionsDeleted)), 2735 I_CmsReport.FORMAT_HEADLINE); 2736 } 2737 List<I_CmsHistoryResource> resources = getHistoryDriver(dbc).getAllDeletedEntries(dbc); 2738 if (resources.isEmpty()) { 2739 report.println(Messages.get().container(Messages.RPT_DELETE_NOTHING_0), I_CmsReport.FORMAT_OK); 2740 } 2741 int n = resources.size(); 2742 int m = 1; 2743 Iterator<I_CmsHistoryResource> itResources = resources.iterator(); 2744 while (itResources.hasNext()) { 2745 I_CmsHistoryResource histResource = itResources.next(); 2746 2747 report.print( 2748 org.opencms.report.Messages.get().container( 2749 org.opencms.report.Messages.RPT_SUCCESSION_2, 2750 String.valueOf(m), 2751 String.valueOf(n)), 2752 I_CmsReport.FORMAT_NOTE); 2753 report.print( 2754 org.opencms.report.Messages.get().container( 2755 org.opencms.report.Messages.RPT_ARGUMENT_1, 2756 dbc.removeSiteRoot(histResource.getRootPath()))); 2757 report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); 2758 2759 try { 2760 int deleted = getHistoryDriver(dbc).deleteEntries(dbc, histResource, versionsDeleted, timeDeleted); 2761 2762 report.print( 2763 Messages.get().container(Messages.RPT_VERSION_DELETING_1, new Integer(deleted)), 2764 I_CmsReport.FORMAT_NOTE); 2765 report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); 2766 report.println( 2767 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), 2768 I_CmsReport.FORMAT_OK); 2769 } catch (CmsDataAccessException e) { 2770 report.println( 2771 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_ERROR_0), 2772 I_CmsReport.FORMAT_ERROR); 2773 2774 if (LOG.isDebugEnabled()) { 2775 LOG.debug(e.getLocalizedMessage(), e); 2776 } 2777 } 2778 2779 m++; 2780 } 2781 report.println( 2782 Messages.get().container(Messages.RPT_END_DELETE_DEL_VERSIONS_0), 2783 I_CmsReport.FORMAT_HEADLINE); 2784 } 2785 report.println(Messages.get().container(Messages.RPT_END_DELETE_VERSIONS_0), I_CmsReport.FORMAT_HEADLINE); 2786 } 2787 2788 /** 2789 * Deletes all log entries matching the given filter.<p> 2790 * 2791 * @param dbc the current db context 2792 * @param filter the filter to use for deletion 2793 * 2794 * @throws CmsException if something goes wrong 2795 * 2796 * @see CmsSecurityManager#deleteLogEntries(CmsRequestContext, CmsLogFilter) 2797 */ 2798 public void deleteLogEntries(CmsDbContext dbc, CmsLogFilter filter) throws CmsException { 2799 2800 updateLog(dbc); 2801 m_projectDriver.deleteLog(dbc, filter); 2802 } 2803 2804 /** 2805 * Deletes an organizational unit.<p> 2806 * 2807 * Only organizational units that contain no suborganizational unit can be deleted.<p> 2808 * 2809 * The organizational unit can not be delete if it is used in the request context, 2810 * or if the current user belongs to it.<p> 2811 * 2812 * All users and groups in the given organizational unit will be deleted.<p> 2813 * 2814 * @param dbc the current db context 2815 * @param organizationalUnit the organizational unit to delete 2816 * 2817 * @throws CmsException if operation was not successful 2818 * 2819 * @see org.opencms.security.CmsOrgUnitManager#deleteOrganizationalUnit(CmsObject, String) 2820 */ 2821 public void deleteOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit organizationalUnit) 2822 throws CmsException { 2823 2824 // check organizational unit in context 2825 if (dbc.getRequestContext().getOuFqn().equals(organizationalUnit.getName())) { 2826 throw new CmsDbConsistencyException( 2827 Messages.get().container(Messages.ERR_ORGUNIT_DELETE_IN_CONTEXT_1, organizationalUnit.getName())); 2828 } 2829 // check organizational unit for user 2830 if (dbc.currentUser().getOuFqn().equals(organizationalUnit.getName())) { 2831 throw new CmsDbConsistencyException( 2832 Messages.get().container(Messages.ERR_ORGUNIT_DELETE_CURRENT_USER_1, organizationalUnit.getName())); 2833 } 2834 // check sub organizational units 2835 if (!getOrganizationalUnits(dbc, organizationalUnit, true).isEmpty()) { 2836 throw new CmsDbConsistencyException( 2837 Messages.get().container(Messages.ERR_ORGUNIT_DELETE_SUB_ORGUNITS_1, organizationalUnit.getName())); 2838 } 2839 // check groups 2840 List<CmsGroup> groups = getGroups(dbc, organizationalUnit, true, false); 2841 Iterator<CmsGroup> itGroups = groups.iterator(); 2842 while (itGroups.hasNext()) { 2843 CmsGroup group = itGroups.next(); 2844 if (!OpenCms.getDefaultUsers().isDefaultGroup(group.getName())) { 2845 throw new CmsDbConsistencyException( 2846 Messages.get().container(Messages.ERR_ORGUNIT_DELETE_GROUPS_1, organizationalUnit.getName())); 2847 } 2848 } 2849 // check users 2850 if (!getUsers(dbc, organizationalUnit, true).isEmpty()) { 2851 throw new CmsDbConsistencyException( 2852 Messages.get().container(Messages.ERR_ORGUNIT_DELETE_USERS_1, organizationalUnit.getName())); 2853 } 2854 2855 // delete default groups if needed 2856 itGroups = groups.iterator(); 2857 while (itGroups.hasNext()) { 2858 CmsGroup group = itGroups.next(); 2859 deleteGroup(dbc, group, null); 2860 } 2861 2862 // delete projects 2863 Iterator<CmsProject> itProjects = getProjectDriver(dbc).readProjects( 2864 dbc, 2865 organizationalUnit.getName()).iterator(); 2866 while (itProjects.hasNext()) { 2867 CmsProject project = itProjects.next(); 2868 deleteProject(dbc, project, false); 2869 } 2870 2871 // delete roles 2872 Iterator<CmsGroup> itRoles = getGroups(dbc, organizationalUnit, true, true).iterator(); 2873 while (itRoles.hasNext()) { 2874 CmsGroup role = itRoles.next(); 2875 deleteGroup(dbc, role, null); 2876 } 2877 2878 // create a publish list for the 'virtual' publish event 2879 CmsResource resource = readResource(dbc, organizationalUnit.getId(), CmsResourceFilter.DEFAULT); 2880 CmsPublishList pl = new CmsPublishList(resource, false); 2881 pl.add(resource, false); 2882 2883 // remove the organizational unit itself 2884 getUserDriver(dbc).deleteOrganizationalUnit(dbc, organizationalUnit); 2885 2886 // write the publish history entry 2887 getProjectDriver(dbc).writePublishHistory( 2888 dbc, 2889 pl.getPublishHistoryId(), 2890 new CmsPublishedResource(resource, -1, CmsResourceState.STATE_DELETED)); 2891 2892 // flush relevant caches 2893 m_monitor.clearPrincipalsCache(); 2894 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); 2895 2896 // fire the 'virtual' publish event 2897 Map<String, Object> eventData = new HashMap<String, Object>(); 2898 eventData.put(I_CmsEventListener.KEY_PUBLISHID, pl.getPublishHistoryId().toString()); 2899 eventData.put(I_CmsEventListener.KEY_PROJECTID, dbc.currentProject().getUuid()); 2900 eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); 2901 CmsEvent afterPublishEvent = new CmsEvent(I_CmsEventListener.EVENT_PUBLISH_PROJECT, eventData); 2902 OpenCms.fireCmsEvent(afterPublishEvent); 2903 2904 m_lockManager.removeDeletedResource(dbc, resource.getRootPath()); 2905 2906 if (!dbc.getProjectId().isNullUUID()) { 2907 // OU modified event is not needed 2908 return; 2909 } 2910 // fire OU modified event 2911 Map<String, Object> event2Data = new HashMap<String, Object>(); 2912 event2Data.put(I_CmsEventListener.KEY_OU_NAME, organizationalUnit.getName()); 2913 event2Data.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_OU_MODIFIED_ACTION_DELETE); 2914 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_OU_MODIFIED, event2Data)); 2915 2916 } 2917 2918 /** 2919 * Deletes a project.<p> 2920 * 2921 * Only the admin or the owner of the project can do this. 2922 * 2923 * @param dbc the current database context 2924 * @param deleteProject the project to be deleted 2925 * 2926 * @throws CmsException if something goes wrong 2927 */ 2928 public void deleteProject(CmsDbContext dbc, CmsProject deleteProject) throws CmsException { 2929 2930 deleteProject(dbc, deleteProject, true); 2931 } 2932 2933 /** 2934 * Deletes a project.<p> 2935 * 2936 * Only the admin or the owner of the project can do this. 2937 * 2938 * @param dbc the current database context 2939 * @param deleteProject the project to be deleted 2940 * @param resetResources if true, the resources of the project to delete will be reset to their online state, or deleted if they have no online state 2941 * 2942 * @throws CmsException if something goes wrong 2943 */ 2944 public void deleteProject(CmsDbContext dbc, CmsProject deleteProject, boolean resetResources) throws CmsException { 2945 2946 CmsUUID projectId = deleteProject.getUuid(); 2947 2948 if (resetResources) { 2949 // changed/new/deleted files in the specified project 2950 List<CmsResource> modifiedFiles = readChangedResourcesInsideProject(dbc, projectId, RCPRM_FILES_ONLY_MODE); 2951 // changed/new/deleted folders in the specified project 2952 List<CmsResource> modifiedFolders = readChangedResourcesInsideProject( 2953 dbc, 2954 projectId, 2955 RCPRM_FOLDERS_ONLY_MODE); 2956 resetResourcesInProject(dbc, projectId, modifiedFiles, modifiedFolders); 2957 } 2958 2959 // unlock all resources in the project 2960 m_lockManager.removeResourcesInProject(deleteProject.getUuid(), true); 2961 m_monitor.clearAccessControlListCache(); 2962 m_monitor.clearResourceCache(); 2963 2964 // set project to online project if current project is the one which will be deleted 2965 if (projectId.equals(dbc.currentProject().getUuid())) { 2966 dbc.getRequestContext().setCurrentProject(readProject(dbc, CmsProject.ONLINE_PROJECT_ID)); 2967 } 2968 2969 // delete the project itself 2970 getProjectDriver(dbc).deleteProject(dbc, deleteProject); 2971 m_monitor.uncacheProject(deleteProject); 2972 2973 // fire the corresponding event 2974 OpenCms.fireCmsEvent( 2975 new CmsEvent( 2976 I_CmsEventListener.EVENT_PROJECT_MODIFIED, 2977 Collections.<String, Object> singletonMap("project", deleteProject))); 2978 2979 } 2980 2981 /** 2982 * Deletes a property definition.<p> 2983 * 2984 * @param dbc the current database context 2985 * @param name the name of the property definition to delete 2986 * 2987 * @throws CmsException if something goes wrong 2988 */ 2989 public void deletePropertyDefinition(CmsDbContext dbc, String name) throws CmsException { 2990 2991 CmsPropertyDefinition propertyDefinition = null; 2992 2993 try { 2994 // first read and then delete the metadefinition. 2995 propertyDefinition = readPropertyDefinition(dbc, name); 2996 getVfsDriver(dbc).deletePropertyDefinition(dbc, propertyDefinition); 2997 getHistoryDriver(dbc).deletePropertyDefinition(dbc, propertyDefinition); 2998 } finally { 2999 3000 // fire an event that a property of a resource has been deleted 3001 OpenCms.fireCmsEvent( 3002 new CmsEvent( 3003 I_CmsEventListener.EVENT_PROPERTY_DEFINITION_MODIFIED, 3004 Collections.<String, Object> singletonMap("propertyDefinition", propertyDefinition))); 3005 } 3006 } 3007 3008 /** 3009 * Deletes a publish job identified by its history id.<p> 3010 * 3011 * @param dbc the current database context 3012 * @param publishHistoryId the history id identifying the publish job 3013 * 3014 * @throws CmsException if something goes wrong 3015 */ 3016 public void deletePublishJob(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { 3017 3018 getProjectDriver(dbc).deletePublishJob(dbc, publishHistoryId); 3019 } 3020 3021 /** 3022 * Deletes the publish list assigned to a publish job.<p> 3023 * 3024 * @param dbc the current database context 3025 * @param publishHistoryId the history id identifying the publish job 3026 * @throws CmsException if something goes wrong 3027 */ 3028 public void deletePublishList(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { 3029 3030 getProjectDriver(dbc).deletePublishList(dbc, publishHistoryId); 3031 } 3032 3033 /** 3034 * Deletes all relations for the given resource matching the given filter.<p> 3035 * 3036 * @param dbc the current db context 3037 * @param resource the resource to delete the relations for 3038 * @param filter the filter to use for deletion 3039 * 3040 * @throws CmsException if something goes wrong 3041 * 3042 * @see CmsSecurityManager#deleteRelationsForResource(CmsRequestContext, CmsResource, CmsRelationFilter) 3043 */ 3044 public void deleteRelationsForResource(CmsDbContext dbc, CmsResource resource, CmsRelationFilter filter) 3045 throws CmsException { 3046 3047 if (filter.includesDefinedInContent()) { 3048 throw new CmsIllegalArgumentException( 3049 Messages.get().container( 3050 Messages.ERR_DELETE_RELATION_IN_CONTENT_2, 3051 dbc.removeSiteRoot(resource.getRootPath()), 3052 filter.getTypes())); 3053 } 3054 getVfsDriver(dbc).deleteRelations(dbc, dbc.currentProject().getUuid(), resource, filter); 3055 setDateLastModified(dbc, resource, System.currentTimeMillis()); 3056 log( 3057 dbc, 3058 new CmsLogEntry( 3059 dbc, 3060 resource.getStructureId(), 3061 CmsLogEntryType.RESOURCE_REMOVE_RELATION, 3062 new String[] {resource.getRootPath(), filter.toString()}), 3063 false); 3064 } 3065 3066 /** 3067 * Deletes a resource.<p> 3068 * 3069 * The <code>siblingMode</code> parameter controls how to handle siblings 3070 * during the delete operation. 3071 * Possible values for this parameter are: 3072 * <ul> 3073 * <li><code>{@link CmsResource#DELETE_REMOVE_SIBLINGS}</code></li> 3074 * <li><code>{@link CmsResource#DELETE_PRESERVE_SIBLINGS}</code></li> 3075 * </ul><p> 3076 * 3077 * @param dbc the current database context 3078 * @param resource the name of the resource to delete (full path) 3079 * @param siblingMode indicates how to handle siblings of the deleted resource 3080 * 3081 * @throws CmsException if something goes wrong 3082 * 3083 * @see CmsObject#deleteResource(String, CmsResource.CmsResourceDeleteMode) 3084 * @see I_CmsResourceType#deleteResource(CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceDeleteMode) 3085 */ 3086 public void deleteResource(CmsDbContext dbc, CmsResource resource, CmsResource.CmsResourceDeleteMode siblingMode) 3087 throws CmsException { 3088 3089 // upgrade a potential inherited, non-shared lock into a common lock 3090 CmsLock currentLock = getLock(dbc, resource); 3091 if (currentLock.getEditionLock().isDirectlyInherited()) { 3092 // upgrade the lock status if required 3093 lockResource(dbc, resource, CmsLockType.EXCLUSIVE); 3094 } 3095 3096 // check if siblings of the resource exist and must be deleted as well 3097 if (resource.isFolder()) { 3098 // folder can have no siblings 3099 siblingMode = CmsResource.DELETE_PRESERVE_SIBLINGS; 3100 } 3101 3102 // if selected, add all siblings of this resource to the list of resources to be deleted 3103 boolean allSiblingsRemoved; 3104 List<CmsResource> resources; 3105 if (siblingMode == CmsResource.DELETE_REMOVE_SIBLINGS) { 3106 resources = new ArrayList<CmsResource>(readSiblings(dbc, resource, CmsResourceFilter.ALL)); 3107 allSiblingsRemoved = true; 3108 3109 // ensure that the resource requested to be deleted is the last resource that gets actually deleted 3110 // to keep the shared locks of the siblings while those get deleted. 3111 resources.remove(resource); 3112 resources.add(resource); 3113 } else { 3114 // only delete the resource, no siblings 3115 resources = Collections.singletonList(resource); 3116 allSiblingsRemoved = false; 3117 } 3118 3119 int size = resources.size(); 3120 // if we have only one resource no further check is required 3121 if (size > 1) { 3122 CmsMultiException me = new CmsMultiException(); 3123 // ensure that each sibling is unlocked or locked by the current user 3124 for (int i = 0; i < size; i++) { 3125 CmsResource currentResource = resources.get(i); 3126 currentLock = getLock(dbc, currentResource); 3127 if (!currentLock.getEditionLock().isUnlocked() && !currentLock.isOwnedBy(dbc.currentUser())) { 3128 // the resource is locked by a user different from the current user 3129 CmsRequestContext context = dbc.getRequestContext(); 3130 me.addException( 3131 new CmsLockException( 3132 org.opencms.lock.Messages.get().container( 3133 org.opencms.lock.Messages.ERR_SIBLING_LOCKED_2, 3134 context.getSitePath(currentResource), 3135 context.getSitePath(resource)))); 3136 } 3137 } 3138 if (!me.getExceptions().isEmpty()) { 3139 throw me; 3140 } 3141 } 3142 3143 boolean removeAce = true; 3144 3145 if (resource.isFolder()) { 3146 // check if the folder has any resources in it 3147 Iterator<CmsResource> childResources = getVfsDriver( 3148 dbc).readChildResources(dbc, dbc.currentProject(), resource, true, true).iterator(); 3149 3150 CmsUUID projectId = CmsProject.ONLINE_PROJECT_ID; 3151 if (dbc.currentProject().isOnlineProject()) { 3152 projectId = CmsUUID.getOpenCmsUUID(); // HACK: to get an offline project id 3153 } 3154 3155 // collect the names of the resources inside the folder, excluding the moved resources 3156 StringBuffer errorResNames = new StringBuffer(128); 3157 while (childResources.hasNext()) { 3158 CmsResource errorRes = childResources.next(); 3159 if (errorRes.getState().isDeleted()) { 3160 continue; 3161 } 3162 // if deleting offline, or not moved, or just renamed inside the deleted folder 3163 // so, it may remain some orphan online entries for moved resources 3164 // which will be fixed during the publishing of the moved resources 3165 boolean error = !dbc.currentProject().isOnlineProject(); 3166 if (!error) { 3167 try { 3168 String originalPath = getVfsDriver( 3169 dbc).readResource(dbc, projectId, errorRes.getRootPath(), true).getRootPath(); 3170 error = originalPath.equals(errorRes.getRootPath()) 3171 || originalPath.startsWith(resource.getRootPath()); 3172 } catch (CmsVfsResourceNotFoundException e) { 3173 // ignore 3174 } 3175 } 3176 if (error) { 3177 if (errorResNames.length() != 0) { 3178 errorResNames.append(", "); 3179 } 3180 errorResNames.append("[" + dbc.removeSiteRoot(errorRes.getRootPath()) + "]"); 3181 } 3182 } 3183 3184 // the current implementation only deletes empty folders 3185 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(errorResNames.toString())) { 3186 throw new CmsVfsException( 3187 org.opencms.db.generic.Messages.get().container( 3188 org.opencms.db.generic.Messages.ERR_DELETE_NONEMTY_FOLDER_2, 3189 dbc.removeSiteRoot(resource.getRootPath()), 3190 errorResNames.toString())); 3191 } 3192 } 3193 3194 // delete all collected resources 3195 for (int i = 0; i < size; i++) { 3196 CmsResource currentResource = resources.get(i); 3197 3198 // try to delete/remove the resource only if the user has write access to the resource 3199 // check permissions only for the sibling, the resource it self was already checked or 3200 // is to be removed without write permissions, ie. while deleting a folder 3201 if (!currentResource.equals(resource) 3202 && (I_CmsPermissionHandler.PERM_ALLOWED != m_securityManager.hasPermissions( 3203 dbc, 3204 currentResource, 3205 CmsPermissionSet.ACCESS_WRITE, 3206 LockCheck.yes, 3207 CmsResourceFilter.ALL))) { 3208 3209 // no write access to sibling - must keep ACE (see below) 3210 allSiblingsRemoved = false; 3211 } else { 3212 // write access to sibling granted 3213 boolean existsOnline = (getVfsDriver(dbc).validateStructureIdExists( 3214 dbc, 3215 CmsProject.ONLINE_PROJECT_ID, 3216 currentResource.getStructureId()) || !(currentResource.getState().equals(CmsResource.STATE_NEW))); 3217 if (!existsOnline) { 3218 // the resource does not exist online => remove the resource 3219 // this means the resource is "new" (blue) in the offline project 3220 3221 // delete all properties of this resource 3222 deleteAllProperties(dbc, currentResource.getRootPath()); 3223 3224 if (currentResource.isFolder()) { 3225 getVfsDriver(dbc).removeFolder(dbc, dbc.currentProject(), currentResource); 3226 } else { 3227 // check labels 3228 if (currentResource.isLabeled() && !labelResource(dbc, currentResource, null, 2)) { 3229 // update the resource flags to "un label" the other siblings 3230 int flags = currentResource.getFlags(); 3231 flags &= ~CmsResource.FLAG_LABELED; 3232 currentResource.setFlags(flags); 3233 } 3234 getVfsDriver(dbc).removeFile(dbc, dbc.currentProject().getUuid(), currentResource); 3235 } 3236 3237 // ensure an exclusive lock is removed in the lock manager for a deleted new resource, 3238 // otherwise it would "stick" in the lock manager, preventing other users from creating 3239 // a file with the same name (issue with temp files in editor) 3240 m_lockManager.removeDeletedResource(dbc, currentResource.getRootPath()); 3241 // delete relations 3242 getVfsDriver(dbc).deleteRelations( 3243 dbc, 3244 dbc.currentProject().getUuid(), 3245 currentResource, 3246 CmsRelationFilter.TARGETS); 3247 getVfsDriver(dbc).deleteUrlNameMappingEntries( 3248 dbc, 3249 false, 3250 CmsUrlNameMappingFilter.ALL.filterStructureId(currentResource.getStructureId())); 3251 getVfsDriver(dbc).deleteAliases( 3252 dbc, 3253 dbc.currentProject(), 3254 new CmsAliasFilter(null, null, currentResource.getStructureId())); 3255 log( 3256 dbc, 3257 new CmsLogEntry( 3258 dbc, 3259 currentResource.getStructureId(), 3260 CmsLogEntryType.RESOURCE_NEW_DELETED, 3261 new String[] {currentResource.getRootPath()}), 3262 true); 3263 } else { 3264 // the resource exists online => mark the resource as deleted 3265 // structure record is removed during next publish 3266 // if one (or more) siblings are not removed, the ACE can not be removed 3267 removeAce = false; 3268 // set resource state to deleted 3269 currentResource.setState(CmsResource.STATE_DELETED); 3270 getVfsDriver( 3271 dbc).writeResourceState(dbc, dbc.currentProject(), currentResource, UPDATE_STRUCTURE, false); 3272 3273 // update the project ID 3274 getVfsDriver(dbc).writeLastModifiedProjectId( 3275 dbc, 3276 dbc.currentProject(), 3277 dbc.currentProject().getUuid(), 3278 currentResource); 3279 // log it 3280 3281 log( 3282 dbc, 3283 new CmsLogEntry( 3284 dbc, 3285 currentResource.getStructureId(), 3286 CmsLogEntryType.RESOURCE_DELETED, 3287 new String[] {currentResource.getRootPath()}), 3288 true); 3289 } 3290 } 3291 } 3292 3293 if ((resource.getSiblingCount() <= 1) || allSiblingsRemoved) { 3294 if (removeAce) { 3295 // remove the access control entries 3296 getUserDriver(dbc).removeAccessControlEntries(dbc, dbc.currentProject(), resource.getResourceId()); 3297 } 3298 } 3299 3300 // flush all caches 3301 m_monitor.clearAccessControlListCache(); 3302 m_monitor.flushCache( 3303 CmsMemoryMonitor.CacheType.PROPERTY, 3304 CmsMemoryMonitor.CacheType.PROPERTY_LIST, 3305 CmsMemoryMonitor.CacheType.PROJECT_RESOURCES); 3306 3307 Map<String, Object> eventData = new HashMap<String, Object>(); 3308 eventData.put(I_CmsEventListener.KEY_RESOURCES, resources); 3309 eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); 3310 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_DELETED, eventData)); 3311 } 3312 3313 /** 3314 * Deletes an entry in the published resource table.<p> 3315 * 3316 * @param dbc the current database context 3317 * @param resourceName The name of the resource to be deleted in the static export 3318 * @param linkType the type of resource deleted (0= non-parameter, 1=parameter) 3319 * @param linkParameter the parameters of the resource 3320 * 3321 * @throws CmsException if something goes wrong 3322 */ 3323 public void deleteStaticExportPublishedResource( 3324 CmsDbContext dbc, 3325 String resourceName, 3326 int linkType, 3327 String linkParameter) 3328 throws CmsException { 3329 3330 getProjectDriver(dbc).deleteStaticExportPublishedResource(dbc, resourceName, linkType, linkParameter); 3331 } 3332 3333 /** 3334 * Deletes a user, where all permissions and resources attributes of the user 3335 * were transfered to a replacement user, if given.<p> 3336 * 3337 * Only users, which are in the group "administrators" are granted.<p> 3338 * 3339 * @param dbc the current database context 3340 * @param project the current project 3341 * @param username the name of the user to be deleted 3342 * @param replacementUsername the name of the user to be transfered, can be <code>null</code> 3343 * 3344 * @throws CmsException if operation was not successful 3345 */ 3346 public void deleteUser(CmsDbContext dbc, CmsProject project, String username, String replacementUsername) 3347 throws CmsException { 3348 3349 // Test if the users exists 3350 CmsUser user = readUser(dbc, username); 3351 CmsUser replacementUser = null; 3352 if (replacementUsername != null) { 3353 replacementUser = readUser(dbc, replacementUsername); 3354 } 3355 3356 CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); 3357 boolean withACEs = true; 3358 if (replacementUser == null) { 3359 withACEs = false; 3360 replacementUser = readUser(dbc, OpenCms.getDefaultUsers().getUserDeletedResource()); 3361 } 3362 3363 boolean isVfsManager = m_securityManager.hasRole(dbc, replacementUser, CmsRole.VFS_MANAGER); 3364 3365 // iterate groups and roles 3366 for (int i = 0; i < 2; i++) { 3367 boolean readRoles = i != 0; 3368 Iterator<CmsGroup> itGroups = getGroupsOfUser( 3369 dbc, 3370 username, 3371 "", 3372 true, 3373 readRoles, 3374 true, 3375 dbc.getRequestContext().getRemoteAddress()).iterator(); 3376 while (itGroups.hasNext()) { 3377 CmsGroup group = itGroups.next(); 3378 if (!isVfsManager) { 3379 // add replacement user to user groups 3380 if (!userInGroup(dbc, replacementUser.getName(), group.getName(), readRoles)) { 3381 addUserToGroup(dbc, replacementUser.getName(), group.getName(), readRoles); 3382 } 3383 } 3384 // remove user from groups 3385 if (userInGroup(dbc, username, group.getName(), readRoles)) { 3386 // we need this additional check because removing a user from a group 3387 // may also automatically remove him from other groups if the group was 3388 // associated with a role. 3389 removeUserFromGroup(dbc, username, group.getName(), readRoles); 3390 } 3391 } 3392 } 3393 // remove all locks set for the deleted user 3394 m_lockManager.removeLocks(user.getId()); 3395 // offline 3396 if (dbc.getProjectId().isNullUUID()) { 3397 // offline project available 3398 transferPrincipalResources(dbc, project, user.getId(), replacementUser.getId(), withACEs); 3399 } 3400 // online 3401 transferPrincipalResources(dbc, onlineProject, user.getId(), replacementUser.getId(), withACEs); 3402 getUserDriver(dbc).removeAccessControlEntriesForPrincipal(dbc, project, onlineProject, user.getId()); 3403 getHistoryDriver(dbc).writePrincipal(dbc, user); 3404 getUserDriver(dbc).deleteUser(dbc, username); 3405 // delete user from cache 3406 m_monitor.clearUserCache(user); 3407 3408 if (!dbc.getProjectId().isNullUUID()) { 3409 // user modified event is not needed 3410 return; 3411 } 3412 // fire user modified event 3413 Map<String, Object> eventData = new HashMap<String, Object>(); 3414 eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); 3415 eventData.put(I_CmsEventListener.KEY_USER_NAME, user.getName()); 3416 eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_DELETE_USER); 3417 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); 3418 } 3419 3420 /** 3421 * Destroys this driver manager and releases all allocated resources.<p> 3422 */ 3423 public void destroy() { 3424 3425 try { 3426 if (m_projectDriver != null) { 3427 try { 3428 m_projectDriver.destroy(); 3429 } catch (Throwable t) { 3430 LOG.error(Messages.get().getBundle().key(Messages.ERR_CLOSE_PROJECT_DRIVER_0), t); 3431 } 3432 m_projectDriver = null; 3433 } 3434 if (m_userDriver != null) { 3435 try { 3436 m_userDriver.destroy(); 3437 } catch (Throwable t) { 3438 LOG.error(Messages.get().getBundle().key(Messages.ERR_CLOSE_USER_DRIVER_0), t); 3439 } 3440 m_userDriver = null; 3441 } 3442 if (m_vfsDriver != null) { 3443 try { 3444 m_vfsDriver.destroy(); 3445 } catch (Throwable t) { 3446 LOG.error(Messages.get().getBundle().key(Messages.ERR_CLOSE_VFS_DRIVER_0), t); 3447 } 3448 m_vfsDriver = null; 3449 } 3450 if (m_historyDriver != null) { 3451 try { 3452 m_historyDriver.destroy(); 3453 } catch (Throwable t) { 3454 LOG.error(Messages.get().getBundle().key(Messages.ERR_CLOSE_HISTORY_DRIVER_0), t); 3455 } 3456 m_historyDriver = null; 3457 } 3458 3459 if (m_pools != null) { 3460 for (CmsDbPoolV11 pool : m_pools.values()) { 3461 try { 3462 pool.close(); 3463 if (CmsLog.INIT.isDebugEnabled()) { 3464 CmsLog.INIT.debug(Messages.get().getBundle().key(Messages.INIT_CLOSE_CONN_POOL_1, pool)); 3465 } 3466 3467 } catch (Throwable t) { 3468 LOG.error(Messages.get().getBundle().key(Messages.LOG_CLOSE_CONN_POOL_ERROR_1, pool), t); 3469 } 3470 } 3471 m_pools.clear(); 3472 } 3473 3474 m_monitor.clearCache(); 3475 3476 m_lockManager = null; 3477 m_htmlLinkValidator = null; 3478 } catch (Throwable t) { 3479 // ignore 3480 } 3481 if (CmsLog.INIT.isInfoEnabled()) { 3482 CmsLog.INIT.info( 3483 Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_DESTROY_1, getClass().getName())); 3484 } 3485 } 3486 3487 /** 3488 * Tests if a resource with the given resourceId does already exist in the Database.<p> 3489 * 3490 * @param dbc the current database context 3491 * @param resourceId the resource id to test for 3492 * @return true if a resource with the given id was found, false otherweise 3493 * @throws CmsException if something goes wrong 3494 */ 3495 public boolean existsResourceId(CmsDbContext dbc, CmsUUID resourceId) throws CmsException { 3496 3497 return getVfsDriver(dbc).validateResourceIdExists(dbc, dbc.currentProject().getUuid(), resourceId); 3498 } 3499 3500 /** 3501 * Fills the given publish list with the the VFS resources that actually get published.<p> 3502 * 3503 * Please refer to the source code of this method for the rules on how to decide whether a 3504 * new/changed/deleted <code>{@link CmsResource}</code> object can be published or not.<p> 3505 * 3506 * @param dbc the current database context 3507 * @param publishList must be initialized with basic publish information (Project or direct publish operation), 3508 * the given publish list will be filled with all new/changed/deleted files from the current 3509 * (offline) project that will be actually published 3510 * 3511 * @throws CmsException if something goes wrong 3512 * 3513 * @see org.opencms.db.CmsPublishList 3514 */ 3515 public void fillPublishList(CmsDbContext dbc, CmsPublishList publishList) throws CmsException { 3516 3517 if (!publishList.isDirectPublish()) { 3518 // when publishing a project 3519 // all modified resources with the last change done in the current project are candidates if unlocked 3520 List<CmsResource> folderList = getVfsDriver(dbc).readResourceTree( 3521 dbc, 3522 dbc.currentProject().getUuid(), 3523 CmsDriverManager.READ_IGNORE_PARENT, 3524 CmsDriverManager.READ_IGNORE_TYPE, 3525 CmsResource.STATE_UNCHANGED, 3526 CmsDriverManager.READ_IGNORE_TIME, 3527 CmsDriverManager.READ_IGNORE_TIME, 3528 CmsDriverManager.READ_IGNORE_TIME, 3529 CmsDriverManager.READ_IGNORE_TIME, 3530 CmsDriverManager.READ_IGNORE_TIME, 3531 CmsDriverManager.READ_IGNORE_TIME, 3532 CmsDriverManager.READMODE_INCLUDE_TREE 3533 | CmsDriverManager.READMODE_INCLUDE_PROJECT 3534 | CmsDriverManager.READMODE_EXCLUDE_STATE 3535 | CmsDriverManager.READMODE_ONLY_FOLDERS); 3536 3537 List<CmsResource> fileList = getVfsDriver(dbc).readResourceTree( 3538 dbc, 3539 dbc.currentProject().getUuid(), 3540 CmsDriverManager.READ_IGNORE_PARENT, 3541 CmsDriverManager.READ_IGNORE_TYPE, 3542 CmsResource.STATE_UNCHANGED, 3543 CmsDriverManager.READ_IGNORE_TIME, 3544 CmsDriverManager.READ_IGNORE_TIME, 3545 CmsDriverManager.READ_IGNORE_TIME, 3546 CmsDriverManager.READ_IGNORE_TIME, 3547 CmsDriverManager.READ_IGNORE_TIME, 3548 CmsDriverManager.READ_IGNORE_TIME, 3549 CmsDriverManager.READMODE_INCLUDE_TREE 3550 | CmsDriverManager.READMODE_INCLUDE_PROJECT 3551 | CmsDriverManager.READMODE_EXCLUDE_STATE 3552 | CmsDriverManager.READMODE_ONLY_FILES); 3553 CmsRequestContext context = dbc.getRequestContext(); 3554 if ((context != null) 3555 && (context.getAttribute(CmsDefaultWorkflowManager.ATTR_CHECK_PUBLISH_RESOURCE_LIMIT) != null)) { 3556 3557 // check if total size and if it exceeds the resource limit and the request 3558 // context attribute is set, throw an exception. 3559 // we do it here since filterResources() can be very expensive on large resource lists 3560 3561 int limit = OpenCms.getWorkflowManager().getResourceLimit(); 3562 int total = fileList.size() + folderList.size(); 3563 if (total > limit) { 3564 throw new CmsTooManyPublishResourcesException(total); 3565 } 3566 } 3567 publishList.addAll(filterResources(dbc, null, folderList), true); 3568 publishList.addAll(filterResources(dbc, publishList, fileList), true); 3569 } else { 3570 // this is a direct publish 3571 Iterator<CmsResource> it = publishList.getDirectPublishResources().iterator(); 3572 while (it.hasNext()) { 3573 // iterate all resources in the direct publish list 3574 CmsResource directPublishResource = it.next(); 3575 if (directPublishResource.isFolder()) { 3576 // when publishing a folder directly, 3577 // the folder and all modified resources within the tree below this folder 3578 // and with the last change done in the current project are candidates if lockable 3579 CmsLock lock = getLock(dbc, directPublishResource); 3580 if (!directPublishResource.getState().isUnchanged() && lock.isLockableBy(dbc.currentUser())) { 3581 3582 try { 3583 m_securityManager.checkPermissions( 3584 dbc, 3585 directPublishResource, 3586 CmsPermissionSet.ACCESS_DIRECT_PUBLISH, 3587 false, 3588 CmsResourceFilter.ALL); 3589 publishList.add(directPublishResource, true); 3590 } catch (CmsException e) { 3591 // skip if not enough permissions 3592 } 3593 } 3594 boolean shouldPublishDeletedSubResources = publishList.isUserPublishList() 3595 && directPublishResource.getState().isDeleted(); 3596 if (publishList.isPublishSubResources() || shouldPublishDeletedSubResources) { 3597 addSubResources(dbc, publishList, directPublishResource, resource -> true); 3598 } 3599 } else if (directPublishResource.isFile() && !directPublishResource.getState().isUnchanged()) { 3600 3601 // when publishing a file directly this file is the only candidate 3602 // if it is modified and lockable 3603 CmsLock lock = getLock(dbc, directPublishResource); 3604 if (lock.isLockableBy(dbc.currentUser())) { 3605 // check permissions 3606 try { 3607 m_securityManager.checkPermissions( 3608 dbc, 3609 directPublishResource, 3610 CmsPermissionSet.ACCESS_DIRECT_PUBLISH, 3611 false, 3612 CmsResourceFilter.ALL); 3613 publishList.add(directPublishResource, true); 3614 } catch (CmsException e) { 3615 // skip if not enough permissions 3616 } 3617 } 3618 } 3619 } 3620 } 3621 3622 // Step 2: if desired, extend the list of files to publish with related siblings 3623 if (publishList.isPublishSiblings()) { 3624 List<CmsResource> publishFiles = publishList.getFileList(); 3625 int size = publishFiles.size(); 3626 3627 // Improved: first calculate closure of all siblings, then filter and add them 3628 Set<CmsResource> siblingsClosure = new HashSet<CmsResource>(publishFiles); 3629 for (int i = 0; i < size; i++) { 3630 CmsResource currentFile = publishFiles.get(i); 3631 if (currentFile.getSiblingCount() > 1) { 3632 siblingsClosure.addAll(readSiblings(dbc, currentFile, CmsResourceFilter.ALL_MODIFIED)); 3633 } 3634 } 3635 publishList.addAll(filterSiblings(dbc, publishList, siblingsClosure), true); 3636 } 3637 publishList.initialize(); 3638 } 3639 3640 /** 3641 * Returns the list of access control entries of a resource given its name.<p> 3642 * 3643 * @param dbc the current database context 3644 * @param resource the resource to read the access control entries for 3645 * @param getInherited true if the result should include all access control entries inherited by parent folders 3646 * 3647 * @return a list of <code>{@link CmsAccessControlEntry}</code> objects defining all permissions for the given resource 3648 * 3649 * @throws CmsException if something goes wrong 3650 */ 3651 public List<CmsAccessControlEntry> getAccessControlEntries( 3652 CmsDbContext dbc, 3653 CmsResource resource, 3654 boolean getInherited) 3655 throws CmsException { 3656 3657 // get the ACE of the resource itself 3658 I_CmsUserDriver userDriver = getUserDriver(dbc); 3659 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 3660 List<CmsAccessControlEntry> ace = userDriver.readAccessControlEntries( 3661 dbc, 3662 dbc.currentProject(), 3663 resource.getResourceId(), 3664 false); 3665 3666 // sort and check if we got the 'overwrite all' ace to stop looking up 3667 boolean overwriteAll = sortAceList(ace); 3668 3669 // get the ACE of each parent folder 3670 // Note: for the immediate parent, get non-inherited access control entries too, 3671 // if the resource is not a folder 3672 String parentPath = CmsResource.getParentFolder(resource.getRootPath()); 3673 int d = (resource.isFolder()) ? 1 : 0; 3674 3675 while (!overwriteAll && getInherited && (parentPath != null)) { 3676 resource = vfsDriver.readFolder(dbc, dbc.currentProject().getUuid(), parentPath); 3677 List<CmsAccessControlEntry> entries = userDriver.readAccessControlEntries( 3678 dbc, 3679 dbc.currentProject(), 3680 resource.getResourceId(), 3681 d > 0); 3682 3683 // sort and check if we got the 'overwrite all' ace to stop looking up 3684 overwriteAll = sortAceList(entries); 3685 3686 for (CmsAccessControlEntry e : entries) { 3687 e.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_INHERITED); 3688 } 3689 3690 ace.addAll(entries); 3691 parentPath = CmsResource.getParentFolder(resource.getRootPath()); 3692 d++; 3693 } 3694 3695 return ace; 3696 } 3697 3698 /** 3699 * Returns the full access control list of a given resource.<p> 3700 * 3701 * @param dbc the current database context 3702 * @param resource the resource 3703 * 3704 * @return the access control list of the resource 3705 * 3706 * @throws CmsException if something goes wrong 3707 */ 3708 public CmsAccessControlList getAccessControlList(CmsDbContext dbc, CmsResource resource) throws CmsException { 3709 3710 return getAccessControlList(dbc, resource, false); 3711 } 3712 3713 /** 3714 * Returns the access control list of a given resource.<p> 3715 * 3716 * If <code>inheritedOnly</code> is set, only inherited access control entries 3717 * are returned.<p> 3718 * 3719 * Note: For file resources, *all* permissions set at the immediate parent folder are inherited, 3720 * not only these marked to inherit. 3721 * 3722 * @param dbc the current database context 3723 * @param resource the resource 3724 * @param inheritedOnly skip non-inherited entries if set 3725 * 3726 * @return the access control list of the resource 3727 * 3728 * @throws CmsException if something goes wrong 3729 */ 3730 public CmsAccessControlList getAccessControlList(CmsDbContext dbc, CmsResource resource, boolean inheritedOnly) 3731 throws CmsException { 3732 3733 return getAccessControlList(dbc, resource, inheritedOnly, resource.isFolder(), 0); 3734 } 3735 3736 /** 3737 * Returns the number of active connections managed by a pool.<p> 3738 * 3739 * @param dbPoolUrl the url of a pool 3740 * @return the number of active connections 3741 * @throws CmsDbException if something goes wrong 3742 */ 3743 public int getActiveConnections(String dbPoolUrl) throws CmsDbException { 3744 3745 CmsDbPoolV11 pool = m_pools.get(dbPoolUrl); 3746 if (pool == null) { 3747 CmsMessageContainer message = Messages.get().container(Messages.ERR_UNKNOWN_POOL_URL_1, dbPoolUrl); 3748 throw new CmsDbException(message); 3749 } 3750 try { 3751 return pool.getActiveConnections(); 3752 } catch (Exception exc) { 3753 CmsMessageContainer message = Messages.get().container(Messages.ERR_ACCESSING_POOL_1, dbPoolUrl); 3754 throw new CmsDbException(message, exc); 3755 } 3756 3757 } 3758 3759 /** 3760 * Reads all access control entries.<p> 3761 * 3762 * @param dbc the current database context 3763 * @return all access control entries for the current project (offline/online) 3764 * 3765 * @throws CmsException if something goes wrong 3766 */ 3767 public List<CmsAccessControlEntry> getAllAccessControlEntries(CmsDbContext dbc) throws CmsException { 3768 3769 I_CmsUserDriver userDriver = getUserDriver(dbc); 3770 List<CmsAccessControlEntry> ace = userDriver.readAccessControlEntries( 3771 dbc, 3772 dbc.currentProject(), 3773 CmsAccessControlEntry.PRINCIPAL_READALL_ID, 3774 false); 3775 return ace; 3776 } 3777 3778 /** 3779 * Returns all projects which are owned by the current user or which are 3780 * accessible by the current user.<p> 3781 * 3782 * @param dbc the current database context 3783 * @param orgUnit the organizational unit to search project in 3784 * @param includeSubOus if to include sub organizational units 3785 * 3786 * @return a list of objects of type <code>{@link CmsProject}</code> 3787 * 3788 * @throws CmsException if something goes wrong 3789 */ 3790 public List<CmsProject> getAllAccessibleProjects( 3791 CmsDbContext dbc, 3792 CmsOrganizationalUnit orgUnit, 3793 boolean includeSubOus) 3794 throws CmsException { 3795 3796 Set<CmsProject> projects = new HashSet<CmsProject>(); 3797 3798 // get the ous where the user has the project manager role 3799 List<CmsOrganizationalUnit> ous = getOrgUnitsForRole( 3800 dbc, 3801 CmsRole.PROJECT_MANAGER.forOrgUnit(orgUnit.getName()), 3802 includeSubOus); 3803 3804 // get the groups of the user if needed 3805 Set<CmsUUID> userGroupIds = new HashSet<CmsUUID>(); 3806 Iterator<CmsGroup> itGroups = getGroupsOfUser(dbc, dbc.currentUser().getName(), false).iterator(); 3807 while (itGroups.hasNext()) { 3808 CmsGroup group = itGroups.next(); 3809 userGroupIds.add(group.getId()); 3810 } 3811 3812 // TODO: this could be optimize if this method would have an additional parameter 'includeSubOus' 3813 // get all projects that might come in question 3814 projects.addAll(getProjectDriver(dbc).readProjects(dbc, orgUnit.getName())); 3815 3816 // filter hidden and not accessible projects 3817 Iterator<CmsProject> itProjects = projects.iterator(); 3818 while (itProjects.hasNext()) { 3819 CmsProject project = itProjects.next(); 3820 boolean accessible = true; 3821 // if hidden 3822 accessible = accessible && !project.isHidden(); 3823 3824 if (!includeSubOus) { 3825 // if not exact in the given ou 3826 accessible = accessible && project.getOuFqn().equals(orgUnit.getName()); 3827 } else { 3828 // if not in the given ou 3829 accessible = accessible && project.getOuFqn().startsWith(orgUnit.getName()); 3830 } 3831 3832 if (!accessible) { 3833 itProjects.remove(); 3834 continue; 3835 } 3836 3837 accessible = false; 3838 // online project 3839 accessible = accessible || project.isOnlineProject(); 3840 // if owner 3841 accessible = accessible || project.getOwnerId().equals(dbc.currentUser().getId()); 3842 3843 // project managers 3844 Iterator<CmsOrganizationalUnit> itOus = ous.iterator(); 3845 while (!accessible && itOus.hasNext()) { 3846 CmsOrganizationalUnit ou = itOus.next(); 3847 // for project managers check visibility 3848 accessible = accessible || project.getOuFqn().startsWith(ou.getName()); 3849 } 3850 3851 if (!accessible) { 3852 // if direct user or manager of project 3853 CmsUUID groupId = null; 3854 if (userGroupIds.contains(project.getGroupId())) { 3855 groupId = project.getGroupId(); 3856 } else if (userGroupIds.contains(project.getManagerGroupId())) { 3857 groupId = project.getManagerGroupId(); 3858 } 3859 if (groupId != null) { 3860 String oufqn = readGroup(dbc, groupId).getOuFqn(); 3861 accessible = accessible || (oufqn.startsWith(dbc.getRequestContext().getOuFqn())); 3862 } 3863 } 3864 if (!accessible) { 3865 // remove not accessible project 3866 itProjects.remove(); 3867 } 3868 } 3869 3870 List<CmsProject> accessibleProjects = new ArrayList<CmsProject>(projects); 3871 // sort the list of projects based on the project name 3872 Collections.sort(accessibleProjects); 3873 // ensure the online project is in first place 3874 CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); 3875 if (accessibleProjects.contains(onlineProject)) { 3876 accessibleProjects.remove(onlineProject); 3877 } 3878 accessibleProjects.add(0, onlineProject); 3879 3880 return accessibleProjects; 3881 } 3882 3883 /** 3884 * Returns a list with all projects from history.<p> 3885 * 3886 * @param dbc the current database context 3887 * 3888 * @return list of <code>{@link CmsHistoryProject}</code> objects 3889 * with all projects from history. 3890 * 3891 * @throws CmsException if operation was not successful 3892 */ 3893 public List<CmsHistoryProject> getAllHistoricalProjects(CmsDbContext dbc) throws CmsException { 3894 3895 // user is allowed to access all existing projects for the ous he has the project_manager role 3896 Set<CmsOrganizationalUnit> manOus = new HashSet<CmsOrganizationalUnit>( 3897 getOrgUnitsForRole(dbc, CmsRole.PROJECT_MANAGER, true)); 3898 3899 List<CmsHistoryProject> projects = getHistoryDriver(dbc).readProjects(dbc); 3900 Iterator<CmsHistoryProject> itProjects = projects.iterator(); 3901 while (itProjects.hasNext()) { 3902 CmsHistoryProject project = itProjects.next(); 3903 if (project.isHidden()) { 3904 // project is hidden 3905 itProjects.remove(); 3906 continue; 3907 } 3908 if (!project.getOuFqn().startsWith(dbc.currentUser().getOuFqn())) { 3909 // project is not visible from the users ou 3910 itProjects.remove(); 3911 continue; 3912 } 3913 CmsOrganizationalUnit ou = readOrganizationalUnit(dbc, project.getOuFqn()); 3914 if (manOus.contains(ou)) { 3915 // user is project manager for this project 3916 continue; 3917 } else if (project.getOwnerId().equals(dbc.currentUser().getId())) { 3918 // user is owner of the project 3919 continue; 3920 } else { 3921 boolean found = false; 3922 Iterator<CmsGroup> itGroups = getGroupsOfUser(dbc, dbc.currentUser().getName(), false).iterator(); 3923 while (itGroups.hasNext()) { 3924 CmsGroup group = itGroups.next(); 3925 if (project.getManagerGroupId().equals(group.getId())) { 3926 found = true; 3927 break; 3928 } 3929 } 3930 if (found) { 3931 // user is member of the manager group of the project 3932 continue; 3933 } 3934 } 3935 itProjects.remove(); 3936 } 3937 return projects; 3938 } 3939 3940 /** 3941 * Returns all projects which are owned by the current user or which are manageable 3942 * for the group of the user.<p> 3943 * 3944 * @param dbc the current database context 3945 * @param orgUnit the organizational unit to search project in 3946 * @param includeSubOus if to include sub organizational units 3947 * 3948 * @return a list of objects of type <code>{@link CmsProject}</code> 3949 * 3950 * @throws CmsException if operation was not successful 3951 */ 3952 public List<CmsProject> getAllManageableProjects( 3953 CmsDbContext dbc, 3954 CmsOrganizationalUnit orgUnit, 3955 boolean includeSubOus) 3956 throws CmsException { 3957 3958 Set<CmsProject> projects = new HashSet<CmsProject>(); 3959 3960 // get the ous where the user has the project manager role 3961 List<CmsOrganizationalUnit> ous = getOrgUnitsForRole( 3962 dbc, 3963 CmsRole.PROJECT_MANAGER.forOrgUnit(orgUnit.getName()), 3964 includeSubOus); 3965 3966 // get the groups of the user if needed 3967 Set<CmsUUID> userGroupIds = new HashSet<CmsUUID>(); 3968 Iterator<CmsGroup> itGroups = getGroupsOfUser(dbc, dbc.currentUser().getName(), false).iterator(); 3969 while (itGroups.hasNext()) { 3970 CmsGroup group = itGroups.next(); 3971 userGroupIds.add(group.getId()); 3972 } 3973 3974 // TODO: this could be optimize if this method would have an additional parameter 'includeSubOus' 3975 // get all projects that might come in question 3976 projects.addAll(getProjectDriver(dbc).readProjects(dbc, orgUnit.getName())); 3977 3978 // filter hidden and not manageable projects 3979 Iterator<CmsProject> itProjects = projects.iterator(); 3980 while (itProjects.hasNext()) { 3981 CmsProject project = itProjects.next(); 3982 boolean manageable = true; 3983 // if online 3984 manageable = manageable && !project.isOnlineProject(); 3985 // if hidden 3986 manageable = manageable && !project.isHidden(); 3987 3988 if (!includeSubOus) { 3989 // if not exact in the given ou 3990 manageable = manageable && project.getOuFqn().equals(orgUnit.getName()); 3991 } else { 3992 // if not in the given ou 3993 manageable = manageable && project.getOuFqn().startsWith(orgUnit.getName()); 3994 } 3995 3996 if (!manageable) { 3997 itProjects.remove(); 3998 continue; 3999 } 4000 4001 manageable = false; 4002 // if owner 4003 manageable = manageable || project.getOwnerId().equals(dbc.currentUser().getId()); 4004 4005 // project managers 4006 Iterator<CmsOrganizationalUnit> itOus = ous.iterator(); 4007 while (!manageable && itOus.hasNext()) { 4008 CmsOrganizationalUnit ou = itOus.next(); 4009 // for project managers check visibility 4010 manageable = manageable || project.getOuFqn().startsWith(ou.getName()); 4011 } 4012 4013 if (!manageable) { 4014 // if manager of project 4015 if (userGroupIds.contains(project.getManagerGroupId())) { 4016 String oufqn = readGroup(dbc, project.getManagerGroupId()).getOuFqn(); 4017 manageable = manageable || (oufqn.startsWith(dbc.getRequestContext().getOuFqn())); 4018 } 4019 } 4020 if (!manageable) { 4021 // remove not accessible project 4022 itProjects.remove(); 4023 } 4024 } 4025 4026 List<CmsProject> manageableProjects = new ArrayList<CmsProject>(projects); 4027 // sort the list of projects based on the project name 4028 Collections.sort(manageableProjects); 4029 // ensure the online project is not in the list 4030 CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); 4031 if (manageableProjects.contains(onlineProject)) { 4032 manageableProjects.remove(onlineProject); 4033 } 4034 4035 return manageableProjects; 4036 } 4037 4038 /** 4039 * Returns all child groups of a group.<p> 4040 * 4041 * @param dbc the current database context 4042 * @param group the group to get the child for 4043 * @param includeSubChildren if set also returns all sub-child groups of the given group 4044 * 4045 * @return a list of all child <code>{@link CmsGroup}</code> objects 4046 * 4047 * @throws CmsException if operation was not successful 4048 */ 4049 public List<CmsGroup> getChildren(CmsDbContext dbc, CmsGroup group, boolean includeSubChildren) 4050 throws CmsException { 4051 4052 if (!includeSubChildren) { 4053 return getUserDriver(dbc).readChildGroups(dbc, group.getName()); 4054 } 4055 Set<CmsGroup> allChildren = new TreeSet<CmsGroup>(); 4056 // iterate all child groups 4057 Iterator<CmsGroup> it = getUserDriver(dbc).readChildGroups(dbc, group.getName()).iterator(); 4058 while (it.hasNext()) { 4059 CmsGroup child = it.next(); 4060 // add the group itself 4061 allChildren.add(child); 4062 // now get all sub-children for each group 4063 allChildren.addAll(getChildren(dbc, child, true)); 4064 } 4065 return new ArrayList<CmsGroup>(allChildren); 4066 } 4067 4068 /** 4069 * Returns the date when the resource was last visited by the user.<p> 4070 * 4071 * @param dbc the database context 4072 * @param poolName the name of the database pool to use 4073 * @param user the user to check the date 4074 * @param resource the resource to check the date 4075 * 4076 * @return the date when the resource was last visited by the user 4077 * 4078 * @throws CmsException if something goes wrong 4079 */ 4080 public long getDateLastVisitedBy(CmsDbContext dbc, String poolName, CmsUser user, CmsResource resource) 4081 throws CmsException { 4082 4083 return m_subscriptionDriver.getDateLastVisitedBy(dbc, poolName, user, resource); 4084 } 4085 4086 /** 4087 * Returns all groups of the given organizational unit.<p> 4088 * 4089 * @param dbc the current db context 4090 * @param orgUnit the organizational unit to get the groups for 4091 * @param includeSubOus if all groups of sub-organizational units should be retrieved too 4092 * @param readRoles if to read roles or groups 4093 * 4094 * @return all <code>{@link CmsGroup}</code> objects in the organizational unit 4095 * 4096 * @throws CmsException if operation was not successful 4097 * 4098 * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String) 4099 * @see org.opencms.security.CmsOrgUnitManager#getGroups(CmsObject, String, boolean) 4100 */ 4101 public List<CmsGroup> getGroups( 4102 CmsDbContext dbc, 4103 CmsOrganizationalUnit orgUnit, 4104 boolean includeSubOus, 4105 boolean readRoles) 4106 throws CmsException { 4107 4108 return getUserDriver(dbc).getGroups(dbc, orgUnit, includeSubOus, readRoles); 4109 } 4110 4111 /** 4112 * Returns the groups of an user filtered by the specified IP address.<p> 4113 * 4114 * @param dbc the current database context 4115 * @param username the name of the user 4116 * @param readRoles if to read roles or groups 4117 * 4118 * @return the groups of the given user, as a list of {@link CmsGroup} objects 4119 * 4120 * @throws CmsException if something goes wrong 4121 */ 4122 public List<CmsGroup> getGroupsOfUser(CmsDbContext dbc, String username, boolean readRoles) throws CmsException { 4123 4124 return getGroupsOfUser(dbc, username, "", true, readRoles, false, dbc.getRequestContext().getRemoteAddress()); 4125 } 4126 4127 /** 4128 * Returns the groups of an user filtered by the specified IP address.<p> 4129 * 4130 * @param dbc the current database context 4131 * @param username the name of the user 4132 * @param ouFqn the fully qualified name of the organizational unit to restrict the result set for 4133 * @param includeChildOus include groups of child organizational units 4134 * @param readRoles if to read roles or groups 4135 * @param directGroupsOnly if set only the direct assigned groups will be returned, if not also indirect groups 4136 * @param remoteAddress the IP address to filter the groups in the result list 4137 * 4138 * @return a list of <code>{@link CmsGroup}</code> objects 4139 * 4140 * @throws CmsException if operation was not successful 4141 */ 4142 public List<CmsGroup> getGroupsOfUser( 4143 CmsDbContext dbc, 4144 String username, 4145 String ouFqn, 4146 boolean includeChildOus, 4147 boolean readRoles, 4148 boolean directGroupsOnly, 4149 String remoteAddress) 4150 throws CmsException { 4151 4152 CmsUser user = readUser(dbc, username); 4153 String prefix = ouFqn + "_" + includeChildOus + "_" + directGroupsOnly + "_" + readRoles + "_" + remoteAddress; 4154 String cacheKey = m_keyGenerator.getCacheKeyForUserGroups(prefix, dbc, user); 4155 List<CmsGroup> groups = m_monitor.getCachedUserGroups(user.getId(), cacheKey); 4156 if (groups == null) { 4157 // get all groups of the user 4158 List<CmsGroup> directGroups = getUserDriver(dbc).readGroupsOfUser( 4159 dbc, 4160 user.getId(), 4161 readRoles ? "" : ouFqn, 4162 readRoles ? true : includeChildOus, 4163 remoteAddress, 4164 readRoles); 4165 Set<CmsGroup> allGroups = new HashSet<CmsGroup>(); 4166 if (!readRoles) { 4167 allGroups.addAll(directGroups); 4168 } 4169 if (!directGroupsOnly) { 4170 if (!readRoles) { 4171 // now get all parents of the groups 4172 for (int i = 0; i < directGroups.size(); i++) { 4173 CmsGroup parent = getParent(dbc, directGroups.get(i).getName()); 4174 while ((parent != null) && (!allGroups.contains(parent))) { 4175 if (parent.getOuFqn().startsWith(ouFqn)) { 4176 allGroups.add(parent); 4177 } 4178 // read next parent group 4179 parent = getParent(dbc, parent.getName()); 4180 } 4181 } 4182 } 4183 } 4184 if (readRoles) { 4185 // for each for role 4186 for (int i = 0; i < directGroups.size(); i++) { 4187 CmsGroup group = directGroups.get(i); 4188 CmsRole role = CmsRole.valueOf(group); 4189 if (!includeChildOus && role.getOuFqn().equals(ouFqn)) { 4190 allGroups.add(group); 4191 } 4192 if (includeChildOus && role.getOuFqn().startsWith(ouFqn)) { 4193 allGroups.add(group); 4194 } 4195 if (directGroupsOnly || (!includeChildOus && !role.getOuFqn().equals(ouFqn))) { 4196 // if roles of child OUs are not requested and the role does not belong to the requested OU don't include the role children 4197 continue; 4198 } 4199 CmsOrganizationalUnit currentOu = readOrganizationalUnit(dbc, group.getOuFqn()); 4200 boolean readChildRoleGroups = true; 4201 if (currentOu.hasFlagWebuser() && role.forOrgUnit(null).equals(CmsRole.ACCOUNT_MANAGER)) { 4202 readChildRoleGroups = false; 4203 } 4204 if (readChildRoleGroups) { 4205 // get the child roles 4206 Iterator<CmsRole> itChildRoles = role.getChildren(true).iterator(); 4207 while (itChildRoles.hasNext()) { 4208 CmsRole childRole = itChildRoles.next(); 4209 if (childRole.isSystemRole()) { 4210 if (canReadRoleInOu(currentOu, childRole)) { 4211 // include system roles only 4212 try { 4213 allGroups.add(readGroup(dbc, childRole.getGroupName())); 4214 } catch (CmsDataAccessException e) { 4215 // should not happen, log error if it does 4216 LOG.error(e.getLocalizedMessage(), e); 4217 } 4218 } 4219 } 4220 } 4221 } else { 4222 LOG.info("Skipping child role group check for web user OU " + currentOu.getName()); 4223 } 4224 if (includeChildOus) { 4225 // if needed include the roles of child ous 4226 Iterator<CmsOrganizationalUnit> itSubOus = getOrganizationalUnits( 4227 dbc, 4228 readOrganizationalUnit(dbc, group.getOuFqn()), 4229 true).iterator(); 4230 while (itSubOus.hasNext()) { 4231 CmsOrganizationalUnit subOu = itSubOus.next(); 4232 // add role in child ou 4233 try { 4234 if (canReadRoleInOu(subOu, role)) { 4235 allGroups.add(readGroup(dbc, role.forOrgUnit(subOu.getName()).getGroupName())); 4236 } 4237 } catch (CmsDbEntryNotFoundException e) { 4238 // ignore, this may happen while deleting an orgunit 4239 if (LOG.isDebugEnabled()) { 4240 LOG.debug(e.getLocalizedMessage(), e); 4241 } 4242 } 4243 // add child roles in child ous 4244 Iterator<CmsRole> itChildRoles = role.getChildren(true).iterator(); 4245 while (itChildRoles.hasNext()) { 4246 CmsRole childRole = itChildRoles.next(); 4247 try { 4248 if (canReadRoleInOu(subOu, childRole)) { 4249 allGroups.add( 4250 readGroup(dbc, childRole.forOrgUnit(subOu.getName()).getGroupName())); 4251 } 4252 } catch (CmsDbEntryNotFoundException e) { 4253 // ignore, this may happen while deleting an orgunit 4254 if (LOG.isDebugEnabled()) { 4255 LOG.debug(e.getLocalizedMessage(), e); 4256 } 4257 } 4258 } 4259 } 4260 } 4261 } 4262 } 4263 // make group list unmodifiable for caching 4264 groups = Collections.unmodifiableList(new ArrayList<CmsGroup>(allGroups)); 4265 if (dbc.getProjectId().isNullUUID()) { 4266 m_monitor.getGroupListCache().setGroups(user, cacheKey, groups); 4267 } 4268 } 4269 4270 return groups; 4271 } 4272 4273 /** 4274 * Returns the history driver.<p> 4275 * 4276 * @return the history driver 4277 */ 4278 public I_CmsHistoryDriver getHistoryDriver() { 4279 4280 return m_historyDriver; 4281 } 4282 4283 /** 4284 * Returns the history driver for a given database context.<p> 4285 * 4286 * @param dbc the database context 4287 * @return the history driver for the database context 4288 */ 4289 public I_CmsHistoryDriver getHistoryDriver(CmsDbContext dbc) { 4290 4291 if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { 4292 return m_historyDriver; 4293 } 4294 I_CmsHistoryDriver driver = dbc.getHistoryDriver(dbc.getProjectId()); 4295 return driver != null ? driver : m_historyDriver; 4296 4297 } 4298 4299 /** 4300 * Returns the number of idle connections managed by a pool.<p> 4301 * 4302 * @param dbPoolUrl the url of a pool 4303 * @return the number of idle connections 4304 * @throws CmsDbException if something goes wrong 4305 */ 4306 public int getIdleConnections(String dbPoolUrl) throws CmsDbException { 4307 4308 CmsDbPoolV11 pool = m_pools.get(dbPoolUrl); 4309 if (pool == null) { 4310 CmsMessageContainer message = Messages.get().container(Messages.ERR_UNKNOWN_POOL_URL_1, dbPoolUrl); 4311 throw new CmsDbException(message); 4312 } 4313 try { 4314 return pool.getIdleConnections(); 4315 } catch (Exception exc) { 4316 CmsMessageContainer message = Messages.get().container(Messages.ERR_ACCESSING_POOL_1, dbPoolUrl); 4317 throw new CmsDbException(message, exc); 4318 } 4319 4320 } 4321 4322 /** 4323 * Returns the lock state of a resource.<p> 4324 * 4325 * @param dbc the current database context 4326 * @param resource the resource to return the lock state for 4327 * 4328 * @return the lock state of the resource 4329 * 4330 * @throws CmsException if something goes wrong 4331 */ 4332 public CmsLock getLock(CmsDbContext dbc, CmsResource resource) throws CmsException { 4333 4334 return m_lockManager.getLock(dbc, resource); 4335 } 4336 4337 /** 4338 * Returns all locked resources in a given folder.<p> 4339 * 4340 * @param dbc the current database context 4341 * @param resource the folder to search in 4342 * @param filter the lock filter 4343 * 4344 * @return a list of locked resource paths (relative to current site) 4345 * 4346 * @throws CmsException if the current project is locked 4347 */ 4348 public List<String> getLockedResources(CmsDbContext dbc, CmsResource resource, CmsLockFilter filter) 4349 throws CmsException { 4350 4351 List<String> lockedResources = new ArrayList<String>(); 4352 // get locked resources 4353 Iterator<CmsLock> it = m_lockManager.getLocks(dbc, resource.getRootPath(), filter).iterator(); 4354 while (it.hasNext()) { 4355 CmsLock lock = it.next(); 4356 lockedResources.add(dbc.removeSiteRoot(lock.getResourceName())); 4357 } 4358 Collections.sort(lockedResources); 4359 return lockedResources; 4360 } 4361 4362 /** 4363 * Returns all locked resources in a given folder.<p> 4364 * 4365 * @param dbc the current database context 4366 * @param resource the folder to search in 4367 * @param filter the lock filter 4368 * 4369 * @return a list of locked resources 4370 * 4371 * @throws CmsException if the current project is locked 4372 */ 4373 public List<CmsResource> getLockedResourcesObjects(CmsDbContext dbc, CmsResource resource, CmsLockFilter filter) 4374 throws CmsException { 4375 4376 return m_lockManager.getLockedResources(dbc, resource, filter); 4377 } 4378 4379 /** 4380 * Returns all locked resources in a given folder, but uses a cache for resource lookups.<p> 4381 * 4382 * @param dbc the current database context 4383 * @param resource the folder to search in 4384 * @param filter the lock filter 4385 * @param cache the cache to use for resource lookups 4386 * 4387 * @return a list of locked resources 4388 * 4389 * @throws CmsException if the current project is locked 4390 */ 4391 public List<CmsResource> getLockedResourcesObjectsWithCache( 4392 CmsDbContext dbc, 4393 CmsResource resource, 4394 CmsLockFilter filter, 4395 Map<String, CmsResource> cache) 4396 throws CmsException { 4397 4398 return m_lockManager.getLockedResourcesWithCache(dbc, resource, filter, cache); 4399 } 4400 4401 /** 4402 * Returns all log entries matching the given filter.<p> 4403 * 4404 * @param dbc the current db context 4405 * @param filter the filter to match the log entries 4406 * 4407 * @return all log entries matching the given filter 4408 * 4409 * @throws CmsException if something goes wrong 4410 * 4411 * @see CmsSecurityManager#getLogEntries(CmsRequestContext, CmsLogFilter) 4412 */ 4413 public List<CmsLogEntry> getLogEntries(CmsDbContext dbc, CmsLogFilter filter) throws CmsException { 4414 4415 updateLog(dbc); 4416 return m_projectDriver.readLog(dbc, filter); 4417 } 4418 4419 /** 4420 * Returns the next publish tag for the published historical resources.<p> 4421 * 4422 * @param dbc the current database context 4423 * 4424 * @return the next available publish tag 4425 */ 4426 public int getNextPublishTag(CmsDbContext dbc) { 4427 4428 return getHistoryDriver(dbc).readNextPublishTag(dbc); 4429 } 4430 4431 /** 4432 * Returns all child organizational units of the given parent organizational unit including 4433 * hierarchical deeper organization units if needed.<p> 4434 * 4435 * @param dbc the current db context 4436 * @param parent the parent organizational unit, or <code>null</code> for the root 4437 * @param includeChildren if hierarchical deeper organization units should also be returned 4438 * 4439 * @return a list of <code>{@link CmsOrganizationalUnit}</code> objects 4440 * 4441 * @throws CmsException if operation was not successful 4442 * 4443 * @see org.opencms.security.CmsOrgUnitManager#getOrganizationalUnits(CmsObject, String, boolean) 4444 */ 4445 public List<CmsOrganizationalUnit> getOrganizationalUnits( 4446 CmsDbContext dbc, 4447 CmsOrganizationalUnit parent, 4448 boolean includeChildren) 4449 throws CmsException { 4450 4451 if (parent == null) { 4452 throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_PARENT_ORGUNIT_NULL_0)); 4453 } 4454 return getUserDriver(dbc).getOrganizationalUnits(dbc, parent, includeChildren); 4455 } 4456 4457 /** 4458 * Returns all the organizational units for which the current user has the given role.<p> 4459 * 4460 * @param dbc the current database context 4461 * @param role the role to check 4462 * @param includeSubOus if sub organizational units should be included in the search 4463 * 4464 * @return a list of {@link org.opencms.security.CmsOrganizationalUnit} objects 4465 * 4466 * @throws CmsException if something goes wrong 4467 */ 4468 public List<CmsOrganizationalUnit> getOrgUnitsForRole(CmsDbContext dbc, CmsRole role, boolean includeSubOus) 4469 throws CmsException { 4470 4471 String ouFqn = role.getOuFqn(); 4472 if (ouFqn == null) { 4473 ouFqn = ""; 4474 role = role.forOrgUnit(""); 4475 } 4476 CmsOrganizationalUnit ou = readOrganizationalUnit(dbc, ouFqn); 4477 List<CmsOrganizationalUnit> orgUnits = new ArrayList<CmsOrganizationalUnit>(); 4478 if (m_securityManager.hasRole(dbc, dbc.currentUser(), role)) { 4479 orgUnits.add(ou); 4480 } 4481 if (includeSubOus) { 4482 Iterator<CmsOrganizationalUnit> it = getOrganizationalUnits(dbc, ou, true).iterator(); 4483 while (it.hasNext()) { 4484 CmsOrganizationalUnit orgUnit = it.next(); 4485 if (m_securityManager.hasRole(dbc, dbc.currentUser(), role.forOrgUnit(orgUnit.getName()))) { 4486 orgUnits.add(orgUnit); 4487 } 4488 } 4489 } 4490 return orgUnits; 4491 } 4492 4493 /** 4494 * Returns the parent group of a group.<p> 4495 * 4496 * @param dbc the current database context 4497 * @param groupname the name of the group 4498 * 4499 * @return group the parent group or <code>null</code> 4500 * 4501 * @throws CmsException if operation was not successful 4502 */ 4503 public CmsGroup getParent(CmsDbContext dbc, String groupname) throws CmsException { 4504 4505 CmsGroup group = readGroup(dbc, groupname); 4506 if (group.getParentId().isNullUUID()) { 4507 return null; 4508 } 4509 4510 // try to read from cache 4511 CmsGroup parent = m_monitor.getCachedGroup(group.getParentId().toString()); 4512 if (parent == null) { 4513 parent = getUserDriver(dbc).readGroup(dbc, group.getParentId()); 4514 m_monitor.cacheGroup(parent); 4515 } 4516 return parent; 4517 } 4518 4519 /** 4520 * Returns the set of permissions of the current user for a given resource.<p> 4521 * 4522 * @param dbc the current database context 4523 * @param resource the resource 4524 * @param user the user 4525 * 4526 * @return bit set with allowed permissions 4527 * 4528 * @throws CmsException if something goes wrong 4529 */ 4530 public CmsPermissionSetCustom getPermissions(CmsDbContext dbc, CmsResource resource, CmsUser user) 4531 throws CmsException { 4532 4533 CmsAccessControlList acList = getAccessControlList(dbc, resource, false); 4534 return acList.getPermissions(user, getGroupsOfUser(dbc, user.getName(), false), getRolesForUser(dbc, user)); 4535 } 4536 4537 /** 4538 * Returns the project driver.<p> 4539 * 4540 * @return the project driver 4541 */ 4542 public I_CmsProjectDriver getProjectDriver() { 4543 4544 return m_projectDriver; 4545 } 4546 4547 /** 4548 * Returns the project driver for a given DB context.<p> 4549 * 4550 * @param dbc the database context 4551 * 4552 * @return the project driver for the database context 4553 */ 4554 public I_CmsProjectDriver getProjectDriver(CmsDbContext dbc) { 4555 4556 if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { 4557 return m_projectDriver; 4558 } 4559 I_CmsProjectDriver driver = dbc.getProjectDriver(dbc.getProjectId()); 4560 return driver != null ? driver : m_projectDriver; 4561 } 4562 4563 /** 4564 * Returns either the project driver for the DB context (if it has one) or a default project driver.<p> 4565 * 4566 * @param dbc the DB context 4567 * @param defaultDriver the driver which should be returned if there is no project driver for the DB context 4568 * 4569 * @return either the project driver for the DB context, or the default driver 4570 */ 4571 public I_CmsProjectDriver getProjectDriver(CmsDbContext dbc, I_CmsProjectDriver defaultDriver) { 4572 4573 if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { 4574 return defaultDriver; 4575 } 4576 I_CmsProjectDriver driver = dbc.getProjectDriver(dbc.getProjectId()); 4577 return driver != null ? driver : defaultDriver; 4578 } 4579 4580 /** 4581 * Returns the uuid id for the given id.<p> 4582 * 4583 * TODO: remove this method as soon as possible 4584 * 4585 * @param dbc the current database context 4586 * @param id the old project id 4587 * 4588 * @return the new uuid for the given id 4589 * 4590 * @throws CmsException if something goes wrong 4591 */ 4592 public CmsUUID getProjectId(CmsDbContext dbc, int id) throws CmsException { 4593 4594 Iterator<CmsProject> itProjects = getAllAccessibleProjects( 4595 dbc, 4596 readOrganizationalUnit(dbc, ""), 4597 true).iterator(); 4598 while (itProjects.hasNext()) { 4599 CmsProject project = itProjects.next(); 4600 if (project.getUuid().hashCode() == id) { 4601 return project.getUuid(); 4602 } 4603 } 4604 return null; 4605 } 4606 4607 /** 4608 * Returns the configuration read from the <code>opencms.properties</code> file.<p> 4609 * 4610 * @return the configuration read from the <code>opencms.properties</code> file 4611 */ 4612 public CmsParameterConfiguration getPropertyConfiguration() { 4613 4614 return m_propertyConfiguration; 4615 } 4616 4617 /** 4618 * Returns a new publish list that contains the unpublished resources related 4619 * to all resources in the given publish list, the related resources exclude 4620 * all resources in the given publish list and also locked (by other users) resources.<p> 4621 * 4622 * @param dbc the current database context 4623 * @param publishList the publish list to exclude from result 4624 * @param filter the relation filter to use to get the related resources 4625 * 4626 * @return a new publish list that contains the related resources 4627 * 4628 * @throws CmsException if something goes wrong 4629 * 4630 * @see org.opencms.publish.CmsPublishManager#getRelatedResourcesToPublish(CmsObject, CmsPublishList) 4631 */ 4632 public CmsPublishList getRelatedResourcesToPublish( 4633 CmsDbContext dbc, 4634 CmsPublishList publishList, 4635 CmsRelationFilter filter) 4636 throws CmsException { 4637 4638 Map<String, CmsResource> relations = new HashMap<String, CmsResource>(); 4639 4640 // check if progress should be set in the thread 4641 A_CmsProgressThread thread = null; 4642 if (Thread.currentThread() instanceof A_CmsProgressThread) { 4643 thread = (A_CmsProgressThread)Thread.currentThread(); 4644 } 4645 4646 // get all resources to publish 4647 List<CmsResource> publishResources = publishList.getAllResources(); 4648 Iterator<CmsResource> itCheckList = publishResources.iterator(); 4649 // iterate over them 4650 int count = 0; 4651 while (itCheckList.hasNext()) { 4652 4653 // set progress in thread 4654 count++; 4655 if (thread != null) { 4656 4657 if (thread.isInterrupted()) { 4658 throw new CmsIllegalStateException( 4659 org.opencms.workplace.commons.Messages.get().container( 4660 org.opencms.workplace.commons.Messages.ERR_PROGRESS_INTERRUPTED_0)); 4661 } 4662 thread.setProgress((count * 20) / publishResources.size()); 4663 thread.setDescription( 4664 org.opencms.workplace.commons.Messages.get().getBundle().key( 4665 org.opencms.workplace.commons.Messages.GUI_PROGRESS_PUBLISH_STEP1_2, 4666 new Integer(count), 4667 new Integer(publishResources.size()))); 4668 } 4669 4670 CmsResource checkResource = itCheckList.next(); 4671 // get and iterate over all related resources 4672 Iterator<CmsRelation> itRelations = getRelationsForResource(dbc, checkResource, filter).iterator(); 4673 while (itRelations.hasNext()) { 4674 CmsRelation relation = itRelations.next(); 4675 try { 4676 // get the target of the relation, see CmsRelation#getTarget(CmsObject, CmsResourceFilter) 4677 CmsResource target; 4678 try { 4679 // first look up by id 4680 target = readResource(dbc, relation.getTargetId(), CmsResourceFilter.ALL); 4681 } catch (CmsVfsResourceNotFoundException e) { 4682 // then look up by name, but from the root site 4683 String storedSiteRoot = dbc.getRequestContext().getSiteRoot(); 4684 try { 4685 dbc.getRequestContext().setSiteRoot(""); 4686 target = readResource(dbc, relation.getTargetPath(), CmsResourceFilter.ALL); 4687 } finally { 4688 dbc.getRequestContext().setSiteRoot(storedSiteRoot); 4689 } 4690 } 4691 CmsLock lock = getLock(dbc, target); 4692 // just add resources that may come in question 4693 if (!publishResources.contains(target) // is not in the original list 4694 && !relations.containsKey(target.getRootPath()) // has not been already added by another relation 4695 && !target.getState().isUnchanged() // has been changed 4696 && lock.isLockableBy(dbc.currentUser())) { // is lockable by current user 4697 4698 relations.put(target.getRootPath(), target); 4699 // now check the folder structure 4700 CmsResource parent = getVfsDriver(dbc).readParentFolder( 4701 dbc, 4702 dbc.currentProject().getUuid(), 4703 target.getStructureId()); 4704 while ((parent != null) && parent.getState().isNew()) { 4705 // just add resources that may come in question 4706 if (!publishResources.contains(parent) // is not in the original list 4707 && !relations.containsKey(parent.getRootPath())) { // has not been already added by another relation 4708 4709 relations.put(parent.getRootPath(), parent); 4710 } 4711 parent = getVfsDriver(dbc).readParentFolder( 4712 dbc, 4713 dbc.currentProject().getUuid(), 4714 parent.getStructureId()); 4715 } 4716 } 4717 } catch (CmsVfsResourceNotFoundException e) { 4718 // ignore broken links 4719 if (LOG.isDebugEnabled()) { 4720 LOG.debug(e.getLocalizedMessage(), e); 4721 } 4722 } 4723 } 4724 } 4725 4726 CmsPublishList ret = new CmsPublishList(publishList.getDirectPublishResources(), false, false); 4727 ret.addAll(relations.values(), false); 4728 ret.initialize(); 4729 return ret; 4730 } 4731 4732 /** 4733 * Returns all relations for the given resource matching the given filter.<p> 4734 * 4735 * @param dbc the current db context 4736 * @param resource the resource to retrieve the relations for 4737 * @param filter the filter to match the relation 4738 * 4739 * @return all relations for the given resource matching the given filter 4740 * 4741 * @throws CmsException if something goes wrong 4742 * 4743 * @see CmsSecurityManager#getRelationsForResource(CmsRequestContext, CmsResource, CmsRelationFilter) 4744 */ 4745 public List<CmsRelation> getRelationsForResource(CmsDbContext dbc, CmsResource resource, CmsRelationFilter filter) 4746 throws CmsException { 4747 4748 CmsUUID projectId = getProjectIdForContext(dbc); 4749 return getVfsDriver(dbc).readRelations(dbc, projectId, resource, filter); 4750 } 4751 4752 /** 4753 * Returns the list of organizational units the given resource belongs to.<p> 4754 * 4755 * @param dbc the current database context 4756 * @param resource the resource 4757 * 4758 * @return list of {@link CmsOrganizationalUnit} objects 4759 * 4760 * @throws CmsException if something goes wrong 4761 */ 4762 public List<CmsOrganizationalUnit> getResourceOrgUnits(CmsDbContext dbc, CmsResource resource) throws CmsException { 4763 4764 boolean nullDbcProjectId = (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID(); 4765 if (nullDbcProjectId && resourceOrgUnitCachingEnabled) { 4766 try { 4767 return m_monitor.getResourceOuCache().get(new ResourceOUCacheKey(this, dbc)).getResourceOrgUnits( 4768 resource.getRootPath()); 4769 } catch (ExecutionException e) { 4770 LOG.error(e.getLocalizedMessage(), e); 4771 } 4772 } 4773 List<CmsOrganizationalUnit> result = getVfsDriver(dbc).getResourceOus( 4774 dbc, 4775 dbc.currentProject().getUuid(), 4776 resource); 4777 4778 return result; 4779 } 4780 4781 /** 4782 * Returns all resources of the given organizational unit.<p> 4783 * 4784 * @param dbc the current db context 4785 * @param orgUnit the organizational unit to get all resources for 4786 * 4787 * @return all <code>{@link CmsResource}</code> objects in the organizational unit 4788 * 4789 * @throws CmsException if operation was not successful 4790 * 4791 * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String) 4792 * @see org.opencms.security.CmsOrgUnitManager#getUsers(CmsObject, String, boolean) 4793 * @see org.opencms.security.CmsOrgUnitManager#getGroups(CmsObject, String, boolean) 4794 */ 4795 public List<CmsResource> getResourcesForOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit) 4796 throws CmsException { 4797 4798 return getUserDriver(dbc).getResourcesForOrganizationalUnit(dbc, orgUnit); 4799 } 4800 4801 /** 4802 * Returns all resources associated to a given principal via an ACE with the given permissions.<p> 4803 * 4804 * If the <code>includeAttr</code> flag is set it returns also all resources associated to 4805 * a given principal through some of following attributes.<p> 4806 * 4807 * <ul> 4808 * <li>User Created</li> 4809 * <li>User Last Modified</li> 4810 * </ul><p> 4811 * 4812 * @param dbc the current database context 4813 * @param project the to read the entries from 4814 * @param principalId the id of the principal 4815 * @param permissions a set of permissions to match, can be <code>null</code> for all ACEs 4816 * @param includeAttr a flag to include resources associated by attributes 4817 * 4818 * @return a set of <code>{@link CmsResource}</code> objects 4819 * 4820 * @throws CmsException if something goes wrong 4821 */ 4822 public Set<CmsResource> getResourcesForPrincipal( 4823 CmsDbContext dbc, 4824 CmsProject project, 4825 CmsUUID principalId, 4826 CmsPermissionSet permissions, 4827 boolean includeAttr) 4828 throws CmsException { 4829 4830 Set<CmsResource> resources = new HashSet<CmsResource>( 4831 getVfsDriver(dbc).readResourcesForPrincipalACE(dbc, project, principalId)); 4832 if (permissions != null) { 4833 Iterator<CmsResource> itRes = resources.iterator(); 4834 while (itRes.hasNext()) { 4835 CmsAccessControlEntry ace = readAccessControlEntry(dbc, itRes.next(), principalId); 4836 if ((ace.getPermissions().getPermissions() 4837 & permissions.getPermissions()) != permissions.getPermissions()) { 4838 // remove if permissions does not match 4839 itRes.remove(); 4840 } 4841 } 4842 } 4843 if (includeAttr) { 4844 resources.addAll(getVfsDriver(dbc).readResourcesForPrincipalAttr(dbc, project, principalId)); 4845 } 4846 return resources; 4847 } 4848 4849 /** 4850 * Gets the rewrite aliases matching a given filter.<p> 4851 * 4852 * @param dbc the current database context 4853 * @param filter the filter used for filtering rewrite aliases 4854 * 4855 * @return the rewrite aliases matching the given filter 4856 * 4857 * @throws CmsException if something goes wrong 4858 */ 4859 public List<CmsRewriteAlias> getRewriteAliases(CmsDbContext dbc, CmsRewriteAliasFilter filter) throws CmsException { 4860 4861 return getVfsDriver(dbc).readRewriteAliases(dbc, filter); 4862 } 4863 4864 /** 4865 * Collects the groups which constitute a given role.<p> 4866 * 4867 * @param dbc the database context 4868 * @param roleGroupName the group related to the role 4869 * @param directUsersOnly if true, only the group belonging to the entry itself wil 4870 * 4871 * @return the set of groups which constitute the role 4872 * 4873 * @throws CmsException if something goes wrong 4874 */ 4875 public Set<CmsGroup> getRoleGroups(CmsDbContext dbc, String roleGroupName, boolean directUsersOnly) 4876 throws CmsException { 4877 4878 return getRoleGroupsImpl(dbc, roleGroupName, directUsersOnly, new HashMap<String, Set<CmsGroup>>()); 4879 } 4880 4881 /** 4882 * Collects the groups which constitute a given role.<p> 4883 * 4884 * @param dbc the database context 4885 * @param roleGroupName the group related to the role 4886 * @param directUsersOnly if true, only the group belonging to the entry itself wil 4887 * @param accumulator a map for memoizing return values of recursive calls 4888 * 4889 * @return the set of groups which constitute the role 4890 * 4891 * @throws CmsException if something goes wrong 4892 */ 4893 public Set<CmsGroup> getRoleGroupsImpl( 4894 CmsDbContext dbc, 4895 String roleGroupName, 4896 boolean directUsersOnly, 4897 Map<String, Set<CmsGroup>> accumulator) 4898 throws CmsException { 4899 4900 Set<CmsGroup> result = new HashSet<CmsGroup>(); 4901 if (accumulator.get(roleGroupName) != null) { 4902 return accumulator.get(roleGroupName); 4903 } 4904 CmsGroup group = readGroup(dbc, roleGroupName); // check that the group really exists 4905 if ((group == null) || (!group.isRole())) { 4906 throw new CmsDbEntryNotFoundException( 4907 Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, roleGroupName)); 4908 } 4909 result.add(group); 4910 if (!directUsersOnly) { 4911 CmsRole role = CmsRole.valueOf(group); 4912 if (role.getParentRole() != null) { 4913 try { 4914 String parentGroup = role.getParentRole().getGroupName(); 4915 // iterate the parent roles 4916 result.addAll(getRoleGroupsImpl(dbc, parentGroup, directUsersOnly, accumulator)); 4917 } catch (CmsDbEntryNotFoundException e) { 4918 // ignore, this may happen while deleting an orgunit 4919 if (LOG.isDebugEnabled()) { 4920 LOG.debug(e.getLocalizedMessage(), e); 4921 } 4922 } 4923 } 4924 String parentOu = CmsOrganizationalUnit.getParentFqn(group.getOuFqn()); 4925 if (parentOu != null) { 4926 // iterate the parent ou's 4927 result.addAll(getRoleGroupsImpl(dbc, parentOu + group.getSimpleName(), directUsersOnly, accumulator)); 4928 } 4929 } 4930 accumulator.put(roleGroupName, result); 4931 return result; 4932 } 4933 4934 /** 4935 * Returns all roles the given user has for the given resource.<p> 4936 * 4937 * @param dbc the current database context 4938 * @param user the user to check 4939 * @param resource the resource to check the roles for 4940 * 4941 * @return a list of {@link CmsRole} objects 4942 * 4943 * @throws CmsException if something goes wrong 4944 */ 4945 public List<CmsRole> getRolesForResource(CmsDbContext dbc, CmsUser user, CmsResource resource) throws CmsException { 4946 4947 // guest user has no role 4948 if (user.isGuestUser()) { 4949 return Collections.emptyList(); 4950 } 4951 4952 // try to read from cache 4953 String key = user.getId().toString() + resource.getRootPath(); 4954 List<CmsRole> result = m_monitor.getCachedRoleList(key); 4955 if (result != null) { 4956 return result; 4957 } 4958 result = new ArrayList<CmsRole>(); 4959 4960 Iterator<CmsOrganizationalUnit> itOus = getResourceOrgUnits(dbc, resource).iterator(); 4961 while (itOus.hasNext()) { 4962 CmsOrganizationalUnit ou = itOus.next(); 4963 4964 // read all roles of the current user 4965 List<CmsGroup> groups = new ArrayList<CmsGroup>( 4966 getGroupsOfUser( 4967 dbc, 4968 user.getName(), 4969 ou.getName(), 4970 false, 4971 true, 4972 false, 4973 dbc.getRequestContext().getRemoteAddress())); 4974 // check the roles applying to the given resource 4975 Iterator<CmsGroup> it = groups.iterator(); 4976 while (it.hasNext()) { 4977 CmsGroup group = it.next(); 4978 CmsRole givenRole = CmsRole.valueOf(group).forOrgUnit(null); 4979 if (givenRole.isOrganizationalUnitIndependent() || result.contains(givenRole)) { 4980 // skip already added roles 4981 continue; 4982 } 4983 result.add(givenRole); 4984 } 4985 } 4986 4987 result = Collections.unmodifiableList(result); 4988 m_monitor.cacheRoleList(key, result); 4989 return result; 4990 } 4991 4992 /** 4993 * Returns all roles the given user has independent of the resource.<p> 4994 * 4995 * @param dbc the current database context 4996 * @param user the user to check 4997 * 4998 * @return a list of {@link CmsRole} objects 4999 * 5000 * @throws CmsException if something goes wrong 5001 */ 5002 public List<CmsRole> getRolesForUser(CmsDbContext dbc, CmsUser user) throws CmsException { 5003 5004 // guest user has no role 5005 if (user.isGuestUser()) { 5006 return Collections.emptyList(); 5007 } 5008 5009 // try to read from cache 5010 List<CmsRole> result = m_monitor.getGroupListCache().getBareRoles(user.getId()); 5011 if (result != null) { 5012 return result; 5013 } 5014 result = new ArrayList<CmsRole>(); 5015 5016 // read all roles of the current user 5017 List<CmsGroup> groups = new ArrayList<CmsGroup>( 5018 getGroupsOfUser(dbc, user.getName(), "", true, true, false, dbc.getRequestContext().getRemoteAddress())); 5019 5020 // check the roles applying to the given resource 5021 Iterator<CmsGroup> it = groups.iterator(); 5022 while (it.hasNext()) { 5023 CmsGroup group = it.next(); 5024 CmsRole givenRole = CmsRole.valueOf(group); 5025 givenRole = givenRole.forOrgUnit(null); 5026 if (!result.contains(givenRole)) { 5027 result.add(givenRole); 5028 } 5029 } 5030 result = Collections.unmodifiableList(result); 5031 m_monitor.getGroupListCache().setBareRoles(user, result); 5032 return result; 5033 } 5034 5035 /** 5036 * Returns the security manager this driver manager belongs to.<p> 5037 * 5038 * @return the security manager this driver manager belongs to 5039 */ 5040 public CmsSecurityManager getSecurityManager() { 5041 5042 return m_securityManager; 5043 } 5044 5045 /** 5046 * Returns an instance of the common sql manager.<p> 5047 * 5048 * @return an instance of the common sql manager 5049 */ 5050 public CmsSqlManager getSqlManager() { 5051 5052 return m_sqlManager; 5053 } 5054 5055 /** 5056 * Returns the subscription driver of this driver manager.<p> 5057 * 5058 * @return a subscription driver 5059 */ 5060 public I_CmsSubscriptionDriver getSubscriptionDriver() { 5061 5062 return m_subscriptionDriver; 5063 } 5064 5065 /** 5066 * Returns the user driver.<p> 5067 * 5068 * @return the user driver 5069 */ 5070 public I_CmsUserDriver getUserDriver() { 5071 5072 return m_userDriver; 5073 } 5074 5075 /** 5076 * Returns the user driver for a given database context.<p> 5077 * 5078 * @param dbc the database context 5079 * 5080 * @return the user driver for the database context 5081 */ 5082 public I_CmsUserDriver getUserDriver(CmsDbContext dbc) { 5083 5084 if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { 5085 return m_userDriver; 5086 } 5087 I_CmsUserDriver driver = dbc.getUserDriver(dbc.getProjectId()); 5088 return driver != null ? driver : m_userDriver; 5089 5090 } 5091 5092 /** 5093 * Returns either the user driver for the given DB context (if it has one) or a default value instead.<p> 5094 * 5095 * @param dbc the DB context 5096 * @param defaultDriver the driver that should be returned if no driver for the DB context was found 5097 * 5098 * @return either the user driver for the DB context, or <code>defaultDriver</code> if none were found 5099 */ 5100 public I_CmsUserDriver getUserDriver(CmsDbContext dbc, I_CmsUserDriver defaultDriver) { 5101 5102 if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { 5103 return defaultDriver; 5104 } 5105 I_CmsUserDriver driver = dbc.getUserDriver(dbc.getProjectId()); 5106 return driver != null ? driver : defaultDriver; 5107 } 5108 5109 /** 5110 * Returns all direct users of the given organizational unit.<p> 5111 * 5112 * @param dbc the current db context 5113 * @param orgUnit the organizational unit to get all users for 5114 * @param recursive if all groups of sub-organizational units should be retrieved too 5115 * 5116 * @return all <code>{@link CmsUser}</code> objects in the organizational unit 5117 * 5118 * @throws CmsException if operation was not successful 5119 * 5120 * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String) 5121 * @see org.opencms.security.CmsOrgUnitManager#getUsers(CmsObject, String, boolean) 5122 */ 5123 public List<CmsUser> getUsers(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, boolean recursive) 5124 throws CmsException { 5125 5126 return getUserDriver(dbc).getUsers(dbc, orgUnit, recursive); 5127 } 5128 5129 /** 5130 * Returns a list of users in a group.<p> 5131 * 5132 * @param dbc the current database context 5133 * @param groupname the name of the group to list users from 5134 * @param includeOtherOuUsers include users of other organizational units 5135 * @param directUsersOnly if set only the direct assigned users will be returned, 5136 * if not also indirect users, ie. members of parent roles, 5137 * this parameter only works with roles 5138 * @param readRoles if to read roles or groups 5139 * 5140 * @return all <code>{@link CmsUser}</code> objects in the group 5141 * 5142 * @throws CmsException if operation was not successful 5143 */ 5144 public List<CmsUser> getUsersOfGroup( 5145 CmsDbContext dbc, 5146 String groupname, 5147 boolean includeOtherOuUsers, 5148 boolean directUsersOnly, 5149 boolean readRoles) 5150 throws CmsException { 5151 5152 return internalUsersOfGroup( 5153 dbc, 5154 CmsOrganizationalUnit.getParentFqn(groupname), 5155 groupname, 5156 includeOtherOuUsers, 5157 directUsersOnly, 5158 readRoles); 5159 } 5160 5161 /** 5162 * Returns the given user's publish list.<p> 5163 * 5164 * @param dbc the database context 5165 * @param userId the user's id 5166 * 5167 * @return the given user's publish list 5168 * 5169 * @throws CmsDataAccessException if something goes wrong 5170 */ 5171 public List<CmsResource> getUsersPubList(CmsDbContext dbc, CmsUUID userId) throws CmsDataAccessException { 5172 5173 synchronized (m_publishListUpdateLock) { 5174 updateLog(dbc); 5175 return m_projectDriver.getUsersPubList(dbc, userId); 5176 } 5177 } 5178 5179 /** 5180 * Returns all direct users of the given organizational unit, without their additional info.<p> 5181 * 5182 * @param dbc the current db context 5183 * @param orgUnit the organizational unit to get all users for 5184 * @param recursive if all groups of sub-organizational units should be retrieved too 5185 * 5186 * @return all <code>{@link CmsUser}</code> objects in the organizational unit 5187 * 5188 * @throws CmsException if operation was not successful 5189 * 5190 * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String) 5191 * @see org.opencms.security.CmsOrgUnitManager#getUsers(CmsObject, String, boolean) 5192 */ 5193 public List<CmsUser> getUsersWithoutAdditionalInfo( 5194 CmsDbContext dbc, 5195 CmsOrganizationalUnit orgUnit, 5196 boolean recursive) 5197 throws CmsException { 5198 5199 return getUserDriver(dbc).getUsersWithoutAdditionalInfo(dbc, orgUnit, recursive); 5200 } 5201 5202 /** 5203 * Returns the VFS driver.<p> 5204 * 5205 * @return the VFS driver 5206 */ 5207 public I_CmsVfsDriver getVfsDriver() { 5208 5209 return m_vfsDriver; 5210 } 5211 5212 /** 5213 * Returns the VFS driver for the given database context.<p> 5214 * 5215 * @param dbc the database context 5216 * 5217 * @return a VFS driver 5218 */ 5219 public I_CmsVfsDriver getVfsDriver(CmsDbContext dbc) { 5220 5221 if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { 5222 return m_vfsDriver; 5223 } 5224 I_CmsVfsDriver driver = dbc.getVfsDriver(dbc.getProjectId()); 5225 return driver != null ? driver : m_vfsDriver; 5226 5227 } 5228 5229 /** 5230 * Writes a vector of access control entries as new access control entries of a given resource.<p> 5231 * 5232 * Already existing access control entries of this resource are removed before. 5233 * Access is granted, if:<p> 5234 * <ul> 5235 * <li>the current user has control permission on the resource</li> 5236 * </ul> 5237 * 5238 * @param dbc the current database context 5239 * @param resource the resource 5240 * @param acEntries a list of <code>{@link CmsAccessControlEntry}</code> objects 5241 * 5242 * @throws CmsException if something goes wrong 5243 */ 5244 public void importAccessControlEntries( 5245 CmsDbContext dbc, 5246 CmsResource resource, 5247 List<CmsAccessControlEntry> acEntries) 5248 throws CmsException { 5249 5250 I_CmsUserDriver userDriver = getUserDriver(dbc); 5251 userDriver.removeAccessControlEntries(dbc, dbc.currentProject(), resource.getResourceId()); 5252 List<CmsAccessControlEntry> fixedAces = new ArrayList<>(); 5253 for (CmsAccessControlEntry entry : acEntries) { 5254 if (entry.getResource() == null) { 5255 entry = new CmsAccessControlEntry( 5256 resource.getResourceId(), 5257 entry.getPrincipal(), 5258 entry.getPermissions(), 5259 entry.getFlags()); 5260 } 5261 fixedAces.add(entry); 5262 } 5263 5264 Iterator<CmsAccessControlEntry> i = fixedAces.iterator(); 5265 while (i.hasNext()) { 5266 userDriver.writeAccessControlEntry(dbc, dbc.currentProject(), i.next()); 5267 } 5268 m_monitor.clearAccessControlListCache(); 5269 } 5270 5271 /** 5272 * Imports a rewrite alias.<p> 5273 * 5274 * @param dbc the database context 5275 * @param siteRoot the site root of the alias 5276 * @param source the source of the alias 5277 * @param target the target of the alias 5278 * @param mode the alias mode 5279 * 5280 * @return the import result 5281 * 5282 * @throws CmsException if something goes wrong 5283 */ 5284 public CmsAliasImportResult importRewriteAlias( 5285 CmsDbContext dbc, 5286 String siteRoot, 5287 String source, 5288 String target, 5289 CmsAliasMode mode) 5290 throws CmsException { 5291 5292 I_CmsVfsDriver vfs = getVfsDriver(dbc); 5293 List<CmsRewriteAlias> existingAliases = vfs.readRewriteAliases( 5294 dbc, 5295 new CmsRewriteAliasFilter().setSiteRoot(siteRoot)); 5296 CmsUUID idToDelete = null; 5297 for (CmsRewriteAlias alias : existingAliases) { 5298 if (alias.getPatternString().equals(source)) { 5299 idToDelete = alias.getId(); 5300 } 5301 } 5302 if (idToDelete != null) { 5303 vfs.deleteRewriteAliases(dbc, new CmsRewriteAliasFilter().setId(idToDelete)); 5304 } 5305 CmsRewriteAlias alias = new CmsRewriteAlias(new CmsUUID(), siteRoot, source, target, mode); 5306 List<CmsRewriteAlias> aliases = new ArrayList<CmsRewriteAlias>(); 5307 aliases.add(alias); 5308 getVfsDriver(dbc).insertRewriteAliases(dbc, aliases); 5309 CmsAliasImportResult result = new CmsAliasImportResult( 5310 CmsAliasImportStatus.aliasNew, 5311 "OK", 5312 source, 5313 target, 5314 mode); 5315 return result; 5316 } 5317 5318 /** 5319 * Creates a new user by import.<p> 5320 * 5321 * @param dbc the current database context 5322 * @param id the id of the user 5323 * @param name the new name for the user 5324 * @param password the new password for the user (already encrypted) 5325 * @param firstname the firstname of the user 5326 * @param lastname the lastname of the user 5327 * @param email the email of the user 5328 * @param flags the flags for a user (for example <code>{@link I_CmsPrincipal#FLAG_ENABLED}</code>) 5329 * @param dateCreated the creation date 5330 * @param additionalInfos the additional user infos 5331 * 5332 * @return the imported user 5333 * 5334 * @throws CmsException if something goes wrong 5335 */ 5336 public CmsUser importUser( 5337 CmsDbContext dbc, 5338 String id, 5339 String name, 5340 String password, 5341 String firstname, 5342 String lastname, 5343 String email, 5344 int flags, 5345 long dateCreated, 5346 Map<String, Object> additionalInfos) 5347 throws CmsException { 5348 5349 // no space before or after the name 5350 name = name.trim(); 5351 // check the user name 5352 String userName = CmsOrganizationalUnit.getSimpleName(name); 5353 OpenCms.getValidationHandler().checkUserName(userName); 5354 if (CmsStringUtil.isEmptyOrWhitespaceOnly(userName)) { 5355 throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_BAD_USER_1, userName)); 5356 } 5357 // check the ou 5358 CmsOrganizationalUnit ou = readOrganizationalUnit(dbc, CmsOrganizationalUnit.getParentFqn(name)); 5359 5360 // check webuser ou 5361 if (ou.hasFlagWebuser() && ((flags & I_CmsPrincipal.FLAG_USER_WEBUSER) == 0)) { 5362 flags += I_CmsPrincipal.FLAG_USER_WEBUSER; 5363 } 5364 CmsUser newUser = getUserDriver(dbc).createUser( 5365 dbc, 5366 new CmsUUID(id), 5367 name, 5368 password, 5369 firstname, 5370 lastname, 5371 email, 5372 0, 5373 flags, 5374 dateCreated, 5375 additionalInfos); 5376 return newUser; 5377 } 5378 5379 /** 5380 * Increments a counter and returns its value before incrementing.<p> 5381 * 5382 * @param dbc the current database context 5383 * @param name the name of the counter which should be incremented 5384 * 5385 * @return the value of the counter 5386 * 5387 * @throws CmsException if something goes wrong 5388 */ 5389 public int incrementCounter(CmsDbContext dbc, String name) throws CmsException { 5390 5391 return getVfsDriver(dbc).incrementCounter(dbc, name); 5392 } 5393 5394 /** 5395 * Initializes the driver and sets up all required modules and connections.<p> 5396 * 5397 * @param configurationManager the configuration manager 5398 * @param dbContextFactory the db context factory 5399 * 5400 * @throws CmsException if something goes wrong 5401 * @throws Exception if something goes wrong 5402 */ 5403 public void init(CmsConfigurationManager configurationManager, I_CmsDbContextFactory dbContextFactory) 5404 throws CmsException, Exception { 5405 5406 // initialize the access-module. 5407 if (CmsLog.INIT.isInfoEnabled()) { 5408 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_PHASE4_0)); 5409 } 5410 // store local reference to the memory monitor to avoid multiple lookups through the OpenCms singelton 5411 m_monitor = OpenCms.getMemoryMonitor(); 5412 5413 CmsSystemConfiguration systemConfiguation = (CmsSystemConfiguration)configurationManager.getConfiguration( 5414 CmsSystemConfiguration.class); 5415 CmsCacheSettings settings = systemConfiguation.getCacheSettings(); 5416 5417 // initialize the key generator 5418 m_keyGenerator = (I_CmsCacheKey)Class.forName(settings.getCacheKeyGenerator()).newInstance(); 5419 5420 // initialize the HTML link validator 5421 m_htmlLinkValidator = new CmsRelationSystemValidator(this); 5422 5423 // fills the defaults if needed 5424 CmsDbContext dbc1 = dbContextFactory.getDbContext(); 5425 getUserDriver().fillDefaults(dbc1); 5426 getProjectDriver().fillDefaults(dbc1); 5427 5428 // set the driver manager in the publish engine 5429 m_publishEngine.setDriverManager(this); 5430 // create the root organizational unit if needed 5431 CmsDbContext dbc2 = dbContextFactory.getDbContext( 5432 new CmsRequestContext( 5433 readUser(dbc1, OpenCms.getDefaultUsers().getUserAdmin()), 5434 readProject(dbc1, CmsProject.ONLINE_PROJECT_ID), 5435 null, 5436 CmsSiteMatcher.DEFAULT_MATCHER, 5437 "", 5438 false, 5439 null, 5440 null, 5441 null, 5442 0, 5443 null, 5444 null, 5445 "", 5446 false)); 5447 dbc1.clear(); 5448 getUserDriver().createRootOrganizationalUnit(dbc2); 5449 dbc2.clear(); 5450 } 5451 5452 /** 5453 * Initializes the organizational unit.<p> 5454 * 5455 * @param dbc the DB context 5456 * @param ou the organizational unit 5457 */ 5458 public void initOrgUnit(CmsDbContext dbc, CmsOrganizationalUnit ou) { 5459 5460 try { 5461 dbc.setAttribute(ATTR_INIT_OU, ou); 5462 m_userDriver.fillDefaults(dbc); 5463 } finally { 5464 dbc.removeAttribute(ATTR_INIT_OU); 5465 } 5466 } 5467 5468 /** 5469 * Checks if the specified resource is inside the current project.<p> 5470 * 5471 * The project "view" is determined by a set of path prefixes. 5472 * If the resource starts with any one of this prefixes, it is considered to 5473 * be "inside" the project.<p> 5474 * 5475 * @param dbc the current database context 5476 * @param resourcename the specified resource name (full path) 5477 * 5478 * @return <code>true</code>, if the specified resource is inside the current project 5479 */ 5480 public boolean isInsideCurrentProject(CmsDbContext dbc, String resourcename) { 5481 5482 List<String> projectResources = null; 5483 try { 5484 projectResources = readProjectResources(dbc, dbc.currentProject()); 5485 } catch (CmsException e) { 5486 if (LOG.isErrorEnabled()) { 5487 LOG.error( 5488 Messages.get().getBundle().key( 5489 Messages.LOG_CHECK_RESOURCE_INSIDE_CURRENT_PROJECT_2, 5490 resourcename, 5491 dbc.currentProject().getName()), 5492 e); 5493 } 5494 return false; 5495 } 5496 return CmsProject.isInsideProject(projectResources, resourcename); 5497 } 5498 5499 /** 5500 * Checks whether the subscription driver is available.<p> 5501 * 5502 * @return true if the subscription driver is available 5503 */ 5504 public boolean isSubscriptionDriverAvailable() { 5505 5506 return m_subscriptionDriver != null; 5507 } 5508 5509 /** 5510 * Checks if a project is the tempfile project.<p> 5511 * @param project the project to test 5512 * @return true if the project is the tempfile project 5513 */ 5514 public boolean isTempfileProject(CmsProject project) { 5515 5516 return project.getName().equals("tempFileProject"); 5517 } 5518 5519 /** 5520 * Checks if one of the resources (except the resource itself) 5521 * is a sibling in a "labeled" site folder.<p> 5522 * 5523 * This method is used when creating a new sibling 5524 * (use the <code>newResource</code> parameter & <code>action = 1</code>) 5525 * or deleting/importing a resource (call with <code>action = 2</code>).<p> 5526 * 5527 * @param dbc the current database context 5528 * @param resource the resource 5529 * @param newResource absolute path for a resource sibling which will be created 5530 * @param action the action which has to be performed (1: create VFS link, 2: all other actions) 5531 * 5532 * @return <code>true</code> if the flag should be set for the resource, otherwise <code>false</code> 5533 * 5534 * @throws CmsDataAccessException if something goes wrong 5535 */ 5536 public boolean labelResource(CmsDbContext dbc, CmsResource resource, String newResource, int action) 5537 throws CmsDataAccessException { 5538 5539 // get the list of labeled site folders from the runtime property 5540 List<String> labeledSites = OpenCms.getWorkplaceManager().getLabelSiteFolders(); 5541 5542 if (labeledSites.size() == 0) { 5543 // no labeled sites defined, just return false 5544 return false; 5545 } 5546 5547 if (action == 1) { 5548 // CASE 1: a new resource is created, check the sites 5549 if (!resource.isLabeled()) { 5550 // source isn't labeled yet, so check! 5551 boolean linkInside = false; 5552 boolean sourceInside = false; 5553 for (int i = 0; i < labeledSites.size(); i++) { 5554 String curSite = labeledSites.get(i); 5555 if (newResource.startsWith(curSite)) { 5556 // the link lies in a labeled site 5557 linkInside = true; 5558 } 5559 if (resource.getRootPath().startsWith(curSite)) { 5560 // the source lies in a labeled site 5561 sourceInside = true; 5562 } 5563 if (linkInside && sourceInside) { 5564 break; 5565 } 5566 } 5567 // return true when either source or link is in labeled site, otherwise false 5568 return (linkInside != sourceInside); 5569 } 5570 // resource is already labeled 5571 return false; 5572 5573 } else { 5574 // CASE 2: the resource will be deleted or created (import) 5575 // check if at least one of the other siblings resides inside a "labeled site" 5576 // and if at least one of the other siblings resides outside a "labeled site" 5577 boolean isInside = false; 5578 boolean isOutside = false; 5579 // check if one of the other vfs links lies in a labeled site folder 5580 List<CmsResource> siblings = getVfsDriver( 5581 dbc).readSiblings(dbc, dbc.currentProject().getUuid(), resource, false); 5582 updateContextDates(dbc, siblings); 5583 Iterator<CmsResource> i = siblings.iterator(); 5584 while (i.hasNext() && (!isInside || !isOutside)) { 5585 CmsResource currentResource = i.next(); 5586 if (currentResource.equals(resource)) { 5587 // dont't check the resource itself! 5588 continue; 5589 } 5590 String curPath = currentResource.getRootPath(); 5591 boolean curInside = false; 5592 for (int k = 0; k < labeledSites.size(); k++) { 5593 if (curPath.startsWith(labeledSites.get(k))) { 5594 // the link is in the labeled site 5595 isInside = true; 5596 curInside = true; 5597 break; 5598 } 5599 } 5600 if (!curInside) { 5601 // the current link was not found in labeled site, so it is outside 5602 isOutside = true; 5603 } 5604 } 5605 // now check the new resource name if present 5606 if (newResource != null) { 5607 boolean curInside = false; 5608 for (int k = 0; k < labeledSites.size(); k++) { 5609 if (newResource.startsWith(labeledSites.get(k))) { 5610 // the new resource is in the labeled site 5611 isInside = true; 5612 curInside = true; 5613 break; 5614 } 5615 } 5616 if (!curInside) { 5617 // the new resource was not found in labeled site, so it is outside 5618 isOutside = true; 5619 } 5620 } 5621 return (isInside && isOutside); 5622 } 5623 } 5624 5625 /** 5626 * Returns the user, who had locked the resource.<p> 5627 * 5628 * A user can lock a resource, so he is the only one who can write this 5629 * resource. This methods checks, if a resource was locked. 5630 * 5631 * @param dbc the current database context 5632 * @param resource the resource 5633 * 5634 * @return the user, who had locked the resource 5635 * 5636 * @throws CmsException will be thrown, if the user has not the rights for this resource 5637 */ 5638 public CmsUser lockedBy(CmsDbContext dbc, CmsResource resource) throws CmsException { 5639 5640 return readUser(dbc, m_lockManager.getLock(dbc, resource).getEditionLock().getUserId()); 5641 } 5642 5643 /** 5644 * Locks a resource.<p> 5645 * 5646 * The <code>type</code> parameter controls what kind of lock is used.<br> 5647 * Possible values for this parameter are: <br> 5648 * <ul> 5649 * <li><code>{@link org.opencms.lock.CmsLockType#EXCLUSIVE}</code></li> 5650 * <li><code>{@link org.opencms.lock.CmsLockType#TEMPORARY}</code></li> 5651 * <li><code>{@link org.opencms.lock.CmsLockType#PUBLISH}</code></li> 5652 * </ul><p> 5653 * 5654 * @param dbc the current database context 5655 * @param resource the resource to lock 5656 * @param type type of the lock 5657 * 5658 * @throws CmsException if something goes wrong 5659 * 5660 * @see CmsObject#lockResource(String) 5661 * @see CmsObject#lockResourceTemporary(String) 5662 * @see org.opencms.file.types.I_CmsResourceType#lockResource(CmsObject, CmsSecurityManager, CmsResource, CmsLockType) 5663 */ 5664 public void lockResource(CmsDbContext dbc, CmsResource resource, CmsLockType type) throws CmsException { 5665 5666 // update the resource cache 5667 m_monitor.clearResourceCache(); 5668 5669 CmsProject project = dbc.currentProject(); 5670 5671 // add the resource to the lock dispatcher 5672 m_lockManager.addResource(dbc, resource, dbc.currentUser(), project, type); 5673 boolean changedProjectLastModified = false; 5674 if (!resource.getState().isUnchanged() && !resource.getState().isKeep()) { 5675 // update the project flag of a modified resource as "last modified inside the current project" 5676 getVfsDriver(dbc).writeLastModifiedProjectId(dbc, project, project.getUuid(), resource); 5677 changedProjectLastModified = true; 5678 } 5679 5680 // we must also clear the permission cache 5681 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PERMISSION); 5682 5683 // fire resource modification event 5684 Map<String, Object> data = new HashMap<String, Object>(2); 5685 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 5686 data.put( 5687 I_CmsEventListener.KEY_CHANGE, 5688 new Integer(changedProjectLastModified ? CHANGED_PROJECT : NOTHING_CHANGED)); 5689 data.put(I_CmsEventListener.KEY_SKIPINDEX, Boolean.TRUE); 5690 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 5691 } 5692 5693 /** 5694 * Adds the given log entry to the current user's log.<p> 5695 * 5696 * This operation works only on memory, to get the log entries actually 5697 * written to DB you have to call the {@link #updateLog(CmsDbContext)} method.<p> 5698 * 5699 * @param dbc the current database context 5700 * @param logEntry the log entry to create 5701 * @param force forces the log entry to be counted, 5702 * if not only the first log entry in a transaction will be taken into account 5703 */ 5704 public void log(CmsDbContext dbc, CmsLogEntry logEntry, boolean force) { 5705 5706 if (dbc == null) { 5707 return; 5708 } 5709 // check log level 5710 if (!logEntry.getType().isActive()) { 5711 // do not log inactive entries 5712 return; 5713 } 5714 // if not forcing 5715 if (!force) { 5716 // operation already logged 5717 boolean abort = (dbc.getAttribute(CmsLogEntry.ATTR_LOG_ENTRY) != null); 5718 // disabled logging from outside 5719 abort |= (dbc.getRequestContext().getAttribute(CmsLogEntry.ATTR_LOG_ENTRY) != null); 5720 if (abort) { 5721 return; 5722 } 5723 } 5724 // prevent several entries for the same operation 5725 dbc.setAttribute(CmsLogEntry.ATTR_LOG_ENTRY, Boolean.TRUE); 5726 // keep it for later 5727 m_log.add(logEntry); 5728 } 5729 5730 /** 5731 * Attempts to authenticate a user into OpenCms with the given password. 5732 * 5733 * <p>The method can be used in multiple modes (see the CmsDriverManager.LoginUserMode enum): Standard mode is the mode for actually logging in a user, 5734 * while check mode merely checks the login details without firing the events normally fired during login, and without modifying the user. However, 5735 * in the case an incorrect password is given, the invalid login counter is still incremented. 5736 * 5737 * @param dbc the current database context 5738 * @param userName the name of the user to be logged in 5739 * @param password the password of the user 5740 * @param secondFactorInfo the second factor information for 2FA (may be null) 5741 * @param remoteAddress the ip address of the request 5742 * @param mode the mode to use (real login or check only) 5743 * 5744 * @return the logged in user 5745 * 5746 * @throws CmsAuthentificationException if the login was not successful 5747 * @throws CmsDataAccessException in case of errors accessing the database 5748 * @throws CmsPasswordEncryptionException in case of errors encrypting the users password 5749 */ 5750 public CmsUser loginUser( 5751 CmsDbContext dbc, 5752 String userName, 5753 String password, 5754 CmsSecondFactorInfo secondFactorInfo, 5755 String remoteAddress, 5756 LoginUserMode mode) 5757 throws CmsAuthentificationException, CmsDataAccessException, CmsPasswordEncryptionException { 5758 5759 if (CmsStringUtil.isEmptyOrWhitespaceOnly(password)) { 5760 throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_USER_1, userName)); 5761 } 5762 CmsUser newUser; 5763 CmsUser userCopy; 5764 try { 5765 // read the user from the driver to avoid the cache 5766 newUser = getUserDriver(dbc).readUser(dbc, userName, password, remoteAddress); 5767 userCopy = newUser.clone(); 5768 userName = newUser.getName(); 5769 5770 } catch (CmsDbEntryNotFoundException e) { 5771 // this indicates that the username / password combination does not exist 5772 // any other exception indicates database issues, these are not catched here 5773 5774 // check if a user with this name exists at all 5775 CmsUser user = null; 5776 try { 5777 user = readUser(dbc, userName); 5778 userName = user.getName(); 5779 } catch (CmsDataAccessException e2) { 5780 // apparently this user does not exist in the database 5781 } 5782 5783 if (user != null) { 5784 if (dbc.currentUser().isGuestUser()) { 5785 // add an invalid login attempt for this user to the storage 5786 OpenCms.getLoginManager().addInvalidLogin(userName, remoteAddress); 5787 } 5788 OpenCms.getLoginManager().checkInvalidLogins(userName, remoteAddress); 5789 throw new CmsAuthentificationException( 5790 org.opencms.security.Messages.get().container( 5791 org.opencms.security.Messages.ERR_LOGIN_FAILED_2, 5792 userName, 5793 remoteAddress), 5794 e); 5795 } else { 5796 String userOu = CmsOrganizationalUnit.getParentFqn(userName); 5797 if (userOu != null) { 5798 String parentOu = CmsOrganizationalUnit.getParentFqn(userOu); 5799 if (parentOu != null) { 5800 // try a higher level ou 5801 String uName = CmsOrganizationalUnit.getSimpleName(userName); 5802 return loginUser(dbc, parentOu + uName, password, secondFactorInfo, remoteAddress, mode); 5803 } 5804 } 5805 throw new CmsAuthentificationException( 5806 org.opencms.security.Messages.get().container( 5807 org.opencms.security.Messages.ERR_LOGIN_FAILED_NO_USER_2, 5808 userName, 5809 remoteAddress), 5810 e); 5811 } 5812 } 5813 // check if the "enabled" flag is set for the user 5814 if (!newUser.isEnabled()) { 5815 // user is disabled, throw a securiy exception 5816 throw new CmsAuthentificationException( 5817 org.opencms.security.Messages.get().container( 5818 org.opencms.security.Messages.ERR_LOGIN_FAILED_DISABLED_2, 5819 userName, 5820 remoteAddress)); 5821 } 5822 5823 if (mode == LoginUserMode.standard) { 5824 CmsTwoFactorAuthenticationHandler handler = OpenCms.getTwoFactorAuthenticationHandler(); 5825 if (handler.needsTwoFactorAuthentication(newUser)) { 5826 // note that password check must already have been successful at this stage 5827 5828 if (handler.hasSecondFactor(newUser)) { 5829 if (!handler.verifySecondFactor(newUser, secondFactorInfo)) { 5830 if (dbc.currentUser().isGuestUser()) { 5831 // add an invalid login attempt for this user to the storage 5832 OpenCms.getLoginManager().addInvalidLogin(userName, remoteAddress); 5833 } 5834 OpenCms.getLoginManager().checkInvalidLogins(userName, remoteAddress); 5835 throw new CmsAuthentificationException( 5836 org.opencms.security.Messages.get().container( 5837 org.opencms.security.Messages.ERR_VERIFICATION_FAILED_1, 5838 userName)); 5839 } 5840 } else { 5841 try { 5842 if (handler.setUpAndVerifySecondFactor(newUser, secondFactorInfo)) { 5843 LOG.info("Second factor setup successful for user " + newUser.getName()); 5844 } else { 5845 if (dbc.currentUser().isGuestUser()) { 5846 // add an invalid login attempt for this user to the storage 5847 OpenCms.getLoginManager().addInvalidLogin(userName, remoteAddress); 5848 } 5849 OpenCms.getLoginManager().checkInvalidLogins(userName, remoteAddress); 5850 throw new CmsAuthentificationException( 5851 org.opencms.security.Messages.get().container( 5852 org.opencms.security.Messages.ERR_VERIFICATION_FAILED_1, 5853 userName)); 5854 } 5855 } catch (CmsSecondFactorSetupException e) { 5856 throw new CmsAuthentificationException( 5857 org.opencms.security.Messages.get().container( 5858 org.opencms.security.Messages.ERR_VERIFICATION_FAILED_1, 5859 userName), 5860 e); 5861 } 5862 } 5863 } 5864 } 5865 if (dbc.currentUser().isGuestUser()) { 5866 // check if this account is temporarily disabled because of too many invalid login attempts 5867 // this will throw an exception if the test fails 5868 OpenCms.getLoginManager().checkInvalidLogins(userName, remoteAddress); 5869 if (mode == LoginUserMode.standard) { 5870 // test successful, remove all previous invalid login attempts for this user from the storage 5871 OpenCms.getLoginManager().removeInvalidLogins(userName, remoteAddress); 5872 } 5873 } 5874 5875 if (!m_securityManager.hasRole( 5876 dbc, 5877 newUser, 5878 CmsRole.ADMINISTRATOR.forOrgUnit(dbc.getRequestContext().getOuFqn()))) { 5879 // new user is not Administrator, check if login is currently allowed 5880 OpenCms.getLoginManager().checkLoginAllowed(); 5881 } 5882 5883 if (mode == LoginUserMode.standard) { 5884 5885 newUser.setLastlogin(System.currentTimeMillis()); 5886 m_monitor.clearUserCache(newUser); 5887 5888 // write the changed user object back to the user driver 5889 Map<String, Object> additionalInfosForRepositories = OpenCms.getRepositoryManager().getAdditionalInfoForLogin( 5890 newUser.getName(), 5891 password); 5892 boolean requiresAddInfoUpdate = false; 5893 5894 // check for changes 5895 for (Entry<String, Object> entry : additionalInfosForRepositories.entrySet()) { 5896 Object value = entry.getValue(); 5897 Object current = newUser.getAdditionalInfo(entry.getKey()); 5898 if (((value == null) && (current != null)) || ((value != null) && !value.equals(current))) { 5899 requiresAddInfoUpdate = true; 5900 break; 5901 } 5902 } 5903 if (requiresAddInfoUpdate) { 5904 newUser.getAdditionalInfo().putAll(additionalInfosForRepositories); 5905 } 5906 String lastPasswordChange = (String)newUser.getAdditionalInfo( 5907 CmsUserSettings.ADDITIONAL_INFO_LAST_PASSWORD_CHANGE); 5908 if (lastPasswordChange == null) { 5909 requiresAddInfoUpdate = true; 5910 newUser.getAdditionalInfo().put( 5911 CmsUserSettings.ADDITIONAL_INFO_LAST_PASSWORD_CHANGE, 5912 "" + System.currentTimeMillis()); 5913 } 5914 if (!requiresAddInfoUpdate) { 5915 dbc.setAttribute(ATTRIBUTE_LOGIN, newUser.getName()); 5916 } 5917 5918 if (mode == LoginUserMode.standard) { 5919 OpenCms.getTwoFactorAuthenticationHandler().trackUserChange(dbc.getRequestContext(), userCopy, newUser); 5920 getUserDriver(dbc).writeUser(dbc, newUser); 5921 } 5922 int changes = CmsUser.FLAG_LAST_LOGIN; 5923 5924 // check if we need to update the password 5925 if (!OpenCms.getPasswordHandler().checkPassword(password, newUser.getPassword(), false) 5926 && OpenCms.getPasswordHandler().checkPassword(password, newUser.getPassword(), true)) { 5927 // the password does not check with the current hash algorithm but with the fall back, update the password 5928 getUserDriver(dbc).writePassword(dbc, userName, password, password); 5929 changes = changes | CmsUser.FLAG_CORE_DATA; 5930 } 5931 5932 // update cache 5933 m_monitor.cacheUser(newUser); 5934 5935 // invalidate all user dependent caches 5936 m_monitor.flushCache( 5937 CmsMemoryMonitor.CacheType.ACL, 5938 CmsMemoryMonitor.CacheType.GROUP, 5939 CmsMemoryMonitor.CacheType.ORG_UNIT, 5940 CmsMemoryMonitor.CacheType.USER_LIST, 5941 CmsMemoryMonitor.CacheType.PERMISSION, 5942 CmsMemoryMonitor.CacheType.RESOURCE_LIST); 5943 5944 // fire user modified event 5945 Map<String, Object> eventData = new HashMap<String, Object>(); 5946 eventData.put(I_CmsEventListener.KEY_USER_ID, newUser.getId().toString()); 5947 eventData.put(I_CmsEventListener.KEY_USER_NAME, newUser.getName()); 5948 eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_WRITE_USER); 5949 eventData.put(I_CmsEventListener.KEY_USER_CHANGES, Integer.valueOf(changes)); 5950 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); 5951 } 5952 5953 // return the user object read from the driver 5954 return newUser.clone(); 5955 } 5956 5957 /** 5958 * Lookup and read the user or group with the given UUID.<p> 5959 * 5960 * @param dbc the current database context 5961 * @param principalId the UUID of the principal to lookup 5962 * 5963 * @return the principal (group or user) if found, otherwise <code>null</code> 5964 */ 5965 public I_CmsPrincipal lookupPrincipal(CmsDbContext dbc, CmsUUID principalId) { 5966 5967 try { 5968 CmsGroup group = getUserDriver(dbc).readGroup(dbc, principalId); 5969 if (group != null) { 5970 return group; 5971 } 5972 } catch (Exception e) { 5973 // ignore this exception 5974 } 5975 5976 try { 5977 CmsUser user = readUser(dbc, principalId); 5978 if (user != null) { 5979 return user; 5980 } 5981 } catch (Exception e) { 5982 // ignore this exception 5983 } 5984 5985 return null; 5986 } 5987 5988 /** 5989 * Lookup and read the user or group with the given name.<p> 5990 * 5991 * @param dbc the current database context 5992 * @param principalName the name of the principal to lookup 5993 * 5994 * @return the principal (group or user) if found, otherwise <code>null</code> 5995 */ 5996 public I_CmsPrincipal lookupPrincipal(CmsDbContext dbc, String principalName) { 5997 5998 try { 5999 CmsGroup group = getUserDriver(dbc).readGroup(dbc, principalName); 6000 if (group != null) { 6001 return group; 6002 } 6003 } catch (Exception e) { 6004 // ignore this exception 6005 } 6006 6007 try { 6008 CmsUser user = readUser(dbc, principalName); 6009 if (user != null) { 6010 return user; 6011 } 6012 } catch (Exception e) { 6013 // ignore this exception 6014 } 6015 6016 return null; 6017 } 6018 6019 /** 6020 * Mark the given resource as visited by the user.<p> 6021 * 6022 * @param dbc the database context 6023 * @param poolName the name of the database pool to use 6024 * @param resource the resource to mark as visited 6025 * @param user the user that visited the resource 6026 * 6027 * @throws CmsException if something goes wrong 6028 */ 6029 public void markResourceAsVisitedBy(CmsDbContext dbc, String poolName, CmsResource resource, CmsUser user) 6030 throws CmsException { 6031 6032 getSubscriptionDriver().markResourceAsVisitedBy(dbc, poolName, resource, user); 6033 } 6034 6035 /** 6036 * Moves a resource.<p> 6037 * 6038 * You must ensure that the parent of the destination path is an absolute, valid and 6039 * existing VFS path. Relative paths from the source are not supported.<p> 6040 * 6041 * The moved resource will always be locked to the current user 6042 * after the move operation.<p> 6043 * 6044 * In case the target resource already exists, it will be overwritten with the 6045 * source resource if possible.<p> 6046 * 6047 * @param dbc the current database context 6048 * @param source the resource to move 6049 * @param destination the name of the move destination with complete path 6050 * @param internal if set nothing more than the path is modified 6051 * 6052 * @throws CmsException if something goes wrong 6053 * 6054 * @see CmsSecurityManager#moveResource(CmsRequestContext, CmsResource, String) 6055 */ 6056 public void moveResource(CmsDbContext dbc, CmsResource source, String destination, boolean internal) 6057 throws CmsException { 6058 6059 CmsFolder destinationFolder = readFolder(dbc, CmsResource.getParentFolder(destination), CmsResourceFilter.ALL); 6060 m_securityManager.checkPermissions( 6061 dbc, 6062 destinationFolder, 6063 CmsPermissionSet.ACCESS_WRITE, 6064 false, 6065 CmsResourceFilter.ALL); 6066 6067 if (source.isFolder()) { 6068 m_monitor.flushCache(CmsMemoryMonitor.CacheType.HAS_ROLE, CmsMemoryMonitor.CacheType.ROLE_LIST); 6069 } 6070 getVfsDriver(dbc).moveResource(dbc, dbc.getRequestContext().getCurrentProject().getUuid(), source, destination); 6071 6072 if (!internal) { 6073 CmsResourceState newState = CmsResource.STATE_CHANGED; 6074 if (source.getState().isNew()) { 6075 newState = CmsResource.STATE_NEW; 6076 } else if (source.getState().isDeleted()) { 6077 newState = CmsResource.STATE_DELETED; 6078 } 6079 source.setState(newState); 6080 // safe since this operation always uses the ids instead of the resource path 6081 getVfsDriver(dbc).writeResourceState( 6082 dbc, 6083 dbc.currentProject(), 6084 source, 6085 CmsDriverManager.UPDATE_STRUCTURE_STATE, 6086 false); 6087 // log it 6088 log( 6089 dbc, 6090 new CmsLogEntry( 6091 dbc, 6092 source.getStructureId(), 6093 CmsLogEntryType.RESOURCE_MOVED, 6094 new String[] {source.getRootPath(), destination}), 6095 false); 6096 } 6097 6098 CmsResource destRes = readResource(dbc, destination, CmsResourceFilter.ALL); 6099 // move lock 6100 m_lockManager.moveResource(source.getRootPath(), destRes.getRootPath()); 6101 6102 // flush all relevant caches 6103 m_monitor.clearAccessControlListCache(); 6104 m_monitor.flushCache( 6105 CmsMemoryMonitor.CacheType.PROPERTY, 6106 CmsMemoryMonitor.CacheType.PROPERTY_LIST, 6107 CmsMemoryMonitor.CacheType.PROJECT_RESOURCES); 6108 6109 List<CmsResource> resources = new ArrayList<CmsResource>(4); 6110 // source 6111 resources.add(source); 6112 try { 6113 resources.add(readFolder(dbc, CmsResource.getParentFolder(source.getRootPath()), CmsResourceFilter.ALL)); 6114 } catch (Exception e) { 6115 if (LOG.isDebugEnabled()) { 6116 LOG.debug(e.getLocalizedMessage(), e); 6117 } 6118 } 6119 // destination 6120 resources.add(destRes); 6121 resources.add(destinationFolder); 6122 6123 Map<String, Object> eventData = new HashMap<String, Object>(); 6124 eventData.put(I_CmsEventListener.KEY_RESOURCES, resources); 6125 eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); 6126 6127 // fire the events 6128 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MOVED, eventData)); 6129 } 6130 6131 /** 6132 * Moves a resource to the "lost and found" folder.<p> 6133 * 6134 * The method can also be used to check get the name of a resource 6135 * in the "lost and found" folder only without actually moving the 6136 * the resource. To do this, the <code>returnNameOnly</code> flag 6137 * must be set to <code>true</code>.<p> 6138 * 6139 * @param dbc the current database context 6140 * @param resource the resource to apply this operation to 6141 * @param returnNameOnly if <code>true</code>, only the name of the resource in the "lost and found" 6142 * folder is returned, the move operation is not really performed 6143 * 6144 * @return the name of the resource inside the "lost and found" folder 6145 * 6146 * @throws CmsException if something goes wrong 6147 * @throws CmsIllegalArgumentException if the <code>resourcename</code> argument is null or of length 0 6148 * 6149 * @see CmsObject#moveToLostAndFound(String) 6150 * @see CmsObject#getLostAndFoundName(String) 6151 */ 6152 public String moveToLostAndFound(CmsDbContext dbc, CmsResource resource, boolean returnNameOnly) 6153 throws CmsException, CmsIllegalArgumentException { 6154 6155 String resourcename = dbc.removeSiteRoot(resource.getRootPath()); 6156 6157 String siteRoot = dbc.getRequestContext().getSiteRoot(); 6158 dbc.getRequestContext().setSiteRoot(""); 6159 String destination = CmsDriverManager.LOST_AND_FOUND_FOLDER + resourcename; 6160 // create the required folders if necessary 6161 try { 6162 // collect all folders... 6163 String folderPath = CmsResource.getParentFolder(destination); 6164 folderPath = folderPath.substring(1, folderPath.length() - 1); // cut out leading and trailing '/' 6165 Iterator<String> folders = CmsStringUtil.splitAsList(folderPath, '/').iterator(); 6166 // ...now create them.... 6167 folderPath = "/"; 6168 while (folders.hasNext()) { 6169 folderPath += folders.next().toString() + "/"; 6170 try { 6171 readFolder(dbc, folderPath, CmsResourceFilter.IGNORE_EXPIRATION); 6172 } catch (Exception e1) { 6173 if (returnNameOnly) { 6174 // we can use the original name without risk, and we do not need to recreate the parent folders 6175 break; 6176 } 6177 // the folder is not existing, so create it 6178 createResource( 6179 dbc, 6180 folderPath, 6181 CmsResourceTypeFolder.RESOURCE_TYPE_ID, 6182 null, 6183 new ArrayList<CmsProperty>()); 6184 } 6185 } 6186 // check if this resource name does already exist 6187 // if so add a postfix to the name 6188 String des = destination; 6189 int postfix = 1; 6190 boolean found = true; 6191 while (found) { 6192 try { 6193 // try to read the file..... 6194 found = true; 6195 readResource(dbc, des, CmsResourceFilter.ALL); 6196 // ....it's there, so add a postfix and try again 6197 String path = destination.substring(0, destination.lastIndexOf('/') + 1); 6198 String filename = destination.substring(destination.lastIndexOf('/') + 1, destination.length()); 6199 6200 des = path; 6201 6202 if (filename.lastIndexOf('.') > 0) { 6203 des += filename.substring(0, filename.lastIndexOf('.')); 6204 } else { 6205 des += filename; 6206 } 6207 des += "_" + postfix; 6208 if (filename.lastIndexOf('.') > 0) { 6209 des += filename.substring(filename.lastIndexOf('.'), filename.length()); 6210 } 6211 postfix++; 6212 } catch (CmsException e3) { 6213 // the file does not exist, so we can use this filename 6214 found = false; 6215 } 6216 } 6217 destination = des; 6218 6219 if (!returnNameOnly) { 6220 // do not use the move semantic here! to prevent links pointing to the lost & found folder 6221 copyResource(dbc, resource, destination, CmsResource.COPY_AS_SIBLING); 6222 deleteResource(dbc, resource, CmsResource.DELETE_PRESERVE_SIBLINGS); 6223 } 6224 } catch (CmsException e2) { 6225 throw e2; 6226 } finally { 6227 // set the site root to the old value again 6228 dbc.getRequestContext().setSiteRoot(siteRoot); 6229 } 6230 return destination; 6231 } 6232 6233 /** 6234 * Gets a new driver instance.<p> 6235 * 6236 * @param dbc the database context 6237 * @param configurationManager the configuration manager 6238 * @param driverName the driver name 6239 * @param successiveDrivers the list of successive drivers 6240 * 6241 * @return the driver object 6242 * @throws CmsInitException if the selected driver could not be initialized 6243 */ 6244 public Object newDriverInstance( 6245 CmsDbContext dbc, 6246 CmsConfigurationManager configurationManager, 6247 String driverName, 6248 List<String> successiveDrivers) 6249 throws CmsInitException { 6250 6251 Class<?> driverClass = null; 6252 I_CmsDriver driver = null; 6253 6254 try { 6255 // try to get the class 6256 driverClass = Class.forName(driverName); 6257 if (CmsLog.INIT.isInfoEnabled()) { 6258 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_START_1, driverName)); 6259 } 6260 6261 // try to create a instance 6262 driver = (I_CmsDriver)driverClass.newInstance(); 6263 if (CmsLog.INIT.isInfoEnabled()) { 6264 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_INITIALIZING_1, driverName)); 6265 } 6266 6267 // invoke the init-method of this access class 6268 driver.init(dbc, configurationManager, successiveDrivers, this); 6269 if (CmsLog.INIT.isInfoEnabled()) { 6270 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_INIT_FINISHED_0)); 6271 } 6272 6273 } catch (Throwable t) { 6274 CmsMessageContainer message = Messages.get().container( 6275 Messages.ERR_ERROR_INITIALIZING_DRIVER_1, 6276 driverName); 6277 if (LOG.isErrorEnabled()) { 6278 LOG.error(message.key(), t); 6279 } 6280 throw new CmsInitException(message, t); 6281 } 6282 6283 return driver; 6284 } 6285 6286 /** 6287 * Method to create a new instance of a driver.<p> 6288 * 6289 * @param configuration the configurations from the propertyfile 6290 * @param driverName the class name of the driver 6291 * @param driverPoolUrl the pool url for the driver 6292 * @return an initialized instance of the driver 6293 * @throws CmsException if something goes wrong 6294 */ 6295 public Object newDriverInstance(CmsParameterConfiguration configuration, String driverName, String driverPoolUrl) 6296 throws CmsException { 6297 6298 Class<?>[] initParamClasses = {CmsParameterConfiguration.class, String.class, CmsDriverManager.class}; 6299 Object[] initParams = {configuration, driverPoolUrl, this}; 6300 6301 Class<?> driverClass = null; 6302 Object driver = null; 6303 6304 try { 6305 // try to get the class 6306 driverClass = Class.forName(driverName); 6307 if (CmsLog.INIT.isInfoEnabled()) { 6308 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_START_1, driverName)); 6309 } 6310 6311 // try to create a instance 6312 driver = driverClass.newInstance(); 6313 if (CmsLog.INIT.isInfoEnabled()) { 6314 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_INITIALIZING_1, driverName)); 6315 } 6316 6317 // invoke the init-method of this access class 6318 driver.getClass().getMethod("init", initParamClasses).invoke(driver, initParams); 6319 if (CmsLog.INIT.isInfoEnabled()) { 6320 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_INIT_FINISHED_1, driverPoolUrl)); 6321 } 6322 6323 } catch (Exception exc) { 6324 6325 CmsMessageContainer message = Messages.get().container(Messages.ERR_INIT_DRIVER_MANAGER_1); 6326 if (LOG.isFatalEnabled()) { 6327 LOG.fatal(message.key(), exc); 6328 } 6329 throw new CmsDbException(message, exc); 6330 6331 } 6332 6333 return driver; 6334 } 6335 6336 /** 6337 * Method to create a new instance of a pool.<p> 6338 * 6339 * @param configuration the configurations from the propertyfile 6340 * @param poolName the configuration name of the pool 6341 * 6342 * @throws CmsInitException if the pools could not be initialized 6343 */ 6344 public void newPoolInstance(CmsParameterConfiguration configuration, String poolName) throws CmsInitException { 6345 6346 CmsDbPoolV11 pool; 6347 6348 try { 6349 pool = new CmsDbPoolV11(configuration, poolName); 6350 } catch (Exception e) { 6351 6352 CmsMessageContainer message = Messages.get().container(Messages.ERR_INIT_CONN_POOL_1, poolName); 6353 if (LOG.isErrorEnabled()) { 6354 LOG.error(message.key(), e); 6355 } 6356 throw new CmsInitException(message, e); 6357 } 6358 addPool(pool); 6359 } 6360 6361 /** 6362 * Publishes the given publish job.<p> 6363 * 6364 * @param cms the cms context 6365 * @param dbc the db context 6366 * @param publishList the list of resources to publish 6367 * @param report the report to write to 6368 * 6369 * @throws CmsException if something goes wrong 6370 */ 6371 public void publishJob(CmsObject cms, CmsDbContext dbc, CmsPublishList publishList, I_CmsReport report) 6372 throws CmsException { 6373 6374 try { 6375 // check state and lock 6376 List<CmsResource> allResources = new ArrayList<CmsResource>(publishList.getFolderList()); 6377 allResources.addAll(publishList.getDeletedFolderList()); 6378 allResources.addAll(publishList.getFileList()); 6379 Iterator<CmsResource> itResources = allResources.iterator(); 6380 while (itResources.hasNext()) { 6381 CmsResource resource = itResources.next(); 6382 try { 6383 resource = readResource(dbc, resource.getStructureId(), CmsResourceFilter.ALL); 6384 } catch (CmsVfsResourceNotFoundException e) { 6385 continue; 6386 } 6387 if (resource.getState().isUnchanged()) { 6388 // remove files that were published by a concurrent job 6389 if (LOG.isDebugEnabled()) { 6390 LOG.debug( 6391 Messages.get().getBundle().key( 6392 Messages.RPT_PUBLISH_REMOVED_RESOURCE_1, 6393 dbc.removeSiteRoot(resource.getRootPath()))); 6394 } 6395 publishList.remove(resource); 6396 unlockResource(dbc, resource, true, true); 6397 continue; 6398 } 6399 CmsLock lock = m_lockManager.getLock(dbc, resource, false); 6400 if (!lock.getSystemLock().isPublish()) { 6401 // remove files that are not locked for publishing 6402 if (LOG.isDebugEnabled()) { 6403 LOG.debug( 6404 Messages.get().getBundle().key( 6405 Messages.RPT_PUBLISH_REMOVED_RESOURCE_1, 6406 dbc.removeSiteRoot(resource.getRootPath()))); 6407 } 6408 publishList.remove(resource); 6409 continue; 6410 } 6411 } 6412 6413 CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); 6414 6415 // clear the cache 6416 m_monitor.clearCacheForPublishing(); 6417 6418 int publishTag = getNextPublishTag(dbc); 6419 getProjectDriver(dbc).publishProject(dbc, report, onlineProject, publishList, publishTag); 6420 6421 // iterate the initialized module action instances 6422 Iterator<String> i = OpenCms.getModuleManager().getModuleNames().iterator(); 6423 while (i.hasNext()) { 6424 CmsModule module = OpenCms.getModuleManager().getModule(i.next()); 6425 if ((module != null) && (module.getActionInstance() != null)) { 6426 module.getActionInstance().publishProject(cms, publishList, publishTag, report); 6427 } 6428 } 6429 6430 boolean temporaryProject = (cms.getRequestContext().getCurrentProject().getType() == CmsProject.PROJECT_TYPE_TEMPORARY); 6431 // the project was stored in the history tables for history 6432 // it will be deleted if the project_flag is PROJECT_TYPE_TEMPORARY 6433 if ((temporaryProject) && (!publishList.isDirectPublish())) { 6434 try { 6435 getProjectDriver(dbc).deleteProject(dbc, dbc.currentProject()); 6436 } catch (CmsException e) { 6437 LOG.error( 6438 Messages.get().getBundle().key( 6439 Messages.LOG_DELETE_TEMP_PROJECT_FAILED_1, 6440 cms.getRequestContext().getCurrentProject().getName())); 6441 } 6442 // if project was temporary set context to online project 6443 cms.getRequestContext().setCurrentProject(onlineProject); 6444 } 6445 } finally { 6446 // clear the cache again 6447 m_monitor.clearCacheForPublishing(); 6448 } 6449 } 6450 6451 /** 6452 * Publishes the resources of a specified publish list.<p> 6453 * 6454 * @param cms the current request context 6455 * @param dbc the current database context 6456 * @param publishList a publish list 6457 * @param report an instance of <code>{@link I_CmsReport}</code> to print messages 6458 * 6459 * @throws CmsException if something goes wrong 6460 * 6461 * @see #fillPublishList(CmsDbContext, CmsPublishList) 6462 */ 6463 public synchronized void publishProject( 6464 CmsObject cms, 6465 CmsDbContext dbc, 6466 CmsPublishList publishList, 6467 I_CmsReport report) 6468 throws CmsException { 6469 6470 // check the parent folders 6471 checkParentFolders(dbc, publishList); 6472 ensureSubResourcesOfMovedFoldersPublished(cms, dbc, publishList); 6473 OpenCms.getPublishManager().getPublishListVerifier().checkPublishList(publishList); 6474 6475 try { 6476 // fire an event that a project is to be published 6477 Map<String, Object> eventData = new HashMap<String, Object>(); 6478 eventData.put(I_CmsEventListener.KEY_REPORT, report); 6479 eventData.put(I_CmsEventListener.KEY_PUBLISHLIST, publishList); 6480 eventData.put(I_CmsEventListener.KEY_PROJECTID, dbc.currentProject().getUuid()); 6481 eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); 6482 CmsEvent beforePublishEvent = new CmsEvent(I_CmsEventListener.EVENT_BEFORE_PUBLISH_PROJECT, eventData); 6483 OpenCms.fireCmsEvent(beforePublishEvent); 6484 } catch (Throwable t) { 6485 if (report != null) { 6486 report.addError(t); 6487 report.println(t); 6488 } 6489 if (LOG.isErrorEnabled()) { 6490 LOG.error(t.getLocalizedMessage(), t); 6491 } 6492 } 6493 6494 // lock all resources with the special publish lock 6495 Iterator<CmsResource> itResources = new ArrayList<CmsResource>(publishList.getAllResources()).iterator(); 6496 while (itResources.hasNext()) { 6497 CmsResource resource = itResources.next(); 6498 CmsLock lock = m_lockManager.getLock(dbc, resource, false); 6499 if (lock.getSystemLock().isUnlocked() && lock.isLockableBy(dbc.currentUser())) { 6500 if (getLock(dbc, resource).getEditionLock().isNullLock()) { 6501 lockResource(dbc, resource, CmsLockType.PUBLISH); 6502 } else { 6503 changeLock(dbc, resource, CmsLockType.PUBLISH); 6504 } 6505 } else if (lock.getSystemLock().isPublish()) { 6506 if (LOG.isWarnEnabled()) { 6507 LOG.warn( 6508 Messages.get().getBundle().key( 6509 Messages.RPT_PUBLISH_REMOVED_RESOURCE_1, 6510 dbc.removeSiteRoot(resource.getRootPath()))); 6511 } 6512 // remove files that are already waiting to be published 6513 publishList.remove(resource); 6514 continue; 6515 } else { 6516 // this is needed to fix TestPublishIsssues#testPublishScenarioE 6517 changeLock(dbc, resource, CmsLockType.PUBLISH); 6518 } 6519 // now re-check the lock state 6520 lock = m_lockManager.getLock(dbc, resource, false); 6521 if (!lock.getSystemLock().isPublish()) { 6522 if (report != null) { 6523 report.println( 6524 Messages.get().container( 6525 Messages.RPT_PUBLISH_REMOVED_RESOURCE_1, 6526 dbc.removeSiteRoot(resource.getRootPath())), 6527 I_CmsReport.FORMAT_WARNING); 6528 } 6529 if (LOG.isWarnEnabled()) { 6530 LOG.warn( 6531 Messages.get().getBundle().key( 6532 Messages.RPT_PUBLISH_REMOVED_RESOURCE_1, 6533 dbc.removeSiteRoot(resource.getRootPath()))); 6534 } 6535 // remove files that could not be locked 6536 publishList.remove(resource); 6537 } 6538 } 6539 6540 // enqueue the publish job 6541 CmsException enqueueException = null; 6542 try { 6543 m_publishEngine.enqueuePublishJob(cms, publishList, report); 6544 } catch (CmsException exc) { 6545 enqueueException = exc; 6546 } 6547 6548 // if an exception was raised, remove the publish locks 6549 // and throw the exception again 6550 if (enqueueException != null) { 6551 itResources = publishList.getAllResources().iterator(); 6552 while (itResources.hasNext()) { 6553 CmsResource resource = itResources.next(); 6554 CmsLock lock = m_lockManager.getLock(dbc, resource, false); 6555 if (lock.getSystemLock().isPublish() 6556 && lock.getSystemLock().isOwnedInProjectBy( 6557 cms.getRequestContext().getCurrentUser(), 6558 cms.getRequestContext().getCurrentProject())) { 6559 unlockResource(dbc, resource, true, true); 6560 } 6561 } 6562 6563 throw enqueueException; 6564 } 6565 } 6566 6567 /** 6568 * Transfers the new URL name mappings (if any) for a given resource to the online project.<p> 6569 * 6570 * @param dbc the current database context 6571 * @param res the resource whose new URL name mappings should be transferred to the online project 6572 * 6573 * @throws CmsDataAccessException if something goes wrong 6574 */ 6575 public void publishUrlNameMapping(CmsDbContext dbc, CmsResource res) throws CmsDataAccessException { 6576 6577 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 6578 6579 if (res.getState().isDeleted()) { 6580 // remove both offline and online mappings 6581 CmsUrlNameMappingFilter idFilter = CmsUrlNameMappingFilter.ALL.filterStructureId(res.getStructureId()); 6582 vfsDriver.deleteUrlNameMappingEntries(dbc, true, idFilter); 6583 vfsDriver.deleteUrlNameMappingEntries(dbc, false, idFilter); 6584 } else { 6585 // copy the new entries to the online table 6586 List<CmsUrlNameMappingEntry> entries = vfsDriver.readUrlNameMappingEntries( 6587 dbc, 6588 false, 6589 CmsUrlNameMappingFilter.ALL.filterStructureId(res.getStructureId()).filterStates( 6590 CmsUrlNameMappingEntry.MAPPING_STATUS_NEW, 6591 CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH)); 6592 6593 boolean isReplaceOnPublish = false; 6594 for (CmsUrlNameMappingEntry entry : entries) { 6595 isReplaceOnPublish |= entry.getState() == CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH; 6596 } 6597 6598 if (!entries.isEmpty()) { 6599 6600 long now = System.currentTimeMillis(); 6601 if (isReplaceOnPublish) { 6602 vfsDriver.deleteUrlNameMappingEntries( 6603 dbc, 6604 true, 6605 CmsUrlNameMappingFilter.ALL.filterStructureId(res.getStructureId())); 6606 vfsDriver.deleteUrlNameMappingEntries( 6607 dbc, 6608 false, 6609 CmsUrlNameMappingFilter.ALL.filterStructureId(res.getStructureId())); 6610 } 6611 6612 for (CmsUrlNameMappingEntry entry : entries) { 6613 CmsUrlNameMappingFilter nameFilter = CmsUrlNameMappingFilter.ALL.filterName(entry.getName()); 6614 if (!isReplaceOnPublish) { // we already handled the other case above 6615 vfsDriver.deleteUrlNameMappingEntries(dbc, true, nameFilter); 6616 vfsDriver.deleteUrlNameMappingEntries(dbc, false, nameFilter); 6617 } 6618 } 6619 for (CmsUrlNameMappingEntry entry : entries) { 6620 CmsUrlNameMappingEntry newEntry = new CmsUrlNameMappingEntry( 6621 entry.getName(), 6622 entry.getStructureId(), 6623 entry.getState() == CmsUrlNameMappingEntry.MAPPING_STATUS_NEW 6624 ? CmsUrlNameMappingEntry.MAPPING_STATUS_PUBLISHED 6625 : CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH_PUBLISHED, 6626 now, 6627 entry.getLocale()); 6628 vfsDriver.addUrlNameMappingEntry(dbc, true, newEntry); 6629 vfsDriver.addUrlNameMappingEntry(dbc, false, newEntry); 6630 } 6631 } 6632 } 6633 } 6634 6635 /** 6636 * Reads an access control entry from the cms.<p> 6637 * 6638 * The access control entries of a resource are readable by everyone. 6639 * 6640 * @param dbc the current database context 6641 * @param resource the resource 6642 * @param principal the id of a group or a user any other entity 6643 * @return an access control entry that defines the permissions of the entity for the given resource 6644 * @throws CmsException if something goes wrong 6645 */ 6646 public CmsAccessControlEntry readAccessControlEntry(CmsDbContext dbc, CmsResource resource, CmsUUID principal) 6647 throws CmsException { 6648 6649 return getUserDriver( 6650 dbc).readAccessControlEntry(dbc, dbc.currentProject(), resource.getResourceId(), principal); 6651 } 6652 6653 /** 6654 * Finds the alias with a given path.<p> 6655 * 6656 * If no alias is found, null is returned.<p> 6657 * 6658 * @param dbc the current database context 6659 * @param project the current project 6660 * @param siteRoot the site root 6661 * @param path the path of the alias 6662 * 6663 * @return the alias with the given path 6664 * 6665 * @throws CmsException if something goes wrong 6666 */ 6667 6668 public CmsAlias readAliasByPath(CmsDbContext dbc, CmsProject project, String siteRoot, String path) 6669 throws CmsException { 6670 6671 List<CmsAlias> aliases = getVfsDriver(dbc).readAliases(dbc, project, new CmsAliasFilter(siteRoot, path, null)); 6672 if (aliases.isEmpty()) { 6673 return null; 6674 } else { 6675 return aliases.get(0); 6676 } 6677 } 6678 6679 /** 6680 * Reads the aliases for a given site root.<p> 6681 * 6682 * @param dbc the current database context 6683 * @param currentProject the current project 6684 * @param siteRoot the site root 6685 * 6686 * @return the list of aliases for the given site root 6687 * 6688 * @throws CmsException if something goes wrong 6689 */ 6690 public List<CmsAlias> readAliasesBySite(CmsDbContext dbc, CmsProject currentProject, String siteRoot) 6691 throws CmsException { 6692 6693 return getVfsDriver(dbc).readAliases(dbc, currentProject, new CmsAliasFilter(siteRoot, null, null)); 6694 } 6695 6696 /** 6697 * Reads the aliases which point to a given structure id.<p> 6698 * 6699 * @param dbc the current database context 6700 * @param project the current project 6701 * @param structureId the structure id for which we want to read the aliases 6702 * 6703 * @return the list of aliases pointing to the structure id 6704 * @throws CmsException if something goes wrong 6705 */ 6706 public List<CmsAlias> readAliasesByStructureId(CmsDbContext dbc, CmsProject project, CmsUUID structureId) 6707 throws CmsException { 6708 6709 return getVfsDriver(dbc).readAliases(dbc, project, new CmsAliasFilter(null, null, structureId)); 6710 } 6711 6712 /** 6713 * Reads all versions of the given resource.<br> 6714 * 6715 * This method returns a list with the history of the given resource, i.e. 6716 * the historical resource entries, independent of the project they were attached to.<br> 6717 * 6718 * The reading excludes the file content.<p> 6719 * 6720 * @param dbc the current database context 6721 * @param resource the resource to read the history for 6722 * 6723 * @return a list of file headers, as <code>{@link I_CmsHistoryResource}</code> objects 6724 * 6725 * @throws CmsException if something goes wrong 6726 */ 6727 public List<I_CmsHistoryResource> readAllAvailableVersions(CmsDbContext dbc, CmsResource resource) 6728 throws CmsException { 6729 6730 // read the historical resources 6731 List<I_CmsHistoryResource> versions = getHistoryDriver(dbc).readAllAvailableVersions( 6732 dbc, 6733 resource.getStructureId()); 6734 if ((versions.size() > OpenCms.getSystemInfo().getHistoryVersions()) 6735 && (OpenCms.getSystemInfo().getHistoryVersions() > -1)) { 6736 return versions.subList(0, OpenCms.getSystemInfo().getHistoryVersions()); 6737 } 6738 return versions; 6739 } 6740 6741 /** 6742 * Reads all property definitions for the given mapping type.<p> 6743 * 6744 * @param dbc the current database context 6745 * 6746 * @return a list with the <code>{@link CmsPropertyDefinition}</code> objects (may be empty) 6747 * 6748 * @throws CmsException if something goes wrong 6749 */ 6750 public List<CmsPropertyDefinition> readAllPropertyDefinitions(CmsDbContext dbc) throws CmsException { 6751 6752 List<CmsPropertyDefinition> result = getVfsDriver(dbc).readPropertyDefinitions( 6753 dbc, 6754 dbc.currentProject().getUuid()); 6755 Collections.sort(result); 6756 return result; 6757 } 6758 6759 /** 6760 * Returns all resources subscribed by the given user or group.<p> 6761 * 6762 * @param dbc the database context 6763 * @param poolName the name of the database pool to use 6764 * @param principal the principal to read the subscribed resources 6765 * 6766 * @return all resources subscribed by the given user or group 6767 * 6768 * @throws CmsException if something goes wrong 6769 */ 6770 public List<CmsResource> readAllSubscribedResources(CmsDbContext dbc, String poolName, CmsPrincipal principal) 6771 throws CmsException { 6772 6773 List<CmsResource> result = getSubscriptionDriver().readAllSubscribedResources(dbc, poolName, principal); 6774 result = filterPermissions(dbc, result, CmsResourceFilter.DEFAULT); 6775 return result; 6776 } 6777 6778 /** 6779 * Selects the best url name for a given resource and locale.<p> 6780 * 6781 * @param dbc the database context 6782 * @param id the resource's structure id 6783 * @param locale the requested locale 6784 * @param defaultLocales the default locales to use if the locale isn't available 6785 * 6786 * @return the URL name which was found 6787 * 6788 * @throws CmsDataAccessException if the database operation failed 6789 */ 6790 public String readBestUrlName(CmsDbContext dbc, CmsUUID id, Locale locale, List<Locale> defaultLocales) 6791 throws CmsDataAccessException { 6792 6793 List<CmsUrlNameMappingEntry> entries = getVfsDriver(dbc).readUrlNameMappingEntries( 6794 dbc, 6795 dbc.currentProject().isOnlineProject(), 6796 CmsUrlNameMappingFilter.ALL.filterStructureId(id)); 6797 if (entries.isEmpty()) { 6798 return null; 6799 } 6800 6801 ArrayListMultimap<String, CmsUrlNameMappingEntry> entriesByLocale = ArrayListMultimap.create(); 6802 for (CmsUrlNameMappingEntry entry : entries) { 6803 entriesByLocale.put(entry.getLocale(), entry); 6804 } 6805 List<CmsUrlNameMappingEntry> lastEntries = new ArrayList<CmsUrlNameMappingEntry>(); 6806 Comparator<CmsUrlNameMappingEntry> dateChangedComparator = new UrlNameMappingComparator(); 6807 for (String localeKey : entriesByLocale.keySet()) { 6808 // for each locale select the latest mapping entry 6809 CmsUrlNameMappingEntry latestEntryForLocale = Collections.max( 6810 entriesByLocale.get(localeKey), 6811 dateChangedComparator); 6812 lastEntries.add(latestEntryForLocale); 6813 } 6814 CmsLocaleManager localeManager = OpenCms.getLocaleManager(); 6815 List<Locale> availableLocales = new ArrayList<Locale>(); 6816 for (CmsUrlNameMappingEntry entry : lastEntries) { 6817 availableLocales.add(CmsLocaleManager.getLocale(entry.getLocale())); 6818 } 6819 Locale bestLocale = localeManager.getBestMatchingLocale(locale, defaultLocales, availableLocales); 6820 String bestLocaleStr = bestLocale.toString(); 6821 for (CmsUrlNameMappingEntry entry : lastEntries) { 6822 if (entry.getLocale().equals(bestLocaleStr)) { 6823 return entry.getName(); 6824 } 6825 } 6826 return null; 6827 } 6828 6829 /** 6830 * Returns the child resources of a resource, that is the resources 6831 * contained in a folder.<p> 6832 * 6833 * With the parameters <code>getFolders</code> and <code>getFiles</code> 6834 * you can control what type of resources you want in the result list: 6835 * files, folders, or both.<p> 6836 * 6837 * This method is mainly used by the workplace explorer.<p> 6838 * 6839 * @param dbc the current database context 6840 * @param resource the resource to return the child resources for 6841 * @param filter the resource filter to use 6842 * @param getFolders if true the child folders are included in the result 6843 * @param getFiles if true the child files are included in the result 6844 * @param checkPermissions if the resources should be filtered with the current user permissions 6845 * 6846 * @return a list of all child resources 6847 * 6848 * @throws CmsException if something goes wrong 6849 */ 6850 public List<CmsResource> readChildResources( 6851 CmsDbContext dbc, 6852 CmsResource resource, 6853 CmsResourceFilter filter, 6854 boolean getFolders, 6855 boolean getFiles, 6856 boolean checkPermissions) 6857 throws CmsException { 6858 6859 String cacheKey = null; 6860 List<CmsResource> resourceList = null; 6861 if (m_monitor.isEnabled(CmsMemoryMonitor.CacheType.RESOURCE_LIST)) { // check this here to skip the complex cache key generation 6862 String time = ""; 6863 if (checkPermissions) { 6864 // ensure correct caching if site time offset is set 6865 if ((dbc.getRequestContext() != null) 6866 && (OpenCms.getSiteManager().getSiteForSiteRoot(dbc.getRequestContext().getSiteRoot()) != null)) { 6867 time += OpenCms.getSiteManager().getSiteForSiteRoot( 6868 dbc.getRequestContext().getSiteRoot()).getSiteMatcher().getTimeOffset(); 6869 } 6870 } 6871 // try to get the sub resources from the cache 6872 cacheKey = getCacheKey( 6873 new String[] { 6874 dbc.currentUser().getName(), 6875 getFolders 6876 ? (getFiles ? CmsCacheKey.CACHE_KEY_SUBALL : CmsCacheKey.CACHE_KEY_SUBFOLDERS) 6877 : CmsCacheKey.CACHE_KEY_SUBFILES, 6878 checkPermissions ? "+" + time : "-", 6879 filter.getCacheId(), 6880 resource.getRootPath()}, 6881 dbc); 6882 6883 resourceList = m_monitor.getCachedResourceList(cacheKey); 6884 } 6885 if ((resourceList == null) || !dbc.getProjectId().isNullUUID()) { 6886 // read the result form the database 6887 resourceList = getVfsDriver( 6888 dbc).readChildResources(dbc, dbc.currentProject(), resource, getFolders, getFiles); 6889 6890 if (checkPermissions) { 6891 // apply the permission filter 6892 resourceList = filterPermissions(dbc, resourceList, filter); 6893 } 6894 // cache the sub resources 6895 if (dbc.getProjectId().isNullUUID()) { 6896 m_monitor.cacheResourceList(cacheKey, resourceList); 6897 } 6898 } 6899 6900 // we must always apply the result filter and update the context dates 6901 return updateContextDates(dbc, resourceList, filter); 6902 } 6903 6904 /** 6905 * Returns the default file for the given folder.<p> 6906 * 6907 * If the given resource is a file, then this file is returned.<p> 6908 * 6909 * Otherwise, in case of a folder:<br> 6910 * <ol> 6911 * <li>the {@link CmsPropertyDefinition#PROPERTY_DEFAULT_FILE} is checked, and 6912 * <li>if still no file could be found, the configured default files in the 6913 * <code>opencms-vfs.xml</code> configuration are iterated until a match is 6914 * found, and 6915 * <li>if still no file could be found, <code>null</code> is retuned 6916 * </ol> 6917 * 6918 * @param dbc the database context 6919 * @param resource the folder to get the default file for 6920 * @param resourceFilter the resource filter 6921 * 6922 * @return the default file for the given folder 6923 */ 6924 public CmsResource readDefaultFile(CmsDbContext dbc, CmsResource resource, CmsResourceFilter resourceFilter) { 6925 6926 // resource exists, lets check if we have a file or a folder 6927 if (resource.isFolder()) { 6928 // the resource is a folder, check if PROPERTY_DEFAULT_FILE is set on folder 6929 try { 6930 String defaultFileName = readPropertyObject( 6931 dbc, 6932 resource, 6933 CmsPropertyDefinition.PROPERTY_DEFAULT_FILE, 6934 false).getValue(); 6935 // check if the default file property does not match the navigation level folder marker value 6936 if ((defaultFileName != null) && !CmsJspNavBuilder.NAVIGATION_LEVEL_FOLDER.equals(defaultFileName)) { 6937 // property was set, so look up this file first 6938 String folderName = CmsResource.getFolderPath(resource.getRootPath()); 6939 resource = readResource(dbc, folderName + defaultFileName, resourceFilter.addRequireFile()); 6940 } 6941 } catch (CmsException e) { 6942 // ignore all other exceptions and continue the lookup process 6943 if (LOG.isDebugEnabled()) { 6944 LOG.debug(e.getLocalizedMessage(), e); 6945 } 6946 } 6947 if (resource.isFolder()) { 6948 String folderName = CmsResource.getFolderPath(resource.getRootPath()); 6949 // resource is (still) a folder, check default files specified in configuration 6950 Iterator<String> it = OpenCms.getDefaultFiles().iterator(); 6951 while (it.hasNext()) { 6952 String tmpResourceName = folderName + it.next(); 6953 try { 6954 resource = readResource(dbc, tmpResourceName, resourceFilter.addRequireFile()); 6955 // no exception? So we have found the default file 6956 // stop looking for default files 6957 break; 6958 } catch (CmsException e) { 6959 // ignore all other exceptions and continue the lookup process 6960 if (LOG.isDebugEnabled()) { 6961 LOG.debug(e.getLocalizedMessage(), e); 6962 } 6963 } 6964 } 6965 } 6966 } 6967 if (resource.isFolder()) { 6968 // we only want files as a result for further processing 6969 resource = null; 6970 } 6971 return resource; 6972 } 6973 6974 /** 6975 * Reads all deleted (historical) resources below the given path, 6976 * including the full tree below the path, if required.<p> 6977 * 6978 * @param dbc the current db context 6979 * @param resource the parent resource to read the resources from 6980 * @param readTree <code>true</code> to read all subresources 6981 * @param isVfsManager <code>true</code> if the current user has the vfs manager role 6982 * 6983 * @return a list of <code>{@link I_CmsHistoryResource}</code> objects 6984 * 6985 * @throws CmsException if something goes wrong 6986 * 6987 * @see CmsObject#readResource(CmsUUID, int) 6988 * @see CmsObject#readResources(String, CmsResourceFilter, boolean) 6989 * @see CmsObject#readDeletedResources(String, boolean) 6990 */ 6991 public List<I_CmsHistoryResource> readDeletedResources( 6992 CmsDbContext dbc, 6993 CmsResource resource, 6994 boolean readTree, 6995 boolean isVfsManager) 6996 throws CmsException { 6997 6998 Set<I_CmsHistoryResource> result = new HashSet<I_CmsHistoryResource>(); 6999 List<I_CmsHistoryResource> deletedResources; 7000 dbc.getRequestContext().setAttribute("ATTR_RESOURCE_NAME", resource.getRootPath()); 7001 try { 7002 deletedResources = getHistoryDriver(dbc).readDeletedResources( 7003 dbc, 7004 resource.getStructureId(), 7005 isVfsManager ? null : dbc.currentUser().getId()); 7006 } finally { 7007 dbc.getRequestContext().removeAttribute("ATTR_RESOURCE_NAME"); 7008 } 7009 result.addAll(deletedResources); 7010 Set<I_CmsHistoryResource> newResult = new HashSet<I_CmsHistoryResource>(result.size()); 7011 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 7012 Iterator<I_CmsHistoryResource> it = result.iterator(); 7013 while (it.hasNext()) { 7014 I_CmsHistoryResource histRes = it.next(); 7015 // adjust the paths 7016 try { 7017 if (vfsDriver.validateStructureIdExists( 7018 dbc, 7019 dbc.currentProject().getUuid(), 7020 histRes.getStructureId())) { 7021 newResult.add(histRes); 7022 continue; 7023 } 7024 // adjust the path in case of deleted files 7025 String resourcePath = histRes.getRootPath(); 7026 String resName = CmsResource.getName(resourcePath); 7027 String path = CmsResource.getParentFolder(resourcePath); 7028 7029 CmsUUID parentId = histRes.getParentId(); 7030 try { 7031 // first look for the path through the parent id 7032 path = readResource(dbc, parentId, CmsResourceFilter.IGNORE_EXPIRATION).getRootPath(); 7033 } catch (CmsDataAccessException e) { 7034 // if the resource with the parent id is not found, try to get a new parent id with the path 7035 try { 7036 parentId = readResource(dbc, path, CmsResourceFilter.IGNORE_EXPIRATION).getStructureId(); 7037 } catch (CmsDataAccessException e1) { 7038 // ignore, the parent folder has been completely deleted 7039 } 7040 } 7041 resourcePath = path + resName; 7042 7043 boolean isFolder = resourcePath.endsWith("/"); 7044 if (isFolder) { 7045 newResult.add( 7046 new CmsHistoryFolder( 7047 histRes.getPublishTag(), 7048 histRes.getStructureId(), 7049 histRes.getResourceId(), 7050 resourcePath, 7051 histRes.getTypeId(), 7052 histRes.getFlags(), 7053 histRes.getProjectLastModified(), 7054 histRes.getState(), 7055 histRes.getDateCreated(), 7056 histRes.getUserCreated(), 7057 histRes.getDateLastModified(), 7058 histRes.getUserLastModified(), 7059 histRes.getDateReleased(), 7060 histRes.getDateExpired(), 7061 histRes.getVersion(), 7062 parentId, 7063 histRes.getResourceVersion(), 7064 histRes.getStructureVersion())); 7065 } else { 7066 newResult.add( 7067 new CmsHistoryFile( 7068 histRes.getPublishTag(), 7069 histRes.getStructureId(), 7070 histRes.getResourceId(), 7071 resourcePath, 7072 histRes.getTypeId(), 7073 histRes.getFlags(), 7074 histRes.getProjectLastModified(), 7075 histRes.getState(), 7076 histRes.getDateCreated(), 7077 histRes.getUserCreated(), 7078 histRes.getDateLastModified(), 7079 histRes.getUserLastModified(), 7080 histRes.getDateReleased(), 7081 histRes.getDateExpired(), 7082 histRes.getLength(), 7083 histRes.getDateContent(), 7084 histRes.getVersion(), 7085 parentId, 7086 null, 7087 histRes.getResourceVersion(), 7088 histRes.getStructureVersion())); 7089 } 7090 } catch (CmsDataAccessException e) { 7091 // should never happen 7092 if (LOG.isErrorEnabled()) { 7093 LOG.error(e.getLocalizedMessage(), e); 7094 } 7095 } 7096 } 7097 if (readTree) { 7098 Iterator<I_CmsHistoryResource> itDeleted = deletedResources.iterator(); 7099 while (itDeleted.hasNext()) { 7100 I_CmsHistoryResource delResource = itDeleted.next(); 7101 if (delResource.isFolder()) { 7102 newResult.addAll(readDeletedResources(dbc, (CmsFolder)delResource, readTree, isVfsManager)); 7103 } 7104 } 7105 try { 7106 readResource(dbc, resource.getStructureId(), CmsResourceFilter.ALL); 7107 // resource exists, so recurse 7108 Iterator<CmsResource> itResources = readResources( 7109 dbc, 7110 resource, 7111 CmsResourceFilter.ALL.addRequireFolder(), 7112 readTree).iterator(); 7113 while (itResources.hasNext()) { 7114 CmsResource subResource = itResources.next(); 7115 if (subResource.isFolder()) { 7116 newResult.addAll(readDeletedResources(dbc, subResource, readTree, isVfsManager)); 7117 } 7118 } 7119 } catch (Exception e) { 7120 // resource does not exists 7121 if (LOG.isDebugEnabled()) { 7122 LOG.debug(e.getLocalizedMessage(), e); 7123 } 7124 } 7125 } 7126 List<I_CmsHistoryResource> finalRes = new ArrayList<I_CmsHistoryResource>(newResult); 7127 Collections.sort(finalRes, I_CmsResource.COMPARE_ROOT_PATH); 7128 return finalRes; 7129 } 7130 7131 /** 7132 * Reads a file resource (including it's binary content) from the VFS, 7133 * using the specified resource filter.<p> 7134 * 7135 * In case you do not need the file content, 7136 * use <code>{@link #readResource(CmsDbContext, String, CmsResourceFilter)}</code> instead.<p> 7137 * 7138 * The specified filter controls what kind of resources should be "found" 7139 * during the read operation. This will depend on the application. For example, 7140 * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently 7141 * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code> 7142 * will ignore the date release / date expired information of the resource.<p> 7143 * 7144 * @param dbc the current database context 7145 * @param resource the base file resource (without content) 7146 * @return the file read from the VFS 7147 * @throws CmsException if operation was not successful 7148 */ 7149 public CmsFile readFile(CmsDbContext dbc, CmsResource resource) throws CmsException { 7150 7151 if (resource.isFolder()) { 7152 throw new CmsVfsResourceNotFoundException( 7153 Messages.get().container( 7154 Messages.ERR_ACCESS_FOLDER_AS_FILE_1, 7155 dbc.removeSiteRoot(resource.getRootPath()))); 7156 } 7157 7158 CmsUUID projectId = dbc.currentProject().getUuid(); 7159 CmsFile file = null; 7160 if (resource instanceof I_CmsHistoryResource) { 7161 file = new CmsHistoryFile((I_CmsHistoryResource)resource); 7162 file.setContents( 7163 getHistoryDriver(dbc).readContent( 7164 dbc, 7165 resource.getResourceId(), 7166 ((I_CmsHistoryResource)resource).getPublishTag())); 7167 } else { 7168 file = new CmsFile(resource); 7169 file.setContents(getVfsDriver(dbc).readContent(dbc, projectId, resource.getResourceId())); 7170 } 7171 return file; 7172 } 7173 7174 /** 7175 * Reads a folder from the VFS, 7176 * using the specified resource filter.<p> 7177 * 7178 * @param dbc the current database context 7179 * @param resourcename the name of the folder to read (full path) 7180 * @param filter the resource filter to use while reading 7181 * 7182 * @return the folder that was read 7183 * 7184 * @throws CmsDataAccessException if something goes wrong 7185 * 7186 * @see #readResource(CmsDbContext, String, CmsResourceFilter) 7187 * @see CmsObject#readFolder(String) 7188 * @see CmsObject#readFolder(String, CmsResourceFilter) 7189 */ 7190 public CmsFolder readFolder(CmsDbContext dbc, String resourcename, CmsResourceFilter filter) 7191 throws CmsDataAccessException { 7192 7193 CmsResource resource = readResource(dbc, resourcename, filter); 7194 7195 return convertResourceToFolder(resource); 7196 } 7197 7198 /** 7199 * Reads the group of a project.<p> 7200 * 7201 * @param dbc the current database context 7202 * @param project the project to read from 7203 * 7204 * @return the group of a resource 7205 */ 7206 public CmsGroup readGroup(CmsDbContext dbc, CmsProject project) { 7207 7208 try { 7209 return readGroup(dbc, project.getGroupId()); 7210 } catch (CmsException exc) { 7211 return new CmsGroup( 7212 CmsUUID.getNullUUID(), 7213 CmsUUID.getNullUUID(), 7214 project.getGroupId() + "", 7215 "deleted group", 7216 0); 7217 } 7218 } 7219 7220 /** 7221 * Reads a group based on its id.<p> 7222 * 7223 * @param dbc the current database context 7224 * @param groupId the id of the group that is to be read 7225 * 7226 * @return the requested group 7227 * 7228 * @throws CmsException if operation was not successful 7229 */ 7230 public CmsGroup readGroup(CmsDbContext dbc, CmsUUID groupId) throws CmsException { 7231 7232 CmsGroup group = null; 7233 // try to read group from cache 7234 group = m_monitor.getCachedGroup(groupId.toString()); 7235 if (group == null) { 7236 group = getUserDriver(dbc).readGroup(dbc, groupId); 7237 m_monitor.cacheGroup(group); 7238 } 7239 return group; 7240 } 7241 7242 /** 7243 * Reads a group based on its name.<p> 7244 * 7245 * @param dbc the current database context 7246 * @param groupname the name of the group that is to be read 7247 * 7248 * @return the requested group 7249 * 7250 * @throws CmsDataAccessException if operation was not successful 7251 */ 7252 public CmsGroup readGroup(CmsDbContext dbc, String groupname) throws CmsDataAccessException { 7253 7254 CmsGroup group = null; 7255 // try to read group from cache 7256 group = m_monitor.getCachedGroup(groupname); 7257 if (group == null) { 7258 group = getUserDriver(dbc).readGroup(dbc, groupname); 7259 m_monitor.cacheGroup(group); 7260 } 7261 return group; 7262 } 7263 7264 /** 7265 * Reads a principal (an user or group) from the historical archive based on its ID.<p> 7266 * 7267 * @param dbc the current database context 7268 * @param principalId the id of the principal to read 7269 * 7270 * @return the historical principal entry with the given id 7271 * 7272 * @throws CmsException if something goes wrong, ie. {@link CmsDbEntryNotFoundException} 7273 * 7274 * @see CmsObject#readUser(CmsUUID) 7275 * @see CmsObject#readGroup(CmsUUID) 7276 * @see CmsObject#readHistoryPrincipal(CmsUUID) 7277 */ 7278 public CmsHistoryPrincipal readHistoricalPrincipal(CmsDbContext dbc, CmsUUID principalId) throws CmsException { 7279 7280 return getHistoryDriver(dbc).readPrincipal(dbc, principalId); 7281 } 7282 7283 /** 7284 * Returns the latest historical project entry with the given id.<p> 7285 * 7286 * @param dbc the current database context 7287 * @param projectId the project id 7288 * 7289 * @return the requested historical project entry 7290 * 7291 * @throws CmsException if something goes wrong 7292 */ 7293 public CmsHistoryProject readHistoryProject(CmsDbContext dbc, CmsUUID projectId) throws CmsException { 7294 7295 return getHistoryDriver(dbc).readProject(dbc, projectId); 7296 } 7297 7298 /** 7299 * Returns a historical project entry.<p> 7300 * 7301 * @param dbc the current database context 7302 * @param publishTag the publish tag of the project 7303 * 7304 * @return the requested historical project entry 7305 * 7306 * @throws CmsException if something goes wrong 7307 */ 7308 public CmsHistoryProject readHistoryProject(CmsDbContext dbc, int publishTag) throws CmsException { 7309 7310 return getHistoryDriver(dbc).readProject(dbc, publishTag); 7311 } 7312 7313 /** 7314 * Reads the list of all <code>{@link CmsProperty}</code> objects that belongs to the given historical resource.<p> 7315 * 7316 * @param dbc the current database context 7317 * @param historyResource the historical resource to read the properties for 7318 * 7319 * @return the list of <code>{@link CmsProperty}</code> objects 7320 * 7321 * @throws CmsException if something goes wrong 7322 */ 7323 public List<CmsProperty> readHistoryPropertyObjects(CmsDbContext dbc, I_CmsHistoryResource historyResource) 7324 throws CmsException { 7325 7326 return getHistoryDriver(dbc).readProperties(dbc, historyResource); 7327 } 7328 7329 /** 7330 * Reads the structure id which is mapped to a given URL name.<p> 7331 * 7332 * @param dbc the current database context 7333 * @param name the name for which the mapped structure id should be looked up 7334 * 7335 * @return the structure id which is mapped to the given name, or null if there is no such id 7336 * 7337 * @throws CmsDataAccessException if something goes wrong 7338 */ 7339 public CmsUUID readIdForUrlName(CmsDbContext dbc, String name) throws CmsDataAccessException { 7340 7341 List<CmsUrlNameMappingEntry> entries = getVfsDriver(dbc).readUrlNameMappingEntries( 7342 dbc, 7343 dbc.currentProject().isOnlineProject(), 7344 CmsUrlNameMappingFilter.ALL.filterName(name)); 7345 if (entries.isEmpty()) { 7346 return null; 7347 } 7348 return entries.get(0).getStructureId(); 7349 } 7350 7351 /** 7352 * Reads the locks that were saved to the database in the previous run of OpenCms.<p> 7353 * 7354 * @param dbc the current database context 7355 * 7356 * @throws CmsException if something goes wrong 7357 */ 7358 public void readLocks(CmsDbContext dbc) throws CmsException { 7359 7360 m_lockManager.readLocks(dbc); 7361 } 7362 7363 /** 7364 * Reads the manager group of a project.<p> 7365 * 7366 * @param dbc the current database context 7367 * @param project the project to read from 7368 * 7369 * @return the group of a resource 7370 */ 7371 public CmsGroup readManagerGroup(CmsDbContext dbc, CmsProject project) { 7372 7373 try { 7374 return readGroup(dbc, project.getManagerGroupId()); 7375 } catch (CmsException exc) { 7376 // the group does not exist any more - return a dummy-group 7377 return new CmsGroup( 7378 CmsUUID.getNullUUID(), 7379 CmsUUID.getNullUUID(), 7380 project.getManagerGroupId() + "", 7381 "deleted group", 7382 0); 7383 } 7384 } 7385 7386 /** 7387 * Reads the URL name which has been most recently mapped to the given structure id, or null 7388 * if no URL name is mapped to the id.<p> 7389 * 7390 * @param dbc the current database context 7391 * @param id a structure id 7392 * @return the name which has been most recently mapped to the given structure id 7393 * 7394 * @throws CmsDataAccessException if something goes wrong 7395 */ 7396 public String readNewestUrlNameForId(CmsDbContext dbc, CmsUUID id) throws CmsDataAccessException { 7397 7398 List<CmsUrlNameMappingEntry> entries = getVfsDriver(dbc).readUrlNameMappingEntries( 7399 dbc, 7400 dbc.currentProject().isOnlineProject(), 7401 CmsUrlNameMappingFilter.ALL.filterStructureId(id)); 7402 if (entries.isEmpty()) { 7403 return null; 7404 } 7405 7406 Collections.sort(entries, new UrlNameMappingComparator()); 7407 CmsUrlNameMappingEntry lastEntry = entries.get(entries.size() - 1); 7408 return lastEntry.getName(); 7409 } 7410 7411 /** 7412 * Reads an organizational Unit based on its fully qualified name.<p> 7413 * 7414 * @param dbc the current db context 7415 * @param ouFqn the fully qualified name of the organizational Unit to be read 7416 * 7417 * @return the organizational Unit that with the provided fully qualified name 7418 * 7419 * @throws CmsException if something goes wrong 7420 */ 7421 public CmsOrganizationalUnit readOrganizationalUnit(CmsDbContext dbc, String ouFqn) throws CmsException { 7422 7423 CmsOrganizationalUnit organizationalUnit = null; 7424 // try to read organizational unit from cache 7425 organizationalUnit = m_monitor.getCachedOrgUnit(ouFqn); 7426 if (organizationalUnit == null) { 7427 organizationalUnit = getUserDriver(dbc).readOrganizationalUnit(dbc, ouFqn); 7428 m_monitor.cacheOrgUnit(organizationalUnit); 7429 } 7430 return organizationalUnit; 7431 } 7432 7433 /** 7434 * Reads the owner of a project.<p> 7435 * 7436 * @param dbc the current database context 7437 * @param project the project to get the owner from 7438 * 7439 * @return the owner of a resource 7440 * @throws CmsException if something goes wrong 7441 */ 7442 public CmsUser readOwner(CmsDbContext dbc, CmsProject project) throws CmsException { 7443 7444 return readUser(dbc, project.getOwnerId()); 7445 } 7446 7447 /** 7448 * Reads the parent folder to a given structure id.<p> 7449 * 7450 * @param dbc the current database context 7451 * @param structureId the structure id of the child 7452 * 7453 * @return the parent folder resource 7454 * 7455 * @throws CmsDataAccessException if something goes wrong 7456 */ 7457 public CmsResource readParentFolder(CmsDbContext dbc, CmsUUID structureId) throws CmsDataAccessException { 7458 7459 return getVfsDriver(dbc).readParentFolder(dbc, dbc.currentProject().getUuid(), structureId); 7460 } 7461 7462 /** 7463 * Builds a list of resources for a given path.<p> 7464 * 7465 * @param dbc the current database context 7466 * @param path the requested path 7467 * @param filter a filter object (only "includeDeleted" information is used!) 7468 * 7469 * @return list of <code>{@link CmsResource}</code>s 7470 * 7471 * @throws CmsException if something goes wrong 7472 */ 7473 public List<CmsResource> readPath(CmsDbContext dbc, String path, CmsResourceFilter filter) throws CmsException { 7474 7475 // splits the path into folder and filename tokens 7476 List<String> tokens = CmsStringUtil.splitAsList(path, '/'); 7477 7478 // the root folder is no token in the path but a resource which has to be added to the path 7479 int count = tokens.size() + 1; 7480 // holds the CmsResource instances in the path 7481 List<CmsResource> pathList = new ArrayList<CmsResource>(count); 7482 7483 // true if the path doesn't end with a folder 7484 boolean lastResourceIsFile = false; 7485 // number of folders in the path 7486 int folderCount = count; 7487 if (!path.endsWith("/")) { 7488 folderCount--; 7489 lastResourceIsFile = true; 7490 } 7491 7492 // read the root folder, because it's ID is required to read any sub-resources 7493 String currentResourceName = "/"; 7494 StringBuffer currentPath = new StringBuffer(64); 7495 currentPath.append('/'); 7496 7497 String cp = currentPath.toString(); 7498 CmsUUID projectId = getProjectIdForContext(dbc); 7499 7500 // key to cache the resources 7501 String cacheKey = getCacheKey(null, false, projectId, cp); 7502 // the current resource 7503 CmsResource currentResource = m_monitor.getCachedResource(cacheKey); 7504 if ((currentResource == null) || !dbc.getProjectId().isNullUUID()) { 7505 currentResource = getVfsDriver(dbc).readFolder(dbc, projectId, cp); 7506 if (dbc.getProjectId().isNullUUID()) { 7507 m_monitor.cacheResource(cacheKey, currentResource); 7508 } 7509 } 7510 7511 pathList.add(0, currentResource); 7512 7513 if (count == 1) { 7514 // the root folder was requested- no further operations required 7515 return pathList; 7516 } 7517 7518 Iterator<String> it = tokens.iterator(); 7519 currentResourceName = it.next(); 7520 7521 // read the folder resources in the path /a/b/c/ 7522 int i = 0; 7523 for (i = 1; i < folderCount; i++) { 7524 currentPath.append(currentResourceName); 7525 currentPath.append('/'); 7526 // read the folder 7527 cp = currentPath.toString(); 7528 cacheKey = getCacheKey(null, false, projectId, cp); 7529 currentResource = m_monitor.getCachedResource(cacheKey); 7530 if ((currentResource == null) || !dbc.getProjectId().isNullUUID()) { 7531 currentResource = getVfsDriver(dbc).readFolder(dbc, projectId, cp); 7532 if (dbc.getProjectId().isNullUUID()) { 7533 m_monitor.cacheResource(cacheKey, currentResource); 7534 } 7535 } 7536 7537 pathList.add(i, currentResource); 7538 7539 if (i < (folderCount - 1)) { 7540 currentResourceName = it.next(); 7541 } 7542 } 7543 7544 // read the (optional) last file resource in the path /x.html 7545 if (lastResourceIsFile) { 7546 if (it.hasNext()) { 7547 // this will only be false if a resource in the 7548 // top level root folder (e.g. "/index.html") was requested 7549 currentResourceName = it.next(); 7550 } 7551 currentPath.append(currentResourceName); 7552 7553 // read the file 7554 cp = currentPath.toString(); 7555 cacheKey = getCacheKey(null, false, projectId, cp); 7556 currentResource = m_monitor.getCachedResource(cacheKey); 7557 if ((currentResource == null) || !dbc.getProjectId().isNullUUID()) { 7558 currentResource = getVfsDriver(dbc).readResource(dbc, projectId, cp, filter.includeDeleted()); 7559 if (dbc.getProjectId().isNullUUID()) { 7560 m_monitor.cacheResource(cacheKey, currentResource); 7561 } 7562 } 7563 7564 pathList.add(i, currentResource); 7565 } 7566 7567 return pathList; 7568 } 7569 7570 /** 7571 * Reads a project given the projects id.<p> 7572 * 7573 * @param dbc the current database context 7574 * @param id the id of the project 7575 * 7576 * @return the project read 7577 * 7578 * @throws CmsDataAccessException if something goes wrong 7579 */ 7580 public CmsProject readProject(CmsDbContext dbc, CmsUUID id) throws CmsDataAccessException { 7581 7582 CmsProject project = null; 7583 project = m_monitor.getCachedProject(id.toString()); 7584 if (project == null) { 7585 project = getProjectDriver(dbc).readProject(dbc, id); 7586 m_monitor.cacheProject(project); 7587 } 7588 return project; 7589 } 7590 7591 /** 7592 * Reads a project.<p> 7593 * 7594 * Important: Since a project name can be used multiple times, this is NOT the most efficient 7595 * way to read the project. This is only a convenience for front end developing. 7596 * Reading a project by name will return the first project with that name. 7597 * All core classes must use the id version {@link #readProject(CmsDbContext, CmsUUID)} to ensure the right project is read.<p> 7598 * 7599 * @param dbc the current database context 7600 * @param name the name of the project 7601 * 7602 * @return the project read 7603 * 7604 * @throws CmsException if something goes wrong 7605 */ 7606 public CmsProject readProject(CmsDbContext dbc, String name) throws CmsException { 7607 7608 CmsProject project = null; 7609 project = m_monitor.getCachedProject(name); 7610 if (project == null) { 7611 project = getProjectDriver(dbc).readProject(dbc, name); 7612 m_monitor.cacheProject(project); 7613 } 7614 return project; 7615 } 7616 7617 /** 7618 * Returns the list of all resource names that define the "view" of the given project.<p> 7619 * 7620 * @param dbc the current database context 7621 * @param project the project to get the project resources for 7622 * 7623 * @return the list of all resources, as <code>{@link String}</code> objects 7624 * that define the "view" of the given project. 7625 * 7626 * @throws CmsException if something goes wrong 7627 */ 7628 public List<String> readProjectResources(CmsDbContext dbc, CmsProject project) throws CmsException { 7629 7630 return getProjectDriver(dbc).readProjectResources(dbc, project); 7631 } 7632 7633 /** 7634 * Reads all resources of a project that match a given state from the VFS.<p> 7635 * 7636 * Possible values for the <code>state</code> parameter are:<br> 7637 * <ul> 7638 * <li><code>{@link CmsResource#STATE_CHANGED}</code>: Read all "changed" resources in the project</li> 7639 * <li><code>{@link CmsResource#STATE_NEW}</code>: Read all "new" resources in the project</li> 7640 * <li><code>{@link CmsResource#STATE_DELETED}</code>: Read all "deleted" resources in the project</li> 7641 * <li><code>{@link CmsResource#STATE_KEEP}</code>: Read all resources either "changed", "new" or "deleted" in the project</li> 7642 * </ul><p> 7643 * 7644 * @param dbc the current database context 7645 * @param projectId the id of the project to read the file resources for 7646 * @param state the resource state to match 7647 * 7648 * @return a list of <code>{@link CmsResource}</code> objects matching the filter criteria 7649 * 7650 * @throws CmsException if something goes wrong 7651 * 7652 * @see CmsObject#readProjectView(CmsUUID, CmsResourceState) 7653 */ 7654 public List<CmsResource> readProjectView(CmsDbContext dbc, CmsUUID projectId, CmsResourceState state) 7655 throws CmsException { 7656 7657 List<CmsResource> resources; 7658 if (state.isNew() || state.isChanged() || state.isDeleted()) { 7659 // get all resources form the database that match the selected state 7660 resources = getVfsDriver(dbc).readResources(dbc, projectId, state, CmsDriverManager.READMODE_MATCHSTATE); 7661 } else { 7662 // get all resources form the database that are somehow changed (i.e. not unchanged) 7663 resources = getVfsDriver( 7664 dbc).readResources(dbc, projectId, CmsResource.STATE_UNCHANGED, CmsDriverManager.READMODE_UNMATCHSTATE); 7665 } 7666 7667 // filter the permissions 7668 List<CmsResource> result = filterPermissions(dbc, resources, CmsResourceFilter.ALL); 7669 // sort the result 7670 Collections.sort(result); 7671 // set the full resource names 7672 return updateContextDates(dbc, result); 7673 } 7674 7675 /** 7676 * Reads a property definition.<p> 7677 * 7678 * If no property definition with the given name is found, 7679 * <code>null</code> is returned.<p> 7680 * 7681 * @param dbc the current database context 7682 * @param name the name of the property definition to read 7683 * 7684 * @return the property definition that was read 7685 * 7686 * @throws CmsException a CmsDbEntryNotFoundException is thrown if the property definition does not exist 7687 */ 7688 public CmsPropertyDefinition readPropertyDefinition(CmsDbContext dbc, String name) throws CmsException { 7689 7690 return getVfsDriver(dbc).readPropertyDefinition(dbc, name, dbc.currentProject().getUuid()); 7691 } 7692 7693 /** 7694 * Reads a property object from a resource specified by a property name.<p> 7695 * 7696 * Returns <code>{@link CmsProperty#getNullProperty()}</code> if the property is not found.<p> 7697 * 7698 * @param dbc the current database context 7699 * @param resource the resource where the property is read from 7700 * @param key the property key name 7701 * @param search if <code>true</code>, the property is searched on all parent folders of the resource. 7702 * if it's not found attached directly to the resource. 7703 * 7704 * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found 7705 * 7706 * @throws CmsException if something goes wrong 7707 */ 7708 public CmsProperty readPropertyObject(CmsDbContext dbc, CmsResource resource, String key, boolean search) 7709 throws CmsException { 7710 7711 // NOTE: Do not call readPropertyObject(dbc, resource, key, search, null) for performance reasons 7712 7713 // use the list reading method to obtain all properties for the resource 7714 List<CmsProperty> properties = readPropertyObjects(dbc, resource, search); 7715 7716 int i = properties.indexOf(new CmsProperty(key, null, null)); 7717 if (i >= 0) { 7718 // property has been found in the map 7719 CmsProperty result = properties.get(i); 7720 // ensure the result value is not frozen 7721 return result.cloneAsProperty(); 7722 } 7723 return CmsProperty.getNullProperty(); 7724 7725 } 7726 7727 /** 7728 * Reads a property object from a resource specified by a property name.<p> 7729 * 7730 * Returns <code>{@link CmsProperty#getNullProperty()}</code> if the property is not found.<p> 7731 * 7732 * @param dbc the current database context 7733 * @param resource the resource where the property is read from 7734 * @param key the property key name 7735 * @param search if <code>true</code>, the property is searched on all parent folders of the resource. 7736 * if it's not found attached directly to the resource. 7737 * @param locale the locale for which the property should be read. 7738 * 7739 * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found 7740 * 7741 * @throws CmsException if something goes wrong 7742 */ 7743 public CmsProperty readPropertyObject( 7744 CmsDbContext dbc, 7745 CmsResource resource, 7746 String key, 7747 boolean search, 7748 Locale locale) 7749 throws CmsException { 7750 7751 // use the list reading method to obtain all properties for the resource 7752 List<CmsProperty> properties = readPropertyObjects(dbc, resource, search); 7753 // create a lookup property object and look this up in the result map 7754 CmsProperty result = null; 7755 // handle the case without locale separately to improve performance 7756 for (String localizedKey : CmsLocaleManager.getLocaleVariants(key, locale, true, false)) { 7757 int i = properties.indexOf(new CmsProperty(localizedKey, null, null)); 7758 if (i >= 0) { 7759 // property has been found in the map 7760 result = properties.get(i); 7761 // ensure the result value is not frozen 7762 return result.cloneAsProperty(); 7763 } 7764 } 7765 return CmsProperty.getNullProperty(); 7766 } 7767 7768 /** 7769 * Reads all property objects mapped to a specified resource from the database.<p> 7770 * 7771 * All properties in the result List will be in frozen (read only) state, so you can't change the values.<p> 7772 * 7773 * Returns an empty list if no properties are found at all.<p> 7774 * 7775 * @param dbc the current database context 7776 * @param resource the resource where the properties are read from 7777 * @param search true, if the properties should be searched on all parent folders if not found on the resource 7778 * 7779 * @return a list of CmsProperty objects containing the structure and/or resource value 7780 * 7781 * @throws CmsException if something goes wrong 7782 * 7783 * @see CmsObject#readPropertyObjects(String, boolean) 7784 */ 7785 public List<CmsProperty> readPropertyObjects(CmsDbContext dbc, CmsResource resource, boolean search) 7786 throws CmsException { 7787 7788 // check if we have the result already cached 7789 CmsUUID projectId = getProjectIdForContext(dbc); 7790 String cacheKey = getCacheKey(CACHE_ALL_PROPERTIES, search, projectId, resource.getRootPath()); 7791 7792 List<CmsProperty> properties = m_monitor.getCachedPropertyList(cacheKey); 7793 7794 if ((properties == null) || !dbc.getProjectId().isNullUUID()) { 7795 // result not cached, let's look it up in the DB 7796 if (search) { 7797 boolean cont; 7798 properties = new ArrayList<CmsProperty>(); 7799 List<CmsProperty> parentProperties = null; 7800 7801 do { 7802 try { 7803 parentProperties = readPropertyObjects(dbc, resource, false); 7804 7805 // make sure properties from lower folders "overwrite" properties from upper folders 7806 parentProperties.removeAll(properties); 7807 parentProperties.addAll(properties); 7808 7809 properties.clear(); 7810 properties.addAll(parentProperties); 7811 7812 cont = resource.getRootPath().length() > 1; 7813 } catch (CmsSecurityException se) { 7814 // a security exception (probably no read permission) we return the current result 7815 cont = false; 7816 } 7817 if (cont) { 7818 // no permission check on parent folder is required since we must have "read" 7819 // permissions to read the child resource anyway 7820 resource = readResource( 7821 dbc, 7822 CmsResource.getParentFolder(resource.getRootPath()), 7823 CmsResourceFilter.ALL); 7824 } 7825 } while (cont); 7826 } else { 7827 properties = getVfsDriver(dbc).readPropertyObjects(dbc, dbc.currentProject(), resource); 7828 // for (CmsProperty prop : properties) { 7829 // prop.setOrigin(resource.getRootPath()); 7830 // } 7831 } 7832 7833 // set all properties in the result list as frozen 7834 CmsProperty.setFrozen(properties); 7835 if (dbc.getProjectId().isNullUUID()) { 7836 // store the result in the cache if needed 7837 m_monitor.cachePropertyList(cacheKey, properties); 7838 } 7839 } 7840 7841 return new ArrayList<CmsProperty>(properties); 7842 } 7843 7844 /** 7845 * Reads the resources that were published in a publish task for a given publish history ID.<p> 7846 * 7847 * @param dbc the current database context 7848 * @param publishHistoryId unique int ID to identify each publish task in the publish history 7849 * 7850 * @return a list of <code>{@link org.opencms.db.CmsPublishedResource}</code> objects 7851 * 7852 * @throws CmsException if something goes wrong 7853 */ 7854 public List<CmsPublishedResource> readPublishedResources(CmsDbContext dbc, CmsUUID publishHistoryId) 7855 throws CmsException { 7856 7857 String cacheKey = publishHistoryId.toString(); 7858 List<CmsPublishedResource> resourceList = m_monitor.getCachedPublishedResources(cacheKey); 7859 if ((resourceList == null) || !dbc.getProjectId().isNullUUID()) { 7860 resourceList = getProjectDriver(dbc).readPublishedResources(dbc, publishHistoryId); 7861 // store the result in the cache 7862 if (dbc.getProjectId().isNullUUID()) { 7863 m_monitor.cachePublishedResources(cacheKey, resourceList); 7864 } 7865 } 7866 return resourceList; 7867 } 7868 7869 /** 7870 * Reads a single publish job identified by its publish history id.<p> 7871 * 7872 * @param dbc the current database context 7873 * @param publishHistoryId unique id to identify the publish job in the publish history 7874 * @return an object of type <code>{@link CmsPublishJobInfoBean}</code> 7875 * 7876 * @throws CmsException if something goes wrong 7877 */ 7878 public CmsPublishJobInfoBean readPublishJob(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { 7879 7880 return getProjectDriver(dbc).readPublishJob(dbc, publishHistoryId); 7881 } 7882 7883 /** 7884 * Reads all available publish jobs.<p> 7885 * 7886 * @param dbc the current database context 7887 * @param startTime the start of the time range for finish time 7888 * @param endTime the end of the time range for finish time 7889 * @return a list of objects of type <code>{@link CmsPublishJobInfoBean}</code> 7890 * 7891 * @throws CmsException if something goes wrong 7892 */ 7893 public List<CmsPublishJobInfoBean> readPublishJobs(CmsDbContext dbc, long startTime, long endTime) 7894 throws CmsException { 7895 7896 return getProjectDriver(dbc).readPublishJobs(dbc, startTime, endTime); 7897 } 7898 7899 /** 7900 * Reads the publish list assigned to a publish job.<p> 7901 * 7902 * @param dbc the current database context 7903 * @param publishHistoryId the history id identifying the publish job 7904 * @return the assigned publish list 7905 * @throws CmsException if something goes wrong 7906 */ 7907 public CmsPublishList readPublishList(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { 7908 7909 return getProjectDriver(dbc).readPublishList(dbc, publishHistoryId); 7910 } 7911 7912 /** 7913 * Reads the publish report assigned to a publish job.<p> 7914 * 7915 * @param dbc the current database context 7916 * @param publishHistoryId the history id identifying the publish job 7917 * @return the content of the assigned publish report 7918 * @throws CmsException if something goes wrong 7919 */ 7920 public byte[] readPublishReportContents(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { 7921 7922 return getProjectDriver(dbc).readPublishReportContents(dbc, publishHistoryId); 7923 } 7924 7925 /** 7926 * Reads an historical resource entry for the given resource and with the given version number.<p> 7927 * 7928 * @param dbc the current db context 7929 * @param resource the resource to be read 7930 * @param version the version number to retrieve 7931 * 7932 * @return the resource that was read 7933 * 7934 * @throws CmsException if the resource could not be read for any reason 7935 * 7936 * @see CmsObject#restoreResourceVersion(CmsUUID, int) 7937 * @see CmsObject#readResource(CmsUUID, int) 7938 */ 7939 public I_CmsHistoryResource readResource(CmsDbContext dbc, CmsResource resource, int version) throws CmsException { 7940 7941 Iterator<I_CmsHistoryResource> itVersions = getHistoryDriver(dbc).readAllAvailableVersions( 7942 dbc, 7943 resource.getStructureId()).iterator(); 7944 while (itVersions.hasNext()) { 7945 I_CmsHistoryResource histRes = itVersions.next(); 7946 if (histRes.getVersion() == version) { 7947 return histRes; 7948 } 7949 } 7950 throw new CmsVfsResourceNotFoundException( 7951 org.opencms.db.generic.Messages.get().container( 7952 org.opencms.db.generic.Messages.ERR_HISTORY_FILE_NOT_FOUND_1, 7953 resource.getStructureId())); 7954 } 7955 7956 /** 7957 * Reads a resource from the VFS, using the specified resource filter.<p> 7958 * 7959 * @param dbc the current database context 7960 * @param structureID the structure id of the resource to read 7961 * @param filter the resource filter to use while reading 7962 * 7963 * @return the resource that was read 7964 * 7965 * @throws CmsDataAccessException if something goes wrong 7966 * 7967 * @see CmsObject#readResource(CmsUUID, CmsResourceFilter) 7968 * @see CmsObject#readResource(CmsUUID) 7969 */ 7970 public CmsResource readResource(CmsDbContext dbc, CmsUUID structureID, CmsResourceFilter filter) 7971 throws CmsDataAccessException { 7972 7973 CmsUUID projectId = getProjectIdForContext(dbc); 7974 // please note: the filter will be applied in the security manager later 7975 CmsResource resource = getVfsDriver(dbc).readResource(dbc, projectId, structureID, filter.includeDeleted()); 7976 7977 // context dates need to be updated 7978 updateContextDates(dbc, resource); 7979 7980 // return the resource 7981 return resource; 7982 } 7983 7984 /** 7985 * Reads a resource from the VFS, using the specified resource filter.<p> 7986 * 7987 * @param dbc the current database context 7988 * @param resourcePath the name of the resource to read (full path) 7989 * @param filter the resource filter to use while reading 7990 * 7991 * @return the resource that was read 7992 * 7993 * @throws CmsDataAccessException if something goes wrong 7994 * 7995 * @see CmsObject#readResource(String, CmsResourceFilter) 7996 * @see CmsObject#readResource(String) 7997 * @see CmsObject#readFile(CmsResource) 7998 */ 7999 public CmsResource readResource(CmsDbContext dbc, String resourcePath, CmsResourceFilter filter) 8000 throws CmsDataAccessException { 8001 8002 CmsUUID projectId = getProjectIdForContext(dbc); 8003 // please note: the filter will be applied in the security manager later 8004 CmsResource resource = getVfsDriver(dbc).readResource(dbc, projectId, resourcePath, filter.includeDeleted()); 8005 8006 // context dates need to be updated 8007 updateContextDates(dbc, resource); 8008 8009 // return the resource 8010 return resource; 8011 } 8012 8013 /** 8014 * Reads all resources below the given path matching the filter criteria, 8015 * including the full tree below the path only in case the <code>readTree</code> 8016 * parameter is <code>true</code>.<p> 8017 * 8018 * @param dbc the current database context 8019 * @param parent the parent path to read the resources from 8020 * @param filter the filter 8021 * @param readTree <code>true</code> to read all subresources 8022 * 8023 * @return a list of <code>{@link CmsResource}</code> objects matching the filter criteria 8024 * 8025 * @throws CmsDataAccessException if the bare reading of the resources fails 8026 * @throws CmsException if security and permission checks for the resources read fail 8027 */ 8028 public List<CmsResource> readResources( 8029 CmsDbContext dbc, 8030 CmsResource parent, 8031 CmsResourceFilter filter, 8032 boolean readTree) 8033 throws CmsException, CmsDataAccessException { 8034 8035 // try to get the sub resources from the cache 8036 String cacheKey = getCacheKey( 8037 new String[] {dbc.currentUser().getName(), filter.getCacheId(), readTree ? "+" : "-", parent.getRootPath()}, 8038 dbc); 8039 8040 List<CmsResource> resourceList = m_monitor.getCachedResourceList(cacheKey); 8041 if ((resourceList == null) || !dbc.getProjectId().isNullUUID()) { 8042 // read the result from the database 8043 resourceList = getVfsDriver(dbc).readResourceTree( 8044 dbc, 8045 dbc.currentProject().getUuid(), 8046 (readTree ? parent.getRootPath() : parent.getStructureId().toString()), 8047 filter.getType(), 8048 filter.getState(), 8049 filter.getModifiedAfter(), 8050 filter.getModifiedBefore(), 8051 filter.getReleaseAfter(), 8052 filter.getReleaseBefore(), 8053 filter.getExpireAfter(), 8054 filter.getExpireBefore(), 8055 (readTree ? CmsDriverManager.READMODE_INCLUDE_TREE : CmsDriverManager.READMODE_EXCLUDE_TREE) 8056 | (filter.excludeType() ? CmsDriverManager.READMODE_EXCLUDE_TYPE : 0) 8057 | (filter.excludeState() ? CmsDriverManager.READMODE_EXCLUDE_STATE : 0) 8058 | ((filter.getOnlyFolders() != null) 8059 ? (filter.getOnlyFolders().booleanValue() 8060 ? CmsDriverManager.READMODE_ONLY_FOLDERS 8061 : CmsDriverManager.READMODE_ONLY_FILES) 8062 : 0)); 8063 8064 // HACK: do not take care of permissions if reading organizational units 8065 if (!parent.getRootPath().startsWith("/system/orgunits/")) { 8066 // apply permission filter 8067 resourceList = filterPermissions(dbc, resourceList, filter); 8068 } 8069 // store the result in the resourceList cache 8070 if (dbc.getProjectId().isNullUUID()) { 8071 m_monitor.cacheResourceList(cacheKey, resourceList); 8072 } 8073 } 8074 // we must always apply the result filter and update the context dates 8075 return updateContextDates(dbc, resourceList, filter); 8076 } 8077 8078 /** 8079 * Returns the resources that were visited by a user set in the filter.<p> 8080 * 8081 * @param dbc the database context 8082 * @param poolName the name of the database pool to use 8083 * @param filter the filter that is used to get the visited resources 8084 * 8085 * @return the resources that were visited by a user set in the filter 8086 * 8087 * @throws CmsException if something goes wrong 8088 */ 8089 public List<CmsResource> readResourcesVisitedBy(CmsDbContext dbc, String poolName, CmsVisitedByFilter filter) 8090 throws CmsException { 8091 8092 List<CmsResource> result = getSubscriptionDriver().readResourcesVisitedBy(dbc, poolName, filter); 8093 result = filterPermissions(dbc, result, CmsResourceFilter.DEFAULT); 8094 return result; 8095 } 8096 8097 /** 8098 * Reads all resources that have a value (containing the given value string) set 8099 * for the specified property (definition) in the given path.<p> 8100 * 8101 * Both individual and shared properties of a resource are checked.<p> 8102 * 8103 * If the <code>value</code> parameter is <code>null</code>, all resources having the 8104 * given property set are returned.<p> 8105 * 8106 * @param dbc the current database context 8107 * @param folder the folder to get the resources with the property from 8108 * @param propertyDefinition the name of the property (definition) to check for 8109 * @param value the string to search in the value of the property 8110 * @param filter the resource filter to apply to the result set 8111 * 8112 * @return a list of all <code>{@link CmsResource}</code> objects 8113 * that have a value set for the specified property. 8114 * 8115 * @throws CmsException if something goes wrong 8116 */ 8117 public List<CmsResource> readResourcesWithProperty( 8118 CmsDbContext dbc, 8119 CmsResource folder, 8120 String propertyDefinition, 8121 String value, 8122 CmsResourceFilter filter) 8123 throws CmsException { 8124 8125 String cacheKey; 8126 if (value == null) { 8127 cacheKey = getCacheKey( 8128 new String[] { 8129 dbc.currentUser().getName(), 8130 folder.getRootPath(), 8131 propertyDefinition, 8132 filter.getCacheId()}, 8133 dbc); 8134 } else { 8135 cacheKey = getCacheKey( 8136 new String[] { 8137 dbc.currentUser().getName(), 8138 folder.getRootPath(), 8139 propertyDefinition, 8140 value, 8141 filter.getCacheId()}, 8142 dbc); 8143 } 8144 List<CmsResource> resourceList = m_monitor.getCachedResourceList(cacheKey); 8145 if ((resourceList == null) || !dbc.getProjectId().isNullUUID()) { 8146 8147 CmsPropertyDefinition propDef = null; 8148 try { 8149 // first read the property definition 8150 propDef = readPropertyDefinition(dbc, propertyDefinition); 8151 } catch (CmsDbEntryNotFoundException e) { 8152 LOG.debug(e.getLocalizedMessage(), e); 8153 } 8154 if (propDef != null) { 8155 // now read the list of resources that have a value set for the property definition 8156 resourceList = getVfsDriver(dbc).readResourcesWithProperty( 8157 dbc, 8158 dbc.currentProject().getUuid(), 8159 propDef.getId(), 8160 folder.getRootPath(), 8161 value); 8162 // apply permission filter 8163 resourceList = filterPermissions(dbc, resourceList, filter); 8164 } else { 8165 resourceList = new ArrayList<>(); 8166 } 8167 // store the result in the resourceList cache 8168 if (dbc.getProjectId().isNullUUID()) { 8169 m_monitor.cacheResourceList(cacheKey, resourceList); 8170 } 8171 } 8172 // we must always apply the result filter and update the context dates 8173 return updateContextDates(dbc, resourceList, filter); 8174 } 8175 8176 /** 8177 * Returns the set of users that are responsible for a specific resource.<p> 8178 * 8179 * @param dbc the current database context 8180 * @param resource the resource to get the responsible users from 8181 * 8182 * @return the set of users that are responsible for a specific resource 8183 * 8184 * @throws CmsException if something goes wrong 8185 */ 8186 public Set<I_CmsPrincipal> readResponsiblePrincipals(CmsDbContext dbc, CmsResource resource) throws CmsException { 8187 8188 Set<I_CmsPrincipal> result = new HashSet<I_CmsPrincipal>(); 8189 Iterator<CmsAccessControlEntry> aces = getAccessControlEntries(dbc, resource, true).iterator(); 8190 while (aces.hasNext()) { 8191 CmsAccessControlEntry ace = aces.next(); 8192 if (ace.isResponsible()) { 8193 I_CmsPrincipal p = lookupPrincipal(dbc, ace.getPrincipal()); 8194 if (p != null) { 8195 result.add(p); 8196 } 8197 } 8198 } 8199 return result; 8200 } 8201 8202 /** 8203 * Returns the set of users that are responsible for a specific resource.<p> 8204 * 8205 * @param dbc the current database context 8206 * @param resource the resource to get the responsible users from 8207 * 8208 * @return the set of users that are responsible for a specific resource 8209 * 8210 * @throws CmsException if something goes wrong 8211 */ 8212 public Set<CmsUser> readResponsibleUsers(CmsDbContext dbc, CmsResource resource) throws CmsException { 8213 8214 Set<CmsUser> result = new HashSet<CmsUser>(); 8215 Iterator<I_CmsPrincipal> principals = readResponsiblePrincipals(dbc, resource).iterator(); 8216 while (principals.hasNext()) { 8217 I_CmsPrincipal principal = principals.next(); 8218 if (principal.isGroup()) { 8219 try { 8220 result.addAll(getUsersOfGroup(dbc, principal.getName(), true, false, false)); 8221 } catch (CmsException e) { 8222 if (LOG.isInfoEnabled()) { 8223 LOG.info(e.getLocalizedMessage(), e); 8224 } 8225 } 8226 } else { 8227 result.add((CmsUser)principal); 8228 } 8229 } 8230 return result; 8231 } 8232 8233 /** 8234 * Returns a List of all siblings of the specified resource, 8235 * the specified resource being always part of the result set.<p> 8236 * 8237 * The result is a list of <code>{@link CmsResource}</code> objects.<p> 8238 * 8239 * @param dbc the current database context 8240 * @param resource the resource to read the siblings for 8241 * @param filter a filter object 8242 * 8243 * @return a list of <code>{@link CmsResource}</code> Objects that 8244 * are siblings to the specified resource, 8245 * including the specified resource itself 8246 * 8247 * @throws CmsException if something goes wrong 8248 */ 8249 public List<CmsResource> readSiblings(CmsDbContext dbc, CmsResource resource, CmsResourceFilter filter) 8250 throws CmsException { 8251 8252 List<CmsResource> siblings = getVfsDriver( 8253 dbc).readSiblings(dbc, dbc.currentProject().getUuid(), resource, filter.includeDeleted()); 8254 8255 // important: there is no permission check done on the returned list of siblings 8256 // this is because of possible issues with the "publish all siblings" option, 8257 // moreover the user has read permission for the content through 8258 // the selected sibling anyway 8259 return updateContextDates(dbc, siblings, filter); 8260 } 8261 8262 /** 8263 * Returns the parameters of a resource in the table of all published template resources.<p> 8264 * 8265 * @param dbc the current database context 8266 * @param rfsName the rfs name of the resource 8267 * 8268 * @return the parameter string of the requested resource 8269 * 8270 * @throws CmsException if something goes wrong 8271 */ 8272 public String readStaticExportPublishedResourceParameters(CmsDbContext dbc, String rfsName) throws CmsException { 8273 8274 return getProjectDriver(dbc).readStaticExportPublishedResourceParameters(dbc, rfsName); 8275 } 8276 8277 /** 8278 * Returns a list of all template resources which must be processed during a static export.<p> 8279 * 8280 * @param dbc the current database context 8281 * @param parameterResources flag for reading resources with parameters (1) or without (0) 8282 * @param timestamp for reading the data from the db 8283 * 8284 * @return a list of template resources as <code>{@link String}</code> objects 8285 * 8286 * @throws CmsException if something goes wrong 8287 */ 8288 public List<String> readStaticExportResources(CmsDbContext dbc, int parameterResources, long timestamp) 8289 throws CmsException { 8290 8291 return getProjectDriver(dbc).readStaticExportResources(dbc, parameterResources, timestamp); 8292 } 8293 8294 /** 8295 * Returns the subscribed history resources that were deleted.<p> 8296 * 8297 * @param dbc the database context 8298 * @param poolName the name of the database pool to use 8299 * @param user the user that subscribed to the resource 8300 * @param groups the groups to check subscribed resources for 8301 * @param parent the parent resource (folder) of the deleted resources, if <code>null</code> all deleted resources will be returned 8302 * @param includeSubFolders indicates if the sub folders of the specified folder path should be considered, too 8303 * @param deletedFrom the time stamp from which the resources should have been deleted 8304 * 8305 * @return the subscribed history resources that were deleted 8306 * 8307 * @throws CmsException if something goes wrong 8308 */ 8309 public List<I_CmsHistoryResource> readSubscribedDeletedResources( 8310 CmsDbContext dbc, 8311 String poolName, 8312 CmsUser user, 8313 List<CmsGroup> groups, 8314 CmsResource parent, 8315 boolean includeSubFolders, 8316 long deletedFrom) 8317 throws CmsException { 8318 8319 List<I_CmsHistoryResource> result = getSubscriptionDriver().readSubscribedDeletedResources( 8320 dbc, 8321 poolName, 8322 user, 8323 groups, 8324 parent, 8325 includeSubFolders, 8326 deletedFrom); 8327 8328 return result; 8329 } 8330 8331 /** 8332 * Returns the resources that were subscribed by a user or group set in the filter.<p> 8333 * 8334 * @param dbc the database context 8335 * @param poolName the name of the database pool to use 8336 * @param filter the filter that is used to get the subscribed resources 8337 * 8338 * @return the resources that were subscribed by a user or group set in the filter 8339 * 8340 * @throws CmsException if something goes wrong 8341 */ 8342 public List<CmsResource> readSubscribedResources(CmsDbContext dbc, String poolName, CmsSubscriptionFilter filter) 8343 throws CmsException { 8344 8345 List<CmsResource> result = getSubscriptionDriver().readSubscribedResources(dbc, poolName, filter); 8346 8347 result = filterPermissions(dbc, result, CmsResourceFilter.DEFAULT); 8348 return result; 8349 } 8350 8351 /** 8352 * Reads URL name mapping entries which match the given filter.<p> 8353 * 8354 * @param dbc the database context 8355 * @param online if true, read online URL name mappings, else offline ones 8356 * @param filter the filter for matching the URL name entries 8357 * 8358 * @return the list of URL name mapping entries which match the given filter 8359 * 8360 * @throws CmsDataAccessException if something goes wrong 8361 */ 8362 public List<CmsUrlNameMappingEntry> readUrlNameMappingEntries( 8363 CmsDbContext dbc, 8364 boolean online, 8365 CmsUrlNameMappingFilter filter) 8366 throws CmsDataAccessException { 8367 8368 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 8369 return vfsDriver.readUrlNameMappingEntries(dbc, online, filter); 8370 } 8371 8372 /** 8373 * Reads the URL name mappings matching the given filter.<p> 8374 * 8375 * @param dbc the DB context to use 8376 * @param filter the filter used to select the mapping entries 8377 * @return the entries matching the given filter 8378 * 8379 * @throws CmsDataAccessException if something goes wrong 8380 */ 8381 public List<CmsUrlNameMappingEntry> readUrlNameMappings(CmsDbContext dbc, CmsUrlNameMappingFilter filter) 8382 throws CmsDataAccessException { 8383 8384 List<CmsUrlNameMappingEntry> entries = getVfsDriver(dbc).readUrlNameMappingEntries( 8385 dbc, 8386 dbc.currentProject().isOnlineProject(), 8387 filter); 8388 return entries; 8389 } 8390 8391 /** 8392 * Reads the newest URL names of a resource for all locales.<p> 8393 * 8394 * @param dbc the database context 8395 * @param id the resource's structure id 8396 * 8397 * @return the url names for the locales 8398 * 8399 * @throws CmsDataAccessException if the database operation failed 8400 */ 8401 public List<String> readUrlNamesForAllLocales(CmsDbContext dbc, CmsUUID id) throws CmsDataAccessException { 8402 8403 List<String> result = new ArrayList<String>(); 8404 List<CmsUrlNameMappingEntry> entries = getVfsDriver(dbc).readUrlNameMappingEntries( 8405 dbc, 8406 dbc.currentProject().isOnlineProject(), 8407 CmsUrlNameMappingFilter.ALL.filterStructureId(id)); 8408 ArrayListMultimap<String, CmsUrlNameMappingEntry> entriesByLocale = ArrayListMultimap.create(); 8409 for (CmsUrlNameMappingEntry entry : entries) { 8410 String localeKey = entry.getLocale(); 8411 entriesByLocale.put(localeKey, entry); 8412 } 8413 8414 for (String localeKey : entriesByLocale.keySet()) { 8415 List<CmsUrlNameMappingEntry> entrs = entriesByLocale.get(localeKey); 8416 CmsUrlNameMappingEntry maxEntryForLocale = Collections.max(entrs, new UrlNameMappingComparator()); 8417 result.add(maxEntryForLocale.getName()); 8418 } 8419 return result; 8420 } 8421 8422 /** 8423 * Returns a user object based on the id of a user.<p> 8424 * 8425 * @param dbc the current database context 8426 * @param id the id of the user to read 8427 * 8428 * @return the user read 8429 * 8430 * @throws CmsException if something goes wrong 8431 */ 8432 public CmsUser readUser(CmsDbContext dbc, CmsUUID id) throws CmsException { 8433 8434 CmsUser user = m_monitor.getCachedUser(id.toString()); 8435 if (user == null) { 8436 user = getUserDriver(dbc).readUser(dbc, id); 8437 m_monitor.cacheUser(user); 8438 } 8439 // important: do not return the cached user object, but a clone to avoid unwanted changes on cached objects 8440 return user.clone(); 8441 } 8442 8443 /** 8444 * Returns a user object.<p> 8445 * 8446 * @param dbc the current database context 8447 * @param username the name of the user that is to be read 8448 * 8449 * @return user read 8450 * 8451 * @throws CmsDataAccessException if operation was not successful 8452 */ 8453 public CmsUser readUser(CmsDbContext dbc, String username) throws CmsDataAccessException { 8454 8455 CmsUser user = m_monitor.getCachedUser(username); 8456 if (user == null) { 8457 user = getUserDriver(dbc).readUser(dbc, username); 8458 m_monitor.cacheUser(user); 8459 } 8460 // important: do not return the cached user object, but a clone to avoid unwanted changes on cached objects 8461 return user.clone(); 8462 } 8463 8464 /** 8465 * Returns a user object if the password for the user is correct.<p> 8466 * 8467 * If the user/pwd pair is not valid a <code>{@link CmsException}</code> is thrown.<p> 8468 * 8469 * @param dbc the current database context 8470 * @param username the username of the user that is to be read 8471 * @param password the password of the user that is to be read 8472 * 8473 * @return user read 8474 * 8475 * @throws CmsException if operation was not successful 8476 */ 8477 public CmsUser readUser(CmsDbContext dbc, String username, String password) throws CmsException { 8478 8479 // don't read user from cache here because password may have changed 8480 CmsUser user = getUserDriver(dbc).readUser(dbc, username, password, null); 8481 m_monitor.cacheUser(user); 8482 return user; 8483 } 8484 8485 /** 8486 * Removes an access control entry for a given resource and principal.<p> 8487 * 8488 * @param dbc the current database context 8489 * @param resource the resource 8490 * @param principal the id of the principal to remove the the access control entry for 8491 * 8492 * @throws CmsException if something goes wrong 8493 */ 8494 public void removeAccessControlEntry(CmsDbContext dbc, CmsResource resource, CmsUUID principal) 8495 throws CmsException { 8496 8497 // remove the ace 8498 getUserDriver(dbc).removeAccessControlEntry(dbc, dbc.currentProject(), resource.getResourceId(), principal); 8499 8500 // log it 8501 log( 8502 dbc, 8503 new CmsLogEntry( 8504 dbc, 8505 resource.getStructureId(), 8506 CmsLogEntryType.RESOURCE_PERMISSIONS, 8507 new String[] {resource.getRootPath()}), 8508 false); 8509 8510 // update the "last modified" information 8511 setDateLastModified(dbc, resource, resource.getDateLastModified()); 8512 8513 // clear the cache 8514 m_monitor.clearAccessControlListCache(); 8515 8516 // fire a resource modification event 8517 Map<String, Object> data = new HashMap<String, Object>(2); 8518 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 8519 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_ACCESSCONTROL)); 8520 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 8521 } 8522 8523 /** 8524 * Removes a resource from the given organizational unit.<p> 8525 * 8526 * @param dbc the current db context 8527 * @param orgUnit the organizational unit to remove the resource from 8528 * @param resource the resource that is to be removed from the organizational unit 8529 * 8530 * @throws CmsException if something goes wrong 8531 * 8532 * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String) 8533 * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String) 8534 */ 8535 public void removeResourceFromOrgUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, CmsResource resource) 8536 throws CmsException { 8537 8538 m_monitor.flushCache(CmsMemoryMonitor.CacheType.HAS_ROLE, CmsMemoryMonitor.CacheType.ROLE_LIST); 8539 getUserDriver(dbc).removeResourceFromOrganizationalUnit(dbc, orgUnit, resource); 8540 } 8541 8542 /** 8543 * Removes a resource from the current project of the user.<p> 8544 * 8545 * @param dbc the current database context 8546 * @param resource the resource to apply this operation to 8547 * 8548 * @throws CmsException if something goes wrong 8549 * 8550 * @see CmsObject#copyResourceToProject(String) 8551 * @see I_CmsResourceType#copyResourceToProject(CmsObject, CmsSecurityManager, CmsResource) 8552 */ 8553 public void removeResourceFromProject(CmsDbContext dbc, CmsResource resource) throws CmsException { 8554 8555 // remove the resource to the project only if the resource is already in the project 8556 if (isInsideCurrentProject(dbc, resource.getRootPath())) { 8557 // check if there are already any subfolders of this resource 8558 I_CmsProjectDriver projectDriver = getProjectDriver(dbc); 8559 if (resource.isFolder()) { 8560 List<String> projectResources = projectDriver.readProjectResources(dbc, dbc.currentProject()); 8561 for (int i = 0; i < projectResources.size(); i++) { 8562 String resname = projectResources.get(i); 8563 if (resname.startsWith(resource.getRootPath())) { 8564 // delete the existing project resource first 8565 projectDriver.deleteProjectResource(dbc, dbc.currentProject().getUuid(), resname); 8566 } 8567 } 8568 } 8569 try { 8570 projectDriver.deleteProjectResource(dbc, dbc.currentProject().getUuid(), resource.getRootPath()); 8571 } catch (CmsException exc) { 8572 // if the subfolder exists already - all is ok 8573 } finally { 8574 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROJECT_RESOURCES); 8575 8576 OpenCms.fireCmsEvent( 8577 new CmsEvent( 8578 I_CmsEventListener.EVENT_PROJECT_MODIFIED, 8579 Collections.<String, Object> singletonMap("project", dbc.currentProject()))); 8580 } 8581 } 8582 } 8583 8584 /** 8585 * Removes the given resource to the given user's publish list.<p> 8586 * 8587 * @param dbc the database context 8588 * @param userId the user's id 8589 * @param structureIds the collection of structure IDs to remove 8590 * 8591 * @throws CmsDataAccessException if something goes wrong 8592 */ 8593 public void removeResourceFromUsersPubList(CmsDbContext dbc, CmsUUID userId, Collection<CmsUUID> structureIds) 8594 throws CmsDataAccessException { 8595 8596 for (CmsUUID structureId : structureIds) { 8597 CmsLogEntry entry = new CmsLogEntry( 8598 userId, 8599 System.currentTimeMillis(), 8600 structureId, 8601 CmsLogEntryType.RESOURCE_HIDDEN, 8602 new String[] {readResource(dbc, structureId, CmsResourceFilter.ALL).getRootPath()}); 8603 log(dbc, entry, true); 8604 } 8605 } 8606 8607 /** 8608 * Removes a user from a group.<p> 8609 * 8610 * @param dbc the current database context 8611 * @param username the name of the user that is to be removed from the group 8612 * @param groupname the name of the group 8613 * @param readRoles if to read roles or groups 8614 * 8615 * @throws CmsException if operation was not successful 8616 * @throws CmsIllegalArgumentException if the given user was not member in the given group 8617 * @throws CmsDbEntryNotFoundException if the given group was not found 8618 * @throws CmsSecurityException if the given user was <b>read as 'null' from the database</b> 8619 * 8620 * @see #addUserToGroup(CmsDbContext, String, String, boolean) 8621 */ 8622 public void removeUserFromGroup(CmsDbContext dbc, String username, String groupname, boolean readRoles) 8623 throws CmsException, CmsIllegalArgumentException, CmsDbEntryNotFoundException, CmsSecurityException { 8624 8625 CmsGroup group = readGroup(dbc, groupname); 8626 //check if group exists 8627 if (group == null) { 8628 // the group does not exists 8629 throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, groupname)); 8630 } 8631 if (group.isVirtual() && !readRoles) { 8632 // if removing a user from a virtual role treat it as removing the user from the role 8633 removeUserFromGroup(dbc, username, CmsRole.valueOf(group).getGroupName(), true); 8634 return; 8635 } 8636 if (group.isVirtual()) { 8637 // this is an hack so to prevent a unlimited recursive calls 8638 readRoles = false; 8639 } 8640 if ((readRoles && !group.isRole()) || (!readRoles && group.isRole())) { 8641 // we want a role but we got a group, or the other way 8642 throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, groupname)); 8643 } 8644 8645 boolean skipRemove = false; 8646 // test if this user is existing in the group 8647 if (!userInGroup(dbc, username, groupname, readRoles)) { 8648 if (readRoles) { 8649 // Sometimes users can end up with the default groups corresponding to roles (Administrators, Users) without the actual roles. 8650 // When trying to remove the user from such a group, we end up here in a recursive call of this method with readRoles = true. We do not 8651 // want to throw an exception then, because it would prevent the code that actually removes the user from the group from running. 8652 LOG.warn( 8653 "Trying to remove user from role that they are not a member of (user: " 8654 + username 8655 + ", group: " 8656 + groupname 8657 + ")"); 8658 skipRemove = true; 8659 } else { 8660 // user is not in the group, throw exception 8661 throw new CmsIllegalArgumentException( 8662 Messages.get().container(Messages.ERR_USER_NOT_IN_GROUP_2, username, groupname)); 8663 } 8664 } 8665 8666 CmsUser user = readUser(dbc, username); 8667 //check if the user exists 8668 if (user == null) { 8669 // the user does not exists 8670 throw new CmsIllegalArgumentException( 8671 Messages.get().container(Messages.ERR_USER_NOT_IN_GROUP_2, username, groupname)); 8672 } 8673 8674 if (readRoles) { 8675 CmsRole role = CmsRole.valueOf(group); 8676 // update virtual groups 8677 Iterator<CmsGroup> it = getVirtualGroupsForRole(dbc, role).iterator(); 8678 while (it.hasNext()) { 8679 CmsGroup virtualGroup = it.next(); 8680 if (userInGroup(dbc, username, virtualGroup.getName(), false)) { 8681 // here we say readroles = true, to prevent an unlimited recursive calls 8682 removeUserFromGroup(dbc, username, virtualGroup.getName(), true); 8683 } 8684 } 8685 } 8686 if (!skipRemove) { 8687 getUserDriver(dbc).deleteUserInGroup(dbc, user.getId(), group.getId()); 8688 } 8689 8690 // flush relevant caches 8691 if (readRoles) { 8692 m_monitor.flushCache(CmsMemoryMonitor.CacheType.HAS_ROLE, CmsMemoryMonitor.CacheType.ROLE_LIST); 8693 } 8694 m_monitor.flushUserGroups(user.getId()); 8695 m_monitor.flushCache(CmsMemoryMonitor.CacheType.USER_LIST); 8696 8697 if (!dbc.getProjectId().isNullUUID()) { 8698 // user modified event is not needed 8699 return; 8700 } 8701 // fire user modified event 8702 Map<String, Object> eventData = new HashMap<String, Object>(); 8703 eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); 8704 eventData.put(I_CmsEventListener.KEY_USER_NAME, user.getName()); 8705 eventData.put(I_CmsEventListener.KEY_GROUP_ID, group.getId().toString()); 8706 eventData.put(I_CmsEventListener.KEY_GROUP_NAME, group.getName()); 8707 eventData.put( 8708 I_CmsEventListener.KEY_USER_ACTION, 8709 I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_REMOVE_USER_FROM_GROUP); 8710 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); 8711 8712 } 8713 8714 /** 8715 * Repairs broken categories.<p> 8716 * 8717 * @param dbc the database context 8718 * @param projectId the project id 8719 * @param resource the resource to repair the categories for 8720 * 8721 * @throws CmsException if something goes wrong 8722 */ 8723 public void repairCategories(CmsDbContext dbc, CmsUUID projectId, CmsResource resource) throws CmsException { 8724 8725 CmsObject cms = OpenCms.initCmsObject(new CmsObject(getSecurityManager(), dbc.getRequestContext())); 8726 cms.getRequestContext().setSiteRoot(""); 8727 cms.getRequestContext().setCurrentProject(readProject(dbc, projectId)); 8728 CmsCategoryService.getInstance().repairRelations(cms, resource); 8729 } 8730 8731 /** 8732 * Replaces the content, type and properties of a resource.<p> 8733 * 8734 * @param dbc the current database context 8735 * @param resource the name of the resource to apply this operation to 8736 * @param type the new type of the resource 8737 * @param content the new content of the resource 8738 * @param properties the new properties of the resource 8739 * 8740 * @throws CmsException if something goes wrong 8741 * 8742 * @see CmsObject#replaceResource(String, int, byte[], List) 8743 * @see I_CmsResourceType#replaceResource(CmsObject, CmsSecurityManager, CmsResource, int, byte[], List) 8744 */ 8745 @SuppressWarnings("javadoc") 8746 public void replaceResource( 8747 CmsDbContext dbc, 8748 CmsResource resource, 8749 int type, 8750 byte[] content, 8751 List<CmsProperty> properties) 8752 throws CmsException { 8753 8754 // replace the existing with the new file content 8755 getVfsDriver(dbc).replaceResource(dbc, resource, content, type); 8756 8757 if ((properties != null) && !properties.isEmpty()) { 8758 // write the properties 8759 getVfsDriver(dbc).writePropertyObjects(dbc, dbc.currentProject(), resource, properties); 8760 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); 8761 } 8762 8763 // update the resource state 8764 if (resource.getState().isUnchanged()) { 8765 resource.setState(CmsResource.STATE_CHANGED); 8766 } 8767 resource.setUserLastModified(dbc.currentUser().getId()); 8768 8769 // log it 8770 log( 8771 dbc, 8772 new CmsLogEntry( 8773 dbc, 8774 resource.getStructureId(), 8775 CmsLogEntryType.RESOURCE_CONTENT_MODIFIED, 8776 new String[] {resource.getRootPath()}), 8777 false); 8778 8779 setDateLastModified(dbc, resource, System.currentTimeMillis()); 8780 8781 getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_RESOURCE, false); 8782 8783 deleteRelationsWithSiblings(dbc, resource); 8784 8785 // clear the cache 8786 m_monitor.clearResourceCache(); 8787 8788 if ((properties != null) && !properties.isEmpty()) { 8789 // resource and properties were modified 8790 OpenCms.fireCmsEvent( 8791 new CmsEvent( 8792 I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, 8793 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, resource))); 8794 } else { 8795 // only the resource was modified 8796 Map<String, Object> data = new HashMap<String, Object>(2); 8797 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 8798 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_RESOURCE | CHANGED_CONTENT)); 8799 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 8800 } 8801 } 8802 8803 /** 8804 * Resets the password for a specified user.<p> 8805 * 8806 * @param dbc the current database context 8807 * @param username the name of the user 8808 * @param oldPassword the old password 8809 * @param secondFactor the second factor data used for 2FA 8810 * @param newPassword the new password 8811 * 8812 * @throws CmsException if the user data could not be read from the database 8813 * @throws CmsSecurityException if the specified username and old password could not be verified 8814 */ 8815 public void resetPassword( 8816 CmsDbContext dbc, 8817 String username, 8818 String oldPassword, 8819 CmsSecondFactorInfo secondFactor, 8820 String newPassword) 8821 throws CmsException, CmsSecurityException { 8822 8823 if ((oldPassword != null) && (newPassword != null)) { 8824 8825 CmsUser user = null; 8826 8827 if (dbc.getRequestContext().getAttribute(CmsUserDriver.REQ_ATTR_DONT_DIGEST_PASSWORD) == null) { 8828 validatePassword(newPassword); 8829 } 8830 8831 // read the user as a system user to verify that the specified old password is correct 8832 try { 8833 user = getUserDriver(dbc).readUser(dbc, username, oldPassword, null); 8834 } catch (CmsDbEntryNotFoundException e) { 8835 throw new CmsDataAccessException(Messages.get().container(Messages.ERR_RESET_PASSWORD_1, username), e); 8836 } 8837 8838 if ((user == null) || user.isManaged()) { 8839 throw new CmsDataAccessException(Messages.get().container(Messages.ERR_RESET_PASSWORD_1, username)); 8840 } 8841 8842 CmsTwoFactorAuthenticationHandler twoFactorHandler = OpenCms.getTwoFactorAuthenticationHandler(); 8843 if (twoFactorHandler.needsTwoFactorAuthentication(user) && twoFactorHandler.hasSecondFactor(user)) { 8844 if (!twoFactorHandler.verifySecondFactor(user, secondFactor)) { 8845 throw new CmsDataAccessException( 8846 Messages.get().container(Messages.ERR_RESET_PASSWORD_1, username), 8847 new RuntimeException("Verification code mismatch")); 8848 } 8849 } 8850 8851 getUserDriver(dbc).writePassword(dbc, username, oldPassword, newPassword); 8852 user.getAdditionalInfo().put( 8853 CmsUserSettings.ADDITIONAL_INFO_LAST_PASSWORD_CHANGE, 8854 "" + System.currentTimeMillis()); 8855 user.deleteAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_PASSWORD_RESET); 8856 getUserDriver(dbc).writeUser(dbc, user); 8857 8858 if (!dbc.getProjectId().isNullUUID()) { 8859 // user modified event is not needed 8860 return; 8861 } 8862 // fire user modified event 8863 Map<String, Object> eventData = new HashMap<String, Object>(); 8864 eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); 8865 eventData.put( 8866 I_CmsEventListener.KEY_USER_ACTION, 8867 I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_RESET_PASSWORD); 8868 eventData.put( 8869 I_CmsEventListener.KEY_USER_CHANGES, 8870 Integer.valueOf(CmsUser.FLAG_CORE_DATA | CmsUser.FLAG_CORE_DATA)); 8871 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); 8872 8873 } else if (CmsStringUtil.isEmpty(oldPassword)) { 8874 throw new CmsDataAccessException(Messages.get().container(Messages.ERR_PWD_OLD_MISSING_0)); 8875 } else if (CmsStringUtil.isEmpty(newPassword)) { 8876 throw new CmsDataAccessException(Messages.get().container(Messages.ERR_PWD_NEW_MISSING_0)); 8877 } 8878 } 8879 8880 /** 8881 * Restores a deleted resource identified by its structure id from the historical archive.<p> 8882 * 8883 * @param dbc the current database context 8884 * @param structureId the structure id of the resource to restore 8885 * 8886 * @throws CmsException if something goes wrong 8887 * 8888 * @see CmsObject#restoreDeletedResource(CmsUUID) 8889 */ 8890 public void restoreDeletedResource(CmsDbContext dbc, CmsUUID structureId) throws CmsException { 8891 8892 // get the last version, which should be the deleted one 8893 int version = getHistoryDriver(dbc).readLastVersion(dbc, structureId); 8894 // get that version 8895 I_CmsHistoryResource histRes = getHistoryDriver(dbc).readResource(dbc, structureId, version); 8896 8897 // check the parent path 8898 CmsResource parent; 8899 try { 8900 // try to read the parent resource by id 8901 parent = getVfsDriver(dbc).readResource(dbc, dbc.currentProject().getUuid(), histRes.getParentId(), true); 8902 } catch (CmsVfsResourceNotFoundException e) { 8903 // if not found try to read the parent resource by name 8904 try { 8905 // try to read the parent resource by id 8906 parent = getVfsDriver(dbc).readResource( 8907 dbc, 8908 dbc.currentProject().getUuid(), 8909 CmsResource.getParentFolder(histRes.getRootPath()), 8910 true); 8911 } catch (CmsVfsResourceNotFoundException e1) { 8912 // if not found try to restore the parent resource 8913 restoreDeletedResource(dbc, histRes.getParentId()); 8914 parent = readResource(dbc, histRes.getParentId(), CmsResourceFilter.IGNORE_EXPIRATION); 8915 } 8916 } 8917 // check write permissions 8918 m_securityManager.checkPermissions( 8919 dbc, 8920 parent, 8921 CmsPermissionSet.ACCESS_WRITE, 8922 false, 8923 CmsResourceFilter.IGNORE_EXPIRATION); 8924 8925 // check the name 8926 String path = parent.getRootPath(); 8927 String resName = CmsResource.getName(histRes.getRootPath()); // name 8928 String ext = ""; 8929 if (resName.charAt(resName.length() - 1) == '/') { 8930 resName = resName.substring(0, resName.length() - 1); 8931 } else { 8932 ext = CmsFileUtil.getExtension(resName); // extension 8933 } 8934 String nameWOExt = resName.substring(0, resName.length() - ext.length()); // name without extension 8935 for (int i = 1; true; i++) { 8936 try { 8937 readResource(dbc, path + resName, CmsResourceFilter.ALL); 8938 resName = nameWOExt + "_" + i + ext; 8939 // try the next resource name with following schema: path/name_{i}.ext 8940 } catch (CmsVfsResourceNotFoundException e) { 8941 // ok, we found a not used resource name 8942 break; 8943 } 8944 } 8945 8946 // check structure id 8947 CmsUUID id = structureId; 8948 if (getVfsDriver(dbc).validateStructureIdExists(dbc, dbc.currentProject().getUuid(), structureId)) { 8949 // should never happen, but if already exists create a new one 8950 id = new CmsUUID(); 8951 } 8952 8953 byte[] contents = null; 8954 boolean isFolder = true; 8955 8956 // do we need the contents? 8957 if (histRes instanceof CmsFile) { 8958 contents = ((CmsFile)histRes).getContents(); 8959 if ((contents == null) || (contents.length == 0)) { 8960 contents = getHistoryDriver(dbc).readContent(dbc, histRes.getResourceId(), histRes.getPublishTag()); 8961 } 8962 isFolder = false; 8963 } 8964 8965 // now read the historical properties 8966 List<CmsProperty> properties = getHistoryDriver(dbc).readProperties(dbc, histRes); 8967 8968 // create the object to create 8969 CmsResource newResource = new CmsResource( 8970 id, 8971 histRes.getResourceId(), 8972 path + resName, 8973 histRes.getTypeId(), 8974 isFolder, 8975 histRes.getFlags(), 8976 dbc.currentProject().getUuid(), 8977 CmsResource.STATE_NEW, 8978 histRes.getDateCreated(), 8979 histRes.getUserCreated(), 8980 histRes.getDateLastModified(), 8981 dbc.currentUser().getId(), 8982 histRes.getDateReleased(), 8983 histRes.getDateExpired(), 8984 histRes.getSiblingCount(), 8985 histRes.getLength(), 8986 histRes.getDateContent(), 8987 histRes.getVersion()); 8988 8989 // log it 8990 log( 8991 dbc, 8992 new CmsLogEntry( 8993 dbc, 8994 newResource.getStructureId(), 8995 CmsLogEntryType.RESOURCE_RESTORE_DELETED, 8996 new String[] {newResource.getRootPath()}), 8997 false); 8998 8999 // prevent the date last modified is set to the current time 9000 newResource.setDateLastModified(newResource.getDateLastModified()); 9001 // restore the resource! 9002 CmsResource resource = createResource(dbc, path + resName, newResource, contents, properties, true); 9003 // set resource state to changed 9004 newResource.setState(CmsResource.STATE_CHANGED); 9005 getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), newResource, UPDATE_RESOURCE_STATE, false); 9006 newResource.setState(CmsResource.STATE_NEW); 9007 // fire the event 9008 Map<String, Object> data = new HashMap<String, Object>(2); 9009 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 9010 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_RESOURCE | CHANGED_CONTENT)); 9011 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 9012 } 9013 9014 /** 9015 * Restores a resource in the current project with a version from the historical archive.<p> 9016 * 9017 * @param dbc the current database context 9018 * @param resource the resource to restore from the archive 9019 * @param version the version number to restore from the archive 9020 * 9021 * @throws CmsException if something goes wrong 9022 * 9023 * @see CmsObject#restoreResourceVersion(CmsUUID, int) 9024 * @see I_CmsResourceType#restoreResource(CmsObject, CmsSecurityManager, CmsResource, int) 9025 */ 9026 public void restoreResource(CmsDbContext dbc, CmsResource resource, int version) throws CmsException { 9027 9028 I_CmsHistoryResource historyResource = readResource(dbc, resource, version); 9029 CmsResourceState state = CmsResource.STATE_CHANGED; 9030 if (resource.getState().isNew()) { 9031 state = CmsResource.STATE_NEW; 9032 } 9033 int newVersion = resource.getVersion(); 9034 if (resource.getState().isUnchanged()) { 9035 newVersion++; 9036 } 9037 CmsResource newResource = null; 9038 // is the resource a file? 9039 if (historyResource instanceof CmsFile) { 9040 // get the historical up flags 9041 int flags = historyResource.getFlags(); 9042 if (resource.isLabeled()) { 9043 // set the flag for labeled links on the restored file 9044 flags |= CmsResource.FLAG_LABELED; 9045 } 9046 CmsFile newFile = new CmsFile( 9047 resource.getStructureId(), 9048 resource.getResourceId(), 9049 resource.getRootPath(), 9050 historyResource.getTypeId(), 9051 flags, 9052 dbc.currentProject().getUuid(), 9053 state, 9054 resource.getDateCreated(), 9055 historyResource.getUserCreated(), 9056 resource.getDateLastModified(), 9057 dbc.currentUser().getId(), 9058 historyResource.getDateReleased(), 9059 historyResource.getDateExpired(), 9060 resource.getSiblingCount(), 9061 historyResource.getLength(), 9062 historyResource.getDateContent(), 9063 newVersion, 9064 readFile(dbc, (CmsHistoryFile)historyResource).getContents()); 9065 9066 // log it 9067 log( 9068 dbc, 9069 new CmsLogEntry( 9070 dbc, 9071 newFile.getStructureId(), 9072 CmsLogEntryType.RESOURCE_HISTORY, 9073 new String[] {newFile.getRootPath()}), 9074 false); 9075 9076 newResource = writeFile(dbc, newFile); 9077 } else { 9078 // it is a folder! 9079 newResource = new CmsFolder( 9080 resource.getStructureId(), 9081 resource.getResourceId(), 9082 resource.getRootPath(), 9083 historyResource.getTypeId(), 9084 historyResource.getFlags(), 9085 dbc.currentProject().getUuid(), 9086 state, 9087 resource.getDateCreated(), 9088 historyResource.getUserCreated(), 9089 resource.getDateLastModified(), 9090 dbc.currentUser().getId(), 9091 historyResource.getDateReleased(), 9092 historyResource.getDateExpired(), 9093 newVersion); 9094 9095 // log it 9096 log( 9097 dbc, 9098 new CmsLogEntry( 9099 dbc, 9100 newResource.getStructureId(), 9101 CmsLogEntryType.RESOURCE_HISTORY, 9102 new String[] {newResource.getRootPath()}), 9103 false); 9104 9105 writeResource(dbc, newResource); 9106 } 9107 if (newResource != null) { 9108 // now read the historical properties 9109 List<CmsProperty> historyProperties = getHistoryDriver(dbc).readProperties(dbc, historyResource); 9110 // remove all properties 9111 deleteAllProperties(dbc, newResource.getRootPath()); 9112 // write them to the restored resource 9113 writePropertyObjects(dbc, newResource, historyProperties, false); 9114 9115 m_monitor.clearResourceCache(); 9116 } 9117 9118 Map<String, Object> data = new HashMap<String, Object>(2); 9119 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 9120 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_RESOURCE | CHANGED_CONTENT)); 9121 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 9122 } 9123 9124 /** 9125 * Saves a list of aliases for the same structure id, replacing any aliases for the same structure id.<p> 9126 * 9127 * @param dbc the current database context 9128 * @param project the current project 9129 * @param structureId the structure id for which the aliases should be saved 9130 * @param aliases the list of aliases to save 9131 * 9132 * @throws CmsException if something goes wrong 9133 */ 9134 public void saveAliases(CmsDbContext dbc, CmsProject project, CmsUUID structureId, List<CmsAlias> aliases) 9135 throws CmsException { 9136 9137 for (CmsAlias alias : aliases) { 9138 if (!structureId.equals(alias.getStructureId())) { 9139 throw new IllegalArgumentException("Aliases to replace must have the same structure id!"); 9140 } 9141 } 9142 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 9143 vfsDriver.deleteAliases(dbc, project, new CmsAliasFilter(null, null, structureId)); 9144 for (CmsAlias alias : aliases) { 9145 String aliasPath = alias.getAliasPath(); 9146 if (CmsAlias.ALIAS_PATTERN.matcher(aliasPath).matches()) { 9147 vfsDriver.insertAlias(dbc, project, alias); 9148 } else { 9149 LOG.error("Invalid alias path: " + aliasPath); 9150 } 9151 } 9152 } 9153 9154 /** 9155 * Replaces the complete list of rewrite aliases for a given site root.<p> 9156 * 9157 * @param dbc the current database context 9158 * @param siteRoot the site root for which the rewrite aliases should be replaced 9159 * @param newAliases the new aliases for the given site root 9160 * @throws CmsException if something goes wrong 9161 */ 9162 public void saveRewriteAliases(CmsDbContext dbc, String siteRoot, List<CmsRewriteAlias> newAliases) 9163 throws CmsException { 9164 9165 CmsRewriteAliasFilter filter = new CmsRewriteAliasFilter().setSiteRoot(siteRoot); 9166 getVfsDriver(dbc).deleteRewriteAliases(dbc, filter); 9167 getVfsDriver(dbc).insertRewriteAliases(dbc, newAliases); 9168 } 9169 9170 /** 9171 * Searches for users which fit the given criteria.<p> 9172 * 9173 * @param dbc the database context 9174 * @param searchParams the search criteria 9175 * 9176 * @return the users which fit the search criteria 9177 * 9178 * @throws CmsDataAccessException if something goes wrong 9179 */ 9180 public List<CmsUser> searchUsers(CmsDbContext dbc, CmsUserSearchParameters searchParams 9181 9182 ) throws CmsDataAccessException { 9183 9184 return getUserDriver(dbc).searchUsers(dbc, searchParams); 9185 } 9186 9187 /** 9188 * Changes the "expire" date of a resource.<p> 9189 * 9190 * @param dbc the current database context 9191 * @param resource the resource to touch 9192 * @param dateExpired the new expire date of the resource 9193 * 9194 * @throws CmsDataAccessException if something goes wrong 9195 * 9196 * @see CmsObject#setDateExpired(String, long, boolean) 9197 * @see I_CmsResourceType#setDateExpired(CmsObject, CmsSecurityManager, CmsResource, long, boolean) 9198 */ 9199 public void setDateExpired(CmsDbContext dbc, CmsResource resource, long dateExpired) throws CmsDataAccessException { 9200 9201 resource.setDateExpired(dateExpired); 9202 if (resource.getState().isUnchanged()) { 9203 resource.setState(CmsResource.STATE_CHANGED); 9204 } 9205 getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_STRUCTURE, false); 9206 9207 // modify the last modified project reference 9208 getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_RESOURCE_PROJECT, false); 9209 // log 9210 log( 9211 dbc, 9212 new CmsLogEntry( 9213 dbc, 9214 resource.getStructureId(), 9215 CmsLogEntryType.RESOURCE_DATE_EXPIRED, 9216 new String[] {resource.getRootPath()}), 9217 false); 9218 9219 // clear the cache 9220 m_monitor.clearResourceCache(); 9221 9222 // fire the event 9223 Map<String, Object> data = new HashMap<String, Object>(2); 9224 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 9225 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_TIMEFRAME)); 9226 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 9227 } 9228 9229 /** 9230 * Changes the "last modified" timestamp of a resource.<p> 9231 * 9232 * @param dbc the current database context 9233 * @param resource the resource to touch 9234 * @param dateLastModified the new last modified date of the resource 9235 * 9236 * @throws CmsDataAccessException if something goes wrong 9237 * 9238 * @see CmsObject#setDateLastModified(String, long, boolean) 9239 * @see I_CmsResourceType#setDateLastModified(CmsObject, CmsSecurityManager, CmsResource, long, boolean) 9240 */ 9241 public void setDateLastModified(CmsDbContext dbc, CmsResource resource, long dateLastModified) 9242 throws CmsDataAccessException { 9243 9244 // modify the last modification date 9245 resource.setDateLastModified(dateLastModified); 9246 if (resource.getState().isUnchanged()) { 9247 resource.setState(CmsResource.STATE_CHANGED); 9248 } else if (resource.getState().isNew() && (resource.getSiblingCount() > 1)) { 9249 // in case of new resources with siblings make sure the state is correct 9250 resource.setState(CmsResource.STATE_CHANGED); 9251 } 9252 resource.setUserLastModified(dbc.currentUser().getId()); 9253 getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_RESOURCE, false); 9254 9255 log( 9256 dbc, 9257 new CmsLogEntry( 9258 dbc, 9259 resource.getStructureId(), 9260 CmsLogEntryType.RESOURCE_TOUCHED, 9261 new String[] {resource.getRootPath()}), 9262 false); 9263 9264 // clear the cache 9265 m_monitor.clearResourceCache(); 9266 9267 // fire the event 9268 Map<String, Object> data = new HashMap<String, Object>(2); 9269 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 9270 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_LASTMODIFIED)); 9271 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 9272 } 9273 9274 /** 9275 * Changes the "release" date of a resource.<p> 9276 * 9277 * @param dbc the current database context 9278 * @param resource the resource to touch 9279 * @param dateReleased the new release date of the resource 9280 * 9281 * @throws CmsDataAccessException if something goes wrong 9282 * 9283 * @see CmsObject#setDateReleased(String, long, boolean) 9284 * @see I_CmsResourceType#setDateReleased(CmsObject, CmsSecurityManager, CmsResource, long, boolean) 9285 */ 9286 public void setDateReleased(CmsDbContext dbc, CmsResource resource, long dateReleased) 9287 throws CmsDataAccessException { 9288 9289 // modify the last modification date 9290 resource.setDateReleased(dateReleased); 9291 if (resource.getState().isUnchanged()) { 9292 resource.setState(CmsResource.STATE_CHANGED); 9293 } 9294 getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_STRUCTURE, false); 9295 9296 // modify the last modified project reference 9297 getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_RESOURCE_PROJECT, false); 9298 // log it 9299 log( 9300 dbc, 9301 new CmsLogEntry( 9302 dbc, 9303 resource.getStructureId(), 9304 CmsLogEntryType.RESOURCE_DATE_RELEASED, 9305 new String[] {resource.getRootPath()}), 9306 false); 9307 9308 // clear the cache 9309 m_monitor.clearResourceCache(); 9310 9311 // fire the event 9312 Map<String, Object> data = new HashMap<String, Object>(2); 9313 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 9314 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_TIMEFRAME)); 9315 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 9316 } 9317 9318 /** 9319 * Sets a new parent group for an already existing group.<p> 9320 * 9321 * @param dbc the current database context 9322 * @param groupName the name of the group that should be written 9323 * @param parentGroupName the name of the parent group to set, 9324 * or <code>null</code> if the parent 9325 * group should be deleted. 9326 * 9327 * @throws CmsException if operation was not successful 9328 * @throws CmsDataAccessException if the group with <code>groupName</code> could not be read from VFS 9329 */ 9330 public void setParentGroup(CmsDbContext dbc, String groupName, String parentGroupName) 9331 throws CmsException, CmsDataAccessException { 9332 9333 CmsGroup group = readGroup(dbc, groupName); 9334 CmsUUID parentGroupId = CmsUUID.getNullUUID(); 9335 9336 // if the group exists, use its id, else set to unknown. 9337 if (parentGroupName != null) { 9338 parentGroupId = readGroup(dbc, parentGroupName).getId(); 9339 } 9340 9341 group.setParentId(parentGroupId); 9342 9343 // write the changes to the cms 9344 writeGroup(dbc, group); 9345 } 9346 9347 /** 9348 * Sets the password for a user.<p> 9349 * 9350 * @param dbc the current database context 9351 * @param username the name of the user 9352 * @param newPassword the new password 9353 * 9354 * @throws CmsException if operation was not successful 9355 * @throws CmsIllegalArgumentException if the user with the <code>username</code> was not found 9356 */ 9357 public void setPassword(CmsDbContext dbc, String username, String newPassword) 9358 throws CmsException, CmsIllegalArgumentException { 9359 9360 if (dbc.getRequestContext().getAttribute(CmsUserDriver.REQ_ATTR_DONT_DIGEST_PASSWORD) == null) { 9361 validatePassword(newPassword); 9362 } 9363 9364 // read the user as a system user to verify that the specified old password is correct 9365 CmsUser user = getUserDriver(dbc).readUser(dbc, username); 9366 // only continue if not found and read user from web might succeed 9367 getUserDriver(dbc).writePassword(dbc, username, null, newPassword); 9368 user.getAdditionalInfo().put( 9369 CmsUserSettings.ADDITIONAL_INFO_LAST_PASSWORD_CHANGE, 9370 "" + System.currentTimeMillis()); 9371 getUserDriver(dbc).writeUser(dbc, user); 9372 9373 // fire user modified event 9374 Map<String, Object> eventData = new HashMap<String, Object>(); 9375 eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); 9376 eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_RESET_PASSWORD); 9377 eventData.put( 9378 I_CmsEventListener.KEY_USER_CHANGES, 9379 Integer.valueOf(CmsUser.FLAG_CORE_DATA | CmsUser.FLAG_CORE_DATA)); 9380 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); 9381 } 9382 9383 /** 9384 * Marks a subscribed resource as deleted.<p> 9385 * 9386 * @param dbc the database context 9387 * @param poolName the name of the database pool to use 9388 * @param resource the subscribed resource to mark as deleted 9389 * 9390 * @throws CmsException if something goes wrong 9391 */ 9392 public void setSubscribedResourceAsDeleted(CmsDbContext dbc, String poolName, CmsResource resource) 9393 throws CmsException { 9394 9395 getSubscriptionDriver().setSubscribedResourceAsDeleted(dbc, poolName, resource); 9396 } 9397 9398 /** 9399 * Moves an user to the given organizational unit.<p> 9400 * 9401 * @param dbc the current db context 9402 * @param orgUnit the organizational unit to add the resource to 9403 * @param user the user that is to be moved to the organizational unit 9404 * 9405 * @throws CmsException if something goes wrong 9406 * 9407 * @see org.opencms.security.CmsOrgUnitManager#setUsersOrganizationalUnit(CmsObject, String, String) 9408 */ 9409 public void setUsersOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, CmsUser user) 9410 throws CmsException { 9411 9412 if (!getGroupsOfUser(dbc, user.getName(), false).isEmpty()) { 9413 throw new CmsDbConsistencyException( 9414 Messages.get().container(Messages.ERR_ORGUNIT_MOVE_USER_2, orgUnit.getName(), user.getName())); 9415 } 9416 9417 // move the principal 9418 getUserDriver(dbc).setUsersOrganizationalUnit(dbc, orgUnit, user); 9419 // remove the principal from cache 9420 m_monitor.clearUserCache(user); 9421 9422 if (!dbc.getProjectId().isNullUUID()) { 9423 // user modified event is not needed 9424 return; 9425 } 9426 // fire user modified event 9427 Map<String, Object> eventData = new HashMap<String, Object>(); 9428 eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); 9429 eventData.put(I_CmsEventListener.KEY_OU_NAME, user.getOuFqn()); 9430 eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_SET_OU); 9431 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); 9432 } 9433 9434 /** 9435 * Subscribes the user or group to the resource.<p> 9436 * 9437 * @param dbc the database context 9438 * @param poolName the name of the database pool to use 9439 * @param principal the principal that subscribes to the resource 9440 * @param resource the resource to subscribe to 9441 * 9442 * @throws CmsException if something goes wrong 9443 */ 9444 public void subscribeResourceFor(CmsDbContext dbc, String poolName, CmsPrincipal principal, CmsResource resource) 9445 throws CmsException { 9446 9447 getSubscriptionDriver().subscribeResourceFor(dbc, poolName, principal, resource); 9448 } 9449 9450 /** 9451 * Undelete the resource.<p> 9452 * 9453 * @param dbc the current database context 9454 * @param resource the name of the resource to apply this operation to 9455 * 9456 * @throws CmsException if something goes wrong 9457 * 9458 * @see CmsObject#undeleteResource(String, boolean) 9459 * @see I_CmsResourceType#undelete(CmsObject, CmsSecurityManager, CmsResource, boolean) 9460 */ 9461 public void undelete(CmsDbContext dbc, CmsResource resource) throws CmsException { 9462 9463 if (!resource.getState().isDeleted()) { 9464 throw new CmsVfsException( 9465 Messages.get().container( 9466 Messages.ERR_UNDELETE_FOR_RESOURCE_DELETED_1, 9467 dbc.removeSiteRoot(resource.getRootPath()))); 9468 } 9469 9470 // set the state to changed 9471 resource.setState(CmsResourceState.STATE_CHANGED); 9472 // perform the changes 9473 updateState(dbc, resource, false); 9474 // log it 9475 log( 9476 dbc, 9477 new CmsLogEntry( 9478 dbc, 9479 resource.getStructureId(), 9480 CmsLogEntryType.RESOURCE_UNDELETED, 9481 new String[] {resource.getRootPath()}), 9482 false); 9483 // clear the cache 9484 m_monitor.clearResourceCache(); 9485 9486 // fire change event 9487 Map<String, Object> data = new HashMap<String, Object>(2); 9488 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 9489 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_RESOURCE)); 9490 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 9491 } 9492 9493 /** 9494 * Undos all changes in the resource by restoring the version from the 9495 * online project to the current offline project.<p> 9496 * 9497 * @param dbc the current database context 9498 * @param resource the name of the resource to apply this operation to 9499 * @param mode the undo mode, one of the <code>{@link org.opencms.file.CmsResource.CmsResourceUndoMode}#UNDO_XXX</code> constants 9500 * please note that the recursive flag is ignored at this level 9501 * 9502 * @throws CmsException if something goes wrong 9503 * 9504 * @see CmsObject#undoChanges(String, CmsResource.CmsResourceUndoMode) 9505 * @see I_CmsResourceType#undoChanges(CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceUndoMode) 9506 */ 9507 public void undoChanges(CmsDbContext dbc, CmsResource resource, CmsResource.CmsResourceUndoMode mode) 9508 throws CmsException { 9509 9510 if (resource.getState().isNew()) { 9511 // undo changes is impossible on a new resource 9512 throw new CmsVfsException(Messages.get().container(Messages.ERR_UNDO_CHANGES_FOR_RESOURCE_NEW_0)); 9513 } 9514 9515 // we need this for later use 9516 CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); 9517 // read the resource from the online project 9518 CmsResource onlineResource = getVfsDriver( 9519 dbc).readResource(dbc, CmsProject.ONLINE_PROJECT_ID, resource.getStructureId(), true); 9520 9521 CmsResource onlineResourceByPath = null; 9522 try { 9523 // this is needed to figure out if a moved resource overwrote a deleted one 9524 onlineResourceByPath = getVfsDriver( 9525 dbc).readResource(dbc, CmsProject.ONLINE_PROJECT_ID, resource.getRootPath(), true); 9526 9527 // force undo move operation if needed 9528 if (!mode.isUndoMove() && !onlineResourceByPath.getRootPath().equals(onlineResource.getRootPath())) { 9529 mode = mode.includeMove(); 9530 } 9531 } catch (Exception e) { 9532 // ok 9533 } 9534 9535 boolean moved = !onlineResource.getRootPath().equals(resource.getRootPath()); 9536 // undo move operation if required 9537 if (moved && mode.isUndoMove()) { 9538 moveResource(dbc, resource, onlineResource.getRootPath(), true); 9539 if ((onlineResourceByPath != null) 9540 && !onlineResourceByPath.getRootPath().equals(onlineResource.getRootPath())) { 9541 // was moved over deleted, so the deleted file has to be undone 9542 undoContentChanges(dbc, onlineProject, null, onlineResourceByPath, CmsResource.STATE_UNCHANGED, true); 9543 } 9544 } 9545 // undo content changes 9546 CmsResourceState newState = CmsResource.STATE_UNCHANGED; 9547 if (moved && !mode.isUndoMove()) { 9548 newState = CmsResource.STATE_CHANGED; 9549 } 9550 undoContentChanges(dbc, onlineProject, resource, onlineResource, newState, moved && mode.isUndoMove()); 9551 // because undoContentChanges deletes the offline resource internally, we have 9552 // to write an entry to the log table to prevent the resource from appearing in the 9553 // user's publish list. 9554 log( 9555 dbc, 9556 new CmsLogEntry( 9557 dbc, 9558 resource.getStructureId(), 9559 CmsLogEntryType.RESOURCE_CHANGES_UNDONE, 9560 new String[] {resource.getRootPath()}), 9561 true); 9562 9563 } 9564 9565 /** 9566 * Unlocks all resources in the given project.<p> 9567 * 9568 * @param project the project to unlock the resources in 9569 */ 9570 public void unlockProject(CmsProject project) { 9571 9572 // unlock all resources in the project 9573 m_lockManager.removeResourcesInProject(project.getUuid(), false); 9574 m_monitor.clearResourceCache(); 9575 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROJECT, CmsMemoryMonitor.CacheType.PERMISSION); 9576 } 9577 9578 /** 9579 * Unlocks a resource.<p> 9580 * 9581 * @param dbc the current database context 9582 * @param resource the resource to unlock 9583 * @param force <code>true</code>, if a resource is forced to get unlocked, no matter by which user and in which project the resource is currently locked 9584 * @param removeSystemLock <code>true</code>, if you also want to remove system locks 9585 * 9586 * @throws CmsException if something goes wrong 9587 * 9588 * @see CmsObject#unlockResource(String) 9589 * @see I_CmsResourceType#unlockResource(CmsObject, CmsSecurityManager, CmsResource) 9590 */ 9591 public void unlockResource(CmsDbContext dbc, CmsResource resource, boolean force, boolean removeSystemLock) 9592 throws CmsException { 9593 9594 // update the resource cache 9595 m_monitor.clearResourceCache(); 9596 9597 // now update lock status 9598 m_lockManager.removeResource(dbc, resource, force, removeSystemLock); 9599 9600 // we must also clear the permission cache 9601 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PERMISSION); 9602 9603 // fire resource modification event 9604 Map<String, Object> data = new HashMap<String, Object>(2); 9605 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 9606 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(NOTHING_CHANGED)); 9607 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 9608 } 9609 9610 /** 9611 * Unsubscribes all deleted resources that were deleted before the specified time stamp.<p> 9612 * 9613 * @param dbc the database context 9614 * @param poolName the name of the database pool to use 9615 * @param deletedTo the time stamp to which the resources have been deleted 9616 * 9617 * @throws CmsException if something goes wrong 9618 */ 9619 public void unsubscribeAllDeletedResources(CmsDbContext dbc, String poolName, long deletedTo) throws CmsException { 9620 9621 getSubscriptionDriver().unsubscribeAllDeletedResources(dbc, poolName, deletedTo); 9622 } 9623 9624 /** 9625 * Unsubscribes the principal from all resources.<p> 9626 * 9627 * @param dbc the database context 9628 * @param poolName the name of the database pool to use 9629 * @param principal the principal that unsubscribes from all resources 9630 * 9631 * @throws CmsException if something goes wrong 9632 */ 9633 public void unsubscribeAllResourcesFor(CmsDbContext dbc, String poolName, CmsPrincipal principal) 9634 throws CmsException { 9635 9636 getSubscriptionDriver().unsubscribeAllResourcesFor(dbc, poolName, principal); 9637 9638 } 9639 9640 /** 9641 * Unsubscribes the principal from the resource.<p> 9642 * 9643 * @param dbc the database context 9644 * @param poolName the name of the database pool to use 9645 * @param principal the principal that unsubscribes from the resource 9646 * @param resource the resource to unsubscribe from 9647 * 9648 * @throws CmsException if something goes wrong 9649 */ 9650 public void unsubscribeResourceFor(CmsDbContext dbc, String poolName, CmsPrincipal principal, CmsResource resource) 9651 throws CmsException { 9652 9653 getSubscriptionDriver().unsubscribeResourceFor(dbc, poolName, principal, resource); 9654 } 9655 9656 /** 9657 * Unsubscribes all groups and users from the resource.<p> 9658 * 9659 * @param dbc the database context 9660 * @param poolName the name of the database pool to use 9661 * @param resource the resource to unsubscribe all groups and users from 9662 * 9663 * @throws CmsException if something goes wrong 9664 */ 9665 public void unsubscribeResourceForAll(CmsDbContext dbc, String poolName, CmsResource resource) throws CmsException { 9666 9667 getSubscriptionDriver().unsubscribeResourceForAll(dbc, poolName, resource); 9668 } 9669 9670 /** 9671 * Update the export points.<p> 9672 * 9673 * All files and folders "inside" an export point are written.<p> 9674 * 9675 * @param dbc the current database context 9676 */ 9677 public void updateExportPoints(CmsDbContext dbc) { 9678 9679 try { 9680 // read the export points and return immediately if there are no export points at all 9681 Set<CmsExportPoint> exportPoints = new HashSet<CmsExportPoint>(); 9682 exportPoints.addAll(OpenCms.getExportPoints()); 9683 exportPoints.addAll(OpenCms.getModuleManager().getExportPoints()); 9684 if (exportPoints.size() == 0) { 9685 if (LOG.isWarnEnabled()) { 9686 LOG.warn(Messages.get().getBundle().key(Messages.LOG_NO_EXPORT_POINTS_CONFIGURED_0)); 9687 } 9688 return; 9689 } 9690 9691 // create the driver to write the export points 9692 I_CmsExportPointDriver exportPointDriver = OpenCms.getImportExportManager().createExportPointDriver( 9693 exportPoints); 9694 9695 // the export point hash table contains RFS export paths keyed by their internal VFS paths 9696 Iterator<String> i = exportPointDriver.getExportPointPaths().iterator(); 9697 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 9698 while (i.hasNext()) { 9699 String currentExportPoint = i.next(); 9700 9701 // print some report messages 9702 if (LOG.isInfoEnabled()) { 9703 LOG.info(Messages.get().getBundle().key(Messages.LOG_WRITE_EXPORT_POINT_1, currentExportPoint)); 9704 } 9705 9706 try { 9707 CmsResourceFilter filter = CmsResourceFilter.DEFAULT; 9708 List<CmsResource> resources = vfsDriver.readResourceTree( 9709 dbc, 9710 CmsProject.ONLINE_PROJECT_ID, 9711 currentExportPoint, 9712 filter.getType(), 9713 filter.getState(), 9714 filter.getModifiedAfter(), 9715 filter.getModifiedBefore(), 9716 filter.getReleaseAfter(), 9717 filter.getReleaseBefore(), 9718 filter.getExpireAfter(), 9719 filter.getExpireBefore(), 9720 CmsDriverManager.READMODE_INCLUDE_TREE 9721 | (filter.excludeType() ? CmsDriverManager.READMODE_EXCLUDE_TYPE : 0) 9722 | (filter.excludeState() ? CmsDriverManager.READMODE_EXCLUDE_STATE : 0)); 9723 9724 Iterator<CmsResource> j = resources.iterator(); 9725 while (j.hasNext()) { 9726 CmsResource currentResource = j.next(); 9727 9728 if (currentResource.isFolder()) { 9729 // export the folder 9730 exportPointDriver.createFolder(currentResource.getRootPath(), currentExportPoint); 9731 } else { 9732 // try to create the exportpoint folder 9733 exportPointDriver.createFolder(currentExportPoint, currentExportPoint); 9734 byte[] onlineContent = vfsDriver.readContent( 9735 dbc, 9736 CmsProject.ONLINE_PROJECT_ID, 9737 currentResource.getResourceId()); 9738 // export the file content online 9739 exportPointDriver.writeFile( 9740 currentResource.getRootPath(), 9741 currentExportPoint, 9742 onlineContent); 9743 } 9744 } 9745 } catch (CmsException e) { 9746 // there might exist export points without corresponding resources in the VFS 9747 // -> ignore exceptions which are not "resource not found" exception quiet here 9748 if (e instanceof CmsVfsResourceNotFoundException) { 9749 if (LOG.isErrorEnabled()) { 9750 LOG.error(Messages.get().getBundle().key(Messages.LOG_UPDATE_EXORT_POINTS_ERROR_0), e); 9751 } 9752 } 9753 } 9754 } 9755 } catch (Exception e) { 9756 if (LOG.isErrorEnabled()) { 9757 LOG.error(Messages.get().getBundle().key(Messages.LOG_UPDATE_EXORT_POINTS_ERROR_0), e); 9758 } 9759 } 9760 } 9761 9762 /** 9763 * Updates the last login date on the given user to the current time.<p> 9764 * 9765 * @param dbc the current database context 9766 * @param user the user to be updated 9767 * 9768 * @throws CmsException if operation was not successful 9769 */ 9770 public void updateLastLoginDate(CmsDbContext dbc, CmsUser user) throws CmsException { 9771 9772 m_monitor.clearUserCache(user); 9773 // set the last login time to the current time 9774 user.setLastlogin(System.currentTimeMillis()); 9775 dbc.setAttribute(ATTRIBUTE_LOGIN, user.getName()); 9776 getUserDriver(dbc).writeUser(dbc, user); 9777 // update cache 9778 m_monitor.cacheUser(user); 9779 9780 // invalidate all user dependent caches 9781 m_monitor.flushCache( 9782 CmsMemoryMonitor.CacheType.ACL, 9783 CmsMemoryMonitor.CacheType.GROUP, 9784 CmsMemoryMonitor.CacheType.ORG_UNIT, 9785 CmsMemoryMonitor.CacheType.USER_LIST, 9786 CmsMemoryMonitor.CacheType.PERMISSION, 9787 CmsMemoryMonitor.CacheType.RESOURCE_LIST); 9788 9789 // fire user modified event 9790 Map<String, Object> eventData = new HashMap<String, Object>(); 9791 eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); 9792 eventData.put(I_CmsEventListener.KEY_USER_NAME, user.getName()); 9793 eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_WRITE_USER); 9794 eventData.put(I_CmsEventListener.KEY_USER_CHANGES, Integer.valueOf(CmsUser.FLAG_LAST_LOGIN)); 9795 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); 9796 } 9797 9798 /** 9799 * Logs everything that has not been written to DB jet.<p> 9800 * 9801 * @param dbc the current db context 9802 * 9803 * @throws CmsDataAccessException if something goes wrong 9804 */ 9805 public void updateLog(CmsDbContext dbc) throws CmsDataAccessException { 9806 9807 synchronized (m_publishListUpdateLock) { 9808 9809 if (m_log.isEmpty()) { 9810 return; 9811 } 9812 9813 List<CmsLogEntry> log = new ArrayList<CmsLogEntry>(m_log); 9814 m_log.clear(); 9815 String logTableEnabledStr = (String)OpenCms.getRuntimeProperty(PARAM_LOG_TABLE_ENABLED); 9816 if (Boolean.parseBoolean(logTableEnabledStr)) { // defaults to 'false' if value not set 9817 m_projectDriver.log(dbc, log); 9818 } 9819 A_CmsLogPublishListConverter converter = null; 9820 switch (OpenCms.getPublishManager().getPublishListRemoveMode()) { 9821 case currentUser: 9822 converter = new CmsLogPublishListConverterCurrentUser(); 9823 break; 9824 case allUsers: 9825 default: 9826 converter = new CmsLogPublishListConverterAllUsers(); 9827 break; 9828 } 9829 for (CmsLogEntry entry : log) { 9830 converter.add(entry); 9831 } 9832 converter.writeChangesToDatabase(dbc, m_projectDriver); 9833 } 9834 } 9835 9836 /** 9837 * Updates/Creates the given relations for the given resource.<p> 9838 * 9839 * @param dbc the db context 9840 * @param resource the resource to update the relations for 9841 * @param links the links to consider for updating 9842 * 9843 * @throws CmsException if something goes wrong 9844 * 9845 * @see CmsSecurityManager#updateRelationsForResource(CmsRequestContext, CmsResource, List) 9846 */ 9847 public void updateRelationsForResource(CmsDbContext dbc, CmsResource resource, List<CmsLink> links) 9848 throws CmsException { 9849 9850 deleteRelationsWithSiblings(dbc, resource); 9851 9852 // build the links again only if needed 9853 if ((links == null) || links.isEmpty()) { 9854 return; 9855 } 9856 // the set of written relations 9857 Set<CmsRelation> writtenRelations = new HashSet<CmsRelation>(); 9858 9859 // create new relation information 9860 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 9861 Iterator<CmsLink> itLinks = links.iterator(); 9862 while (itLinks.hasNext()) { 9863 CmsLink link = itLinks.next(); 9864 if (link.isInternal()) { // only update internal links 9865 if (CmsStringUtil.isEmptyOrWhitespaceOnly(link.getTarget())) { 9866 // only an anchor 9867 continue; 9868 } 9869 CmsUUID targetId = link.getStructureId(); 9870 String destPath = link.getTarget(); 9871 9872 if (targetId != null) { 9873 // the link target may not be a VFS path even if the link id is a structure id, 9874 // so if possible, we read the resource for the id and set the relation target to its 9875 // real root path. 9876 try { 9877 CmsResource destRes = readResource(dbc, targetId, CmsResourceFilter.ALL); 9878 destPath = destRes.getRootPath(); 9879 } catch (CmsVfsResourceNotFoundException e) { 9880 // ignore 9881 } 9882 } 9883 9884 CmsRelation originalRelation = new CmsRelation( 9885 resource.getStructureId(), 9886 resource.getRootPath(), 9887 link.getStructureId(), 9888 destPath, 9889 link.getType()); 9890 9891 // do not write twice the same relation 9892 if (writtenRelations.contains(originalRelation)) { 9893 continue; 9894 } 9895 writtenRelations.add(originalRelation); 9896 9897 // TODO: it would be good to have the link locale to make the relation just to the right sibling 9898 // create the relations in content for all siblings 9899 Iterator<CmsResource> itSiblings = readSiblings(dbc, resource, CmsResourceFilter.ALL).iterator(); 9900 while (itSiblings.hasNext()) { 9901 CmsResource sibling = itSiblings.next(); 9902 CmsRelation relation = new CmsRelation( 9903 sibling.getStructureId(), 9904 sibling.getRootPath(), 9905 originalRelation.getTargetId(), 9906 originalRelation.getTargetPath(), 9907 link.getType()); 9908 vfsDriver.createRelation(dbc, dbc.currentProject().getUuid(), relation); 9909 } 9910 } 9911 } 9912 } 9913 9914 /** 9915 * Returns <code>true</code> if a user is member of the given group.<p> 9916 * 9917 * @param dbc the current database context 9918 * @param username the name of the user to check 9919 * @param groupname the name of the group to check 9920 * @param readRoles if to read roles or groups 9921 * 9922 * @return <code>true</code>, if the user is in the group, <code>false</code> otherwise 9923 * 9924 * @throws CmsException if something goes wrong 9925 */ 9926 public boolean userInGroup(CmsDbContext dbc, String username, String groupname, boolean readRoles) 9927 throws CmsException { 9928 9929 List<CmsGroup> groups = getGroupsOfUser(dbc, username, readRoles); 9930 for (int i = 0; i < groups.size(); i++) { 9931 CmsGroup group = groups.get(i); 9932 if (groupname.equals(group.getName()) || groupname.substring(1).equals(group.getName())) { 9933 return true; 9934 } 9935 } 9936 return false; 9937 } 9938 9939 /** 9940 * This method checks if a new password follows the rules for 9941 * new passwords, which are defined by a Class implementing the 9942 * <code>{@link org.opencms.security.I_CmsPasswordHandler}</code> 9943 * interface and configured in the opencms.properties file.<p> 9944 * 9945 * If this method throws no exception the password is valid.<p> 9946 * 9947 * @param password the new password that has to be checked 9948 * 9949 * @throws CmsSecurityException if the password is not valid 9950 */ 9951 public void validatePassword(String password) throws CmsSecurityException { 9952 9953 OpenCms.getPasswordHandler().validatePassword(password); 9954 } 9955 9956 /** 9957 * Validates the relations for the given resources.<p> 9958 * 9959 * @param dbc the database context 9960 * @param publishList the resources to validate during publishing 9961 * @param report a report to write the messages to 9962 * 9963 * @return a map with lists of invalid links 9964 * (<code>{@link org.opencms.relations.CmsRelation}}</code> objects) 9965 * keyed by root paths 9966 * 9967 * @throws Exception if something goes wrong 9968 */ 9969 public Map<String, List<CmsRelation>> validateRelations( 9970 CmsDbContext dbc, 9971 CmsPublishList publishList, 9972 I_CmsReport report) 9973 throws Exception { 9974 9975 return m_htmlLinkValidator.validateResources(dbc, publishList, report); 9976 } 9977 9978 /** 9979 * Writes an access control entries to a given resource.<p> 9980 * 9981 * @param dbc the current database context 9982 * @param resource the resource 9983 * @param ace the entry to write 9984 * 9985 * @throws CmsException if something goes wrong 9986 */ 9987 public void writeAccessControlEntry(CmsDbContext dbc, CmsResource resource, CmsAccessControlEntry ace) 9988 throws CmsException { 9989 9990 // write the new ace 9991 getUserDriver(dbc).writeAccessControlEntry(dbc, dbc.currentProject(), ace); 9992 9993 // log it 9994 log( 9995 dbc, 9996 new CmsLogEntry( 9997 dbc, 9998 resource.getStructureId(), 9999 CmsLogEntryType.RESOURCE_PERMISSIONS, 10000 new String[] {resource.getRootPath()}), 10001 false); 10002 10003 // update the "last modified" information 10004 setDateLastModified(dbc, resource, resource.getDateLastModified()); 10005 10006 // clear the cache 10007 m_monitor.clearAccessControlListCache(); 10008 10009 // fire a resource modification event 10010 Map<String, Object> data = new HashMap<String, Object>(2); 10011 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 10012 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_ACCESSCONTROL)); 10013 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 10014 } 10015 10016 /** 10017 * Writes all export points into the file system for the publish task 10018 * specified by trhe given publish history ID.<p> 10019 * 10020 * @param dbc the current database context 10021 * @param report an I_CmsReport instance to print output message, or null to write messages to the log file 10022 * @param publishHistoryId ID to identify the publish task in the publish history 10023 */ 10024 public void writeExportPoints(CmsDbContext dbc, I_CmsReport report, CmsUUID publishHistoryId) { 10025 10026 boolean printReportHeaders = false; 10027 List<CmsPublishedResource> publishedResources = null; 10028 try { 10029 // read the "published resources" for the specified publish history ID 10030 publishedResources = getProjectDriver(dbc).readPublishedResources(dbc, publishHistoryId); 10031 } catch (CmsException e) { 10032 if (LOG.isErrorEnabled()) { 10033 LOG.error( 10034 Messages.get().getBundle().key(Messages.ERR_READ_PUBLISHED_RESOURCES_FOR_ID_1, publishHistoryId), 10035 e); 10036 } 10037 } 10038 if ((publishedResources == null) || publishedResources.isEmpty()) { 10039 if (LOG.isWarnEnabled()) { 10040 LOG.warn(Messages.get().getBundle().key(Messages.LOG_EMPTY_PUBLISH_HISTORY_1, publishHistoryId)); 10041 } 10042 return; 10043 } 10044 10045 // read the export points and return immediately if there are no export points at all 10046 Set<CmsExportPoint> exportPoints = new HashSet<CmsExportPoint>(); 10047 exportPoints.addAll(OpenCms.getExportPoints()); 10048 exportPoints.addAll(OpenCms.getModuleManager().getExportPoints()); 10049 if (exportPoints.size() == 0) { 10050 if (LOG.isWarnEnabled()) { 10051 LOG.warn(Messages.get().getBundle().key(Messages.LOG_NO_EXPORT_POINTS_CONFIGURED_0)); 10052 } 10053 return; 10054 } 10055 10056 // create the driver to write the export points 10057 I_CmsExportPointDriver exportPointDriver = OpenCms.getImportExportManager().createExportPointDriver( 10058 exportPoints); 10059 10060 // the report may be null if the export point write was started by an event 10061 if (report == null) { 10062 if (dbc.getRequestContext() != null) { 10063 report = new CmsLogReport(dbc.getRequestContext().getLocale(), getClass()); 10064 } else { 10065 report = new CmsLogReport(CmsLocaleManager.getDefaultLocale(), getClass()); 10066 } 10067 } 10068 10069 // iterate over all published resources to export them 10070 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 10071 Iterator<CmsPublishedResource> i = publishedResources.iterator(); 10072 while (i.hasNext()) { 10073 CmsPublishedResource currentPublishedResource = i.next(); 10074 String currentExportPoint = exportPointDriver.getExportPoint(currentPublishedResource.getRootPath()); 10075 10076 if (currentExportPoint != null) { 10077 if (!printReportHeaders) { 10078 report.println( 10079 Messages.get().container(Messages.RPT_EXPORT_POINTS_WRITE_BEGIN_0), 10080 I_CmsReport.FORMAT_HEADLINE); 10081 printReportHeaders = true; 10082 } 10083 10084 // print report message 10085 if (currentPublishedResource.getState().isDeleted()) { 10086 report.print( 10087 Messages.get().container(Messages.RPT_EXPORT_POINTS_DELETE_0), 10088 I_CmsReport.FORMAT_NOTE); 10089 } else { 10090 report.print(Messages.get().container(Messages.RPT_EXPORT_POINTS_WRITE_0), I_CmsReport.FORMAT_NOTE); 10091 } 10092 report.print( 10093 org.opencms.report.Messages.get().container( 10094 org.opencms.report.Messages.RPT_ARGUMENT_1, 10095 currentPublishedResource.getRootPath())); 10096 report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); 10097 10098 if (currentPublishedResource.isFolder()) { 10099 // export the folder 10100 if (currentPublishedResource.getState().isDeleted()) { 10101 exportPointDriver.deleteResource(currentPublishedResource.getRootPath(), currentExportPoint); 10102 } else { 10103 exportPointDriver.createFolder(currentPublishedResource.getRootPath(), currentExportPoint); 10104 } 10105 report.println( 10106 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), 10107 I_CmsReport.FORMAT_OK); 10108 } else { 10109 // export the file 10110 try { 10111 if (currentPublishedResource.getState().isDeleted()) { 10112 exportPointDriver.deleteResource( 10113 currentPublishedResource.getRootPath(), 10114 currentExportPoint); 10115 } else { 10116 // read the file content online 10117 byte[] onlineContent = vfsDriver.readContent( 10118 dbc, 10119 CmsProject.ONLINE_PROJECT_ID, 10120 currentPublishedResource.getResourceId()); 10121 exportPointDriver.writeFile( 10122 currentPublishedResource.getRootPath(), 10123 currentExportPoint, 10124 onlineContent); 10125 } 10126 report.println( 10127 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), 10128 I_CmsReport.FORMAT_OK); 10129 } catch (CmsException e) { 10130 if (LOG.isErrorEnabled()) { 10131 LOG.error( 10132 Messages.get().getBundle().key( 10133 Messages.LOG_WRITE_EXPORT_POINT_ERROR_1, 10134 currentPublishedResource.getRootPath()), 10135 e); 10136 } 10137 report.println( 10138 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_FAILED_0), 10139 I_CmsReport.FORMAT_ERROR); 10140 } 10141 } 10142 } 10143 } 10144 if (printReportHeaders) { 10145 report.println( 10146 Messages.get().container(Messages.RPT_EXPORT_POINTS_WRITE_END_0), 10147 I_CmsReport.FORMAT_HEADLINE); 10148 } 10149 } 10150 10151 /** 10152 * Writes a resource to the OpenCms VFS, including it's content.<p> 10153 * 10154 * Applies only to resources of type <code>{@link CmsFile}</code> 10155 * i.e. resources that have a binary content attached.<p> 10156 * 10157 * Certain resource types might apply content validation or transformation rules 10158 * before the resource is actually written to the VFS. The returned result 10159 * might therefore be a modified version from the provided original.<p> 10160 * 10161 * @param dbc the current database context 10162 * @param resource the resource to apply this operation to 10163 * 10164 * @return the written resource (may have been modified) 10165 * 10166 * @throws CmsException if something goes wrong 10167 * 10168 * @see CmsObject#writeFile(CmsFile) 10169 * @see I_CmsResourceType#writeFile(CmsObject, CmsSecurityManager, CmsFile) 10170 */ 10171 public CmsFile writeFile(CmsDbContext dbc, CmsFile resource) throws CmsException { 10172 10173 resource.setUserLastModified(dbc.currentUser().getId()); 10174 resource.setContents(resource.getContents()); // to be sure the content date is updated 10175 10176 getVfsDriver(dbc).writeResource(dbc, dbc.currentProject().getUuid(), resource, UPDATE_RESOURCE_STATE); 10177 10178 byte[] contents = resource.getContents(); 10179 getVfsDriver(dbc).writeContent(dbc, resource.getResourceId(), contents); 10180 // log it 10181 log( 10182 dbc, 10183 new CmsLogEntry( 10184 dbc, 10185 resource.getStructureId(), 10186 CmsLogEntryType.RESOURCE_CONTENT_MODIFIED, 10187 new String[] {resource.getRootPath()}), 10188 false); 10189 10190 // read the file back from db 10191 resource = new CmsFile(readResource(dbc, resource.getStructureId(), CmsResourceFilter.ALL)); 10192 resource.setContents(contents); 10193 10194 deleteRelationsWithSiblings(dbc, resource); 10195 10196 // update the cache 10197 m_monitor.clearResourceCache(); 10198 10199 Map<String, Object> data = new HashMap<String, Object>(2); 10200 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 10201 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_CONTENT)); 10202 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 10203 10204 return resource; 10205 } 10206 10207 /** 10208 * Writes an already existing group.<p> 10209 * 10210 * The group id has to be a valid OpenCms group id.<br> 10211 * 10212 * The group with the given id will be completely overridden 10213 * by the given data.<p> 10214 * 10215 * @param dbc the current database context 10216 * @param group the group that should be written 10217 * 10218 * @throws CmsException if operation was not successful 10219 */ 10220 public void writeGroup(CmsDbContext dbc, CmsGroup group) throws CmsException { 10221 10222 CmsGroup oldGroup = readGroup(dbc, group.getName()); 10223 m_monitor.uncacheGroup(oldGroup); 10224 getUserDriver(dbc).writeGroup(dbc, group); 10225 m_monitor.cacheGroup(group); 10226 10227 if (!dbc.getProjectId().isNullUUID()) { 10228 // group modified event is not needed 10229 return; 10230 } 10231 // fire group modified event 10232 Map<String, Object> eventData = new HashMap<String, Object>(); 10233 eventData.put(I_CmsEventListener.KEY_GROUP_ID, group.getId().toString()); 10234 eventData.put(I_CmsEventListener.KEY_GROUP_NAME, oldGroup.getName()); 10235 eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_GROUP_MODIFIED_ACTION_WRITE); 10236 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_GROUP_MODIFIED, eventData)); 10237 } 10238 10239 /** 10240 * Creates an historical entry of the current project.<p> 10241 * 10242 * @param dbc the current database context 10243 * @param publishTag the version 10244 * @param publishDate the date of publishing 10245 * 10246 * @throws CmsDataAccessException if operation was not successful 10247 */ 10248 public void writeHistoryProject(CmsDbContext dbc, int publishTag, long publishDate) throws CmsDataAccessException { 10249 10250 getHistoryDriver(dbc).writeProject(dbc, publishTag, publishDate); 10251 } 10252 10253 /** 10254 * Writes the locks that are currently stored in-memory to the database to allow restoring them 10255 * in future server startups.<p> 10256 * 10257 * This overwrites the locks previously stored in the underlying database table.<p> 10258 * 10259 * @param dbc the current database context 10260 * 10261 * @throws CmsException if something goes wrong 10262 */ 10263 public void writeLocks(CmsDbContext dbc) throws CmsException { 10264 10265 m_lockManager.writeLocks(dbc); 10266 } 10267 10268 /** 10269 * Writes an already existing organizational unit.<p> 10270 * 10271 * The organizational unit id has to be a valid OpenCms organizational unit id.<br> 10272 * 10273 * The organizational unit with the given id will be completely overridden 10274 * by the given data.<p> 10275 * 10276 * @param dbc the current db context 10277 * @param organizationalUnit the organizational unit that should be written 10278 * 10279 * @throws CmsException if operation was not successful 10280 * 10281 * @see org.opencms.security.CmsOrgUnitManager#writeOrganizationalUnit(CmsObject, CmsOrganizationalUnit) 10282 */ 10283 public void writeOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit organizationalUnit) 10284 throws CmsException { 10285 10286 m_monitor.uncacheOrgUnit(organizationalUnit); 10287 getUserDriver(dbc).writeOrganizationalUnit(dbc, organizationalUnit); 10288 10289 // create a publish list for the 'virtual' publish event 10290 CmsResource ouRes = readResource(dbc, organizationalUnit.getId(), CmsResourceFilter.DEFAULT); 10291 CmsPublishList pl = new CmsPublishList(ouRes, false); 10292 pl.add(ouRes, false); 10293 10294 getProjectDriver(dbc).writePublishHistory( 10295 dbc, 10296 pl.getPublishHistoryId(), 10297 new CmsPublishedResource(ouRes, -1, CmsResourceState.STATE_NEW)); 10298 10299 // fire the 'virtual' publish event 10300 Map<String, Object> eventData = new HashMap<String, Object>(); 10301 eventData.put(I_CmsEventListener.KEY_PUBLISHID, pl.getPublishHistoryId().toString()); 10302 eventData.put(I_CmsEventListener.KEY_PROJECTID, dbc.currentProject().getUuid()); 10303 eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); 10304 CmsEvent afterPublishEvent = new CmsEvent(I_CmsEventListener.EVENT_PUBLISH_PROJECT, eventData); 10305 OpenCms.fireCmsEvent(afterPublishEvent); 10306 10307 m_monitor.cacheOrgUnit(organizationalUnit); 10308 } 10309 10310 /** 10311 * Writes an already existing project.<p> 10312 * 10313 * The project id has to be a valid OpenCms project id.<br> 10314 * 10315 * The project with the given id will be completely overridden 10316 * by the given data.<p> 10317 * 10318 * @param dbc the current database context 10319 * @param project the project that should be written 10320 * 10321 * @throws CmsException if operation was not successful 10322 */ 10323 public void writeProject(CmsDbContext dbc, CmsProject project) throws CmsException { 10324 10325 m_monitor.uncacheProject(project); 10326 getProjectDriver(dbc).writeProject(dbc, project); 10327 m_monitor.cacheProject(project); 10328 } 10329 10330 /** 10331 * Writes a new project into the PROJECT_LASTMODIFIED field of a resource record.<p> 10332 * 10333 * @param dbc the current database context 10334 * @param resource the resource which should be modified 10335 * @param projectId the project id to write 10336 * 10337 * @throws CmsDataAccessException if the database access fails 10338 */ 10339 public void writeProjectLastModified(CmsDbContext dbc, CmsResource resource, CmsUUID projectId) 10340 throws CmsDataAccessException { 10341 10342 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 10343 vfsDriver.writeLastModifiedProjectId(dbc, dbc.currentProject(), projectId, resource); 10344 } 10345 10346 /** 10347 * Writes a property for a specified resource.<p> 10348 * 10349 * @param dbc the current database context 10350 * @param resource the resource to write the property for 10351 * @param property the property to write 10352 * 10353 * @throws CmsException if something goes wrong 10354 * 10355 * @see CmsObject#writePropertyObject(String, CmsProperty) 10356 * @see I_CmsResourceType#writePropertyObject(CmsObject, CmsSecurityManager, CmsResource, CmsProperty) 10357 */ 10358 public void writePropertyObject(CmsDbContext dbc, CmsResource resource, CmsProperty property) throws CmsException { 10359 10360 try { 10361 if (property == CmsProperty.getNullProperty()) { 10362 // skip empty or null properties 10363 return; 10364 } 10365 10366 // test if and what state should be updated 10367 // 0: none, 1: structure, 2: resource 10368 int updateState = getUpdateState(dbc, resource, Collections.singletonList(property)); 10369 10370 // write the property 10371 getVfsDriver(dbc).writePropertyObject(dbc, dbc.currentProject(), resource, property); 10372 10373 if (updateState > 0) { 10374 updateState(dbc, resource, updateState == 2); 10375 } 10376 // log it 10377 log( 10378 dbc, 10379 new CmsLogEntry( 10380 dbc, 10381 resource.getStructureId(), 10382 CmsLogEntryType.RESOURCE_PROPERTIES, 10383 new String[] {resource.getRootPath()}), 10384 false); 10385 10386 } finally { 10387 // update the driver manager cache 10388 m_monitor.clearResourceCache(); 10389 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); 10390 10391 // fire an event that a property of a resource has been modified 10392 Map<String, Object> data = new HashMap<String, Object>(); 10393 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 10394 data.put("property", property); 10395 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_PROPERTY_MODIFIED, data)); 10396 } 10397 } 10398 10399 /** 10400 * Writes a list of properties for a specified resource.<p> 10401 * 10402 * Code calling this method has to ensure that the no properties 10403 * <code>a, b</code> are contained in the specified list so that <code>a.equals(b)</code>, 10404 * otherwise an exception is thrown.<p> 10405 * 10406 * @param dbc the current database context 10407 * @param resource the resource to write the properties for 10408 * @param properties the list of properties to write 10409 * @param updateState if <code>true</code> the state of the resource will be updated 10410 * 10411 * @throws CmsException if something goes wrong 10412 * 10413 * @see CmsObject#writePropertyObjects(String, List) 10414 * @see I_CmsResourceType#writePropertyObjects(CmsObject, CmsSecurityManager, CmsResource, List) 10415 */ 10416 public void writePropertyObjects( 10417 CmsDbContext dbc, 10418 CmsResource resource, 10419 List<CmsProperty> properties, 10420 boolean updateState) 10421 throws CmsException { 10422 10423 if ((properties == null) || (properties.size() == 0)) { 10424 // skip empty or null lists 10425 return; 10426 } 10427 10428 try { 10429 // the specified list must not contain two or more equal property objects 10430 for (int i = 0, n = properties.size(); i < n; i++) { 10431 Set<String> keyValidationSet = new HashSet<String>(); 10432 CmsProperty property = properties.get(i); 10433 if (!keyValidationSet.contains(property.getName())) { 10434 keyValidationSet.add(property.getName()); 10435 } else { 10436 throw new CmsVfsException( 10437 Messages.get().container(Messages.ERR_VFS_INVALID_PROPERTY_LIST_1, property.getName())); 10438 } 10439 } 10440 10441 // test if and what state should be updated 10442 // 0: none, 1: structure, 2: resource 10443 int updateStateValue = 0; 10444 if (updateState) { 10445 updateStateValue = getUpdateState(dbc, resource, properties); 10446 } 10447 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 10448 for (int i = 0; i < properties.size(); i++) { 10449 // write the property 10450 CmsProperty property = properties.get(i); 10451 vfsDriver.writePropertyObject(dbc, dbc.currentProject(), resource, property); 10452 } 10453 10454 if (updateStateValue > 0) { 10455 // update state 10456 updateState(dbc, resource, (updateStateValue == 2)); 10457 } 10458 10459 if (updateState) { 10460 // log it 10461 log( 10462 dbc, 10463 new CmsLogEntry( 10464 dbc, 10465 resource.getStructureId(), 10466 CmsLogEntryType.RESOURCE_PROPERTIES, 10467 new String[] {resource.getRootPath()}), 10468 false); 10469 } 10470 } finally { 10471 // update the driver manager cache 10472 m_monitor.clearResourceCache(); 10473 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); 10474 10475 // fire an event that the properties of a resource have been modified 10476 OpenCms.fireCmsEvent( 10477 new CmsEvent( 10478 I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, 10479 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, resource))); 10480 } 10481 } 10482 10483 /** 10484 * Updates a publish job.<p> 10485 * 10486 * @param dbc the current database context 10487 * @param publishJob the publish job to update 10488 * 10489 * @throws CmsException if something goes wrong 10490 */ 10491 public void writePublishJob(CmsDbContext dbc, CmsPublishJobInfoBean publishJob) throws CmsException { 10492 10493 getProjectDriver(dbc).writePublishJob(dbc, publishJob); 10494 } 10495 10496 /** 10497 * Writes the publish report for a publish job.<p> 10498 * 10499 * @param dbc the current database context 10500 * @param publishJob the publish job 10501 * @throws CmsException if something goes wrong 10502 */ 10503 public void writePublishReport(CmsDbContext dbc, CmsPublishJobInfoBean publishJob) throws CmsException { 10504 10505 CmsPublishReport report = (CmsPublishReport)publishJob.removePublishReport(); 10506 10507 if (report != null) { 10508 getProjectDriver(dbc).writePublishReport(dbc, publishJob.getPublishHistoryId(), report.getContents()); 10509 } 10510 } 10511 10512 /** 10513 * Writes a resource to the OpenCms VFS.<p> 10514 * 10515 * @param dbc the current database context 10516 * @param resource the resource to write 10517 * 10518 * @throws CmsException if something goes wrong 10519 */ 10520 public void writeResource(CmsDbContext dbc, CmsResource resource) throws CmsException { 10521 10522 // access was granted - write the resource 10523 resource.setUserLastModified(dbc.currentUser().getId()); 10524 CmsUUID projectId = ((dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) 10525 ? dbc.currentProject().getUuid() 10526 : dbc.getProjectId(); 10527 10528 getVfsDriver(dbc).writeResource(dbc, projectId, resource, UPDATE_RESOURCE_STATE); 10529 10530 // make sure the written resource has the state correctly set 10531 if (resource.getState().isUnchanged()) { 10532 resource.setState(CmsResource.STATE_CHANGED); 10533 } 10534 10535 // delete in content relations if the new type is not parseable 10536 if (!(OpenCms.getResourceManager().getResourceType(resource.getTypeId()) instanceof I_CmsLinkParseable)) { 10537 deleteRelationsWithSiblings(dbc, resource); 10538 } 10539 10540 // update the cache 10541 m_monitor.clearResourceCache(); 10542 Map<String, Object> data = new HashMap<String, Object>(2); 10543 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 10544 data.put(I_CmsEventListener.KEY_CHANGE, new Integer(CHANGED_RESOURCE)); 10545 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 10546 } 10547 10548 /** 10549 * Inserts an entry in the published resource table.<p> 10550 * 10551 * This is done during static export.<p> 10552 * 10553 * @param dbc the current database context 10554 * @param resourceName The name of the resource to be added to the static export 10555 * @param linkType the type of resource exported (0= non-parameter, 1=parameter) 10556 * @param linkParameter the parameters added to the resource 10557 * @param timestamp a time stamp for writing the data into the db 10558 * 10559 * @throws CmsException if something goes wrong 10560 */ 10561 public void writeStaticExportPublishedResource( 10562 CmsDbContext dbc, 10563 String resourceName, 10564 int linkType, 10565 String linkParameter, 10566 long timestamp) 10567 throws CmsException { 10568 10569 getProjectDriver(dbc).writeStaticExportPublishedResource(dbc, resourceName, linkType, linkParameter, timestamp); 10570 } 10571 10572 /** 10573 * Adds a new url name mapping for a structure id.<p> 10574 * 10575 * Instead of taking the name directly, this method takes an iterator of strings 10576 * which generates candidate URL names on-the-fly. The first generated name which is 10577 * not already mapped to another structure id will be chosen for the new URL name mapping. 10578 * 10579 * @param dbc the current database context 10580 * @param nameSeq the sequence of URL name candidates 10581 * @param structureId the structure id to which the url name should be mapped 10582 * @param locale the locale for which the mapping should be written 10583 * @param replaceOnPublish name mappings for which this is set will replace all other mappings for the same resource on publishing 10584 * 10585 * @return the actual name which was mapped to the structure id 10586 * 10587 * @throws CmsDataAccessException if something goes wrong 10588 */ 10589 public String writeUrlNameMapping( 10590 CmsDbContext dbc, 10591 Iterator<String> nameSeq, 10592 CmsUUID structureId, 10593 String locale, 10594 boolean replaceOnPublish) 10595 throws CmsDataAccessException { 10596 10597 String bestName = findBestNameForUrlNameMapping(dbc, nameSeq, structureId, locale); 10598 addOrReplaceUrlNameMapping(dbc, bestName, structureId, locale, replaceOnPublish); 10599 return bestName; 10600 } 10601 10602 /** 10603 * Updates the user information. <p> 10604 * 10605 * The user id has to be a valid OpenCms user id.<br> 10606 * 10607 * The user with the given id will be completely overridden 10608 * by the given data.<p> 10609 * 10610 * @param dbc the current database context 10611 * @param user the user to be updated 10612 * 10613 * @throws CmsException if operation was not successful 10614 */ 10615 public void writeUser(CmsDbContext dbc, CmsUser user) throws CmsException { 10616 10617 CmsUser oldUser = readUser(dbc, user.getId()); 10618 m_monitor.clearUserCache(oldUser); 10619 getUserDriver(dbc).writeUser(dbc, user); 10620 m_monitor.flushCache(CmsMemoryMonitor.CacheType.USER_LIST); 10621 10622 if (!dbc.getProjectId().isNullUUID()) { 10623 // user modified event is not needed 10624 return; 10625 } 10626 // fire user modified event 10627 Map<String, Object> eventData = new HashMap<String, Object>(); 10628 eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); 10629 eventData.put(I_CmsEventListener.KEY_USER_NAME, oldUser.getName()); 10630 eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_WRITE_USER); 10631 eventData.put(I_CmsEventListener.KEY_USER_CHANGES, Integer.valueOf(user.getChanges(oldUser))); 10632 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); 10633 OpenCms.getTwoFactorAuthenticationHandler().trackUserChange(dbc.getRequestContext(), oldUser, user); 10634 } 10635 10636 /** 10637 * Adds or replaces a new url name mapping in the offline project.<p> 10638 * 10639 * @param dbc the current database context 10640 * @param name the URL name of the mapping 10641 * @param structureId the structure id of the mapping 10642 * @param locale the locale of the mapping 10643 * @param replaceOnPublish if the mapping shoudl replace previous URL name mappings when published 10644 * 10645 * @throws CmsDataAccessException if something goes wrong 10646 */ 10647 protected void addOrReplaceUrlNameMapping( 10648 CmsDbContext dbc, 10649 String name, 10650 CmsUUID structureId, 10651 String locale, 10652 boolean replaceOnPublish) 10653 throws CmsDataAccessException { 10654 10655 getVfsDriver(dbc).deleteUrlNameMappingEntries( 10656 dbc, 10657 false, 10658 CmsUrlNameMappingFilter.ALL.filterStructureId(structureId).filterLocale(locale).filterStates( 10659 CmsUrlNameMappingEntry.MAPPING_STATUS_NEW, 10660 CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH)); 10661 CmsUrlNameMappingEntry newEntry = new CmsUrlNameMappingEntry( 10662 name, 10663 structureId, 10664 replaceOnPublish 10665 ? CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH 10666 : CmsUrlNameMappingEntry.MAPPING_STATUS_NEW, 10667 System.currentTimeMillis(), 10668 locale); 10669 getVfsDriver(dbc).addUrlNameMappingEntry(dbc, false, newEntry); 10670 } 10671 10672 /** 10673 * Converts a resource to a folder (if possible).<p> 10674 * 10675 * @param resource the resource to convert 10676 * @return the converted resource 10677 * 10678 * @throws CmsVfsResourceNotFoundException if the resource is not a folder 10679 */ 10680 protected CmsFolder convertResourceToFolder(CmsResource resource) throws CmsVfsResourceNotFoundException { 10681 10682 if (resource.isFolder()) { 10683 return new CmsFolder(resource); 10684 } 10685 10686 throw new CmsVfsResourceNotFoundException( 10687 Messages.get().container(Messages.ERR_ACCESS_FILE_AS_FOLDER_1, resource.getRootPath())); 10688 } 10689 10690 /** 10691 * Helper method for creating a driver from configuration data.<p> 10692 * 10693 * @param dbc the db context 10694 * @param configManager the configuration manager 10695 * @param config the configuration 10696 * @param driverChainKey the configuration key under which the driver chain is stored 10697 * @param suffix the suffix to append to a driver chain entry to get the key for the driver class 10698 * 10699 * @return the newly created driver 10700 */ 10701 protected Object createDriver( 10702 CmsDbContext dbc, 10703 CmsConfigurationManager configManager, 10704 CmsParameterConfiguration config, 10705 String driverChainKey, 10706 String suffix) { 10707 10708 // read the vfs driver class properties and initialize a new instance 10709 List<String> drivers = config.getList(driverChainKey); 10710 String driverKey = drivers.get(0) + suffix; 10711 String driverName = config.get(driverKey); 10712 drivers = (drivers.size() > 1) ? drivers.subList(1, drivers.size()) : null; 10713 if (driverName == null) { 10714 CmsLog.INIT.error(Messages.get().getBundle().key(Messages.INIT_DRIVER_FAILED_1, driverKey)); 10715 } 10716 Object result = newDriverInstance(dbc, configManager, driverName, drivers); 10717 if ("true".equalsIgnoreCase(System.getProperty("opencms.profile.drivers"))) { 10718 result = wrapDriverInProfilingProxy(result); 10719 } 10720 return result; 10721 } 10722 10723 /** 10724 * Deletes all relations for the given resource and all its siblings.<p> 10725 * 10726 * @param dbc the current database context 10727 * @param resource the resource to delete the resource for 10728 * 10729 * @throws CmsException if something goes wrong 10730 */ 10731 protected void deleteRelationsWithSiblings(CmsDbContext dbc, CmsResource resource) throws CmsException { 10732 10733 // get all siblings 10734 List<CmsResource> siblings; 10735 if (resource.getSiblingCount() > 1) { 10736 siblings = readSiblings(dbc, resource, CmsResourceFilter.ALL); 10737 } else { 10738 siblings = new ArrayList<CmsResource>(); 10739 siblings.add(resource); 10740 } 10741 // clean the relations in content for all siblings 10742 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 10743 Iterator<CmsResource> it = siblings.iterator(); 10744 while (it.hasNext()) { 10745 CmsResource sibling = it.next(); 10746 // clean the relation information for this sibling 10747 vfsDriver.deleteRelations( 10748 dbc, 10749 dbc.currentProject().getUuid(), 10750 sibling, 10751 CmsRelationFilter.TARGETS.filterDefinedInContent()); 10752 } 10753 } 10754 10755 /** 10756 * Tries to add sub-resources of moved folders to the publish list and throws an exception if the publish list still does 10757 * not contain some sub-resources of the moved folders.<p> 10758 * 10759 * @param cms the current CMS context 10760 * @param dbc the current database context 10761 * @param pubList the publish list 10762 * @throws CmsException if something goes wrong 10763 */ 10764 protected void ensureSubResourcesOfMovedFoldersPublished(CmsObject cms, CmsDbContext dbc, CmsPublishList pubList) 10765 throws CmsException { 10766 10767 List<CmsResource> topMovedFolders = pubList.getTopMovedFolders(cms); 10768 Iterator<CmsResource> folderIt = topMovedFolders.iterator(); 10769 while (folderIt.hasNext()) { 10770 CmsResource folder = folderIt.next(); 10771 addSubResources(dbc, pubList, folder, resource -> !resource.getState().isNew()); 10772 } 10773 List<CmsResource> missingSubResources = pubList.getMissingSubResources(cms, topMovedFolders); 10774 if (missingSubResources.isEmpty()) { 10775 return; 10776 } 10777 10778 StringBuffer pathBuffer = new StringBuffer(); 10779 10780 for (CmsResource missing : missingSubResources) { 10781 pathBuffer.append(missing.getRootPath()); 10782 pathBuffer.append(" "); 10783 } 10784 throw new CmsVfsException( 10785 Messages.get().container(Messages.RPT_CHILDREN_OF_MOVED_FOLDER_NOT_PUBLISHED_1, pathBuffer.toString())); 10786 10787 } 10788 10789 /** 10790 * Tries to find the best name for an URL name mapping for the given structure id.<p> 10791 * 10792 * @param dbc the database context 10793 * @param nameSeq the sequence of name candidates 10794 * @param structureId the structure id to which an URL name should be mapped 10795 * @param locale the locale for which the URL name should be mapped 10796 * 10797 * @return the selected URL name candidate 10798 * 10799 * @throws CmsDataAccessException if something goes wrong 10800 */ 10801 protected String findBestNameForUrlNameMapping( 10802 CmsDbContext dbc, 10803 Iterator<String> nameSeq, 10804 CmsUUID structureId, 10805 String locale) 10806 throws CmsDataAccessException { 10807 10808 String newName; 10809 boolean alreadyInUse; 10810 do { 10811 newName = nameSeq.next(); 10812 alreadyInUse = false; 10813 CmsUrlNameMappingFilter filter = CmsUrlNameMappingFilter.ALL.filterName(newName); 10814 List<CmsUrlNameMappingEntry> entriesWithSameName = getVfsDriver(dbc).readUrlNameMappingEntries( 10815 dbc, 10816 false, 10817 filter); 10818 for (CmsUrlNameMappingEntry entry : entriesWithSameName) { 10819 boolean sameId = entry.getStructureId().equals(structureId); 10820 if (!sameId) { 10821 // name already used for other resource, or for different locale of the same resource 10822 alreadyInUse = true; 10823 break; 10824 } 10825 } 10826 } while (alreadyInUse); 10827 return newName; 10828 } 10829 10830 /** 10831 * Helper method for finding the 'best' URL name to use for a new URL name mapping.<p> 10832 * 10833 * Since the name given as a parameter may be already used, this method will try to append numeric suffixes 10834 * to the name to find a mapping name which is not used.<p> 10835 * 10836 * @param dbc the current database context 10837 * @param name the name of the mapping 10838 * @param structureId the structure id to which the name is mapped 10839 * 10840 * @return the best name which was found for the new mapping 10841 * 10842 * @throws CmsDataAccessException if something goes wrong 10843 */ 10844 protected String findBestNameForUrlNameMapping(CmsDbContext dbc, String name, CmsUUID structureId) 10845 throws CmsDataAccessException { 10846 10847 List<CmsUrlNameMappingEntry> entriesStartingWithName = getVfsDriver(dbc).readUrlNameMappingEntries( 10848 dbc, 10849 false, 10850 CmsUrlNameMappingFilter.ALL.filterNamePattern(name + "%").filterRejectStructureId(structureId)); 10851 Set<String> usedNames = new HashSet<String>(); 10852 for (CmsUrlNameMappingEntry entry : entriesStartingWithName) { 10853 usedNames.add(entry.getName()); 10854 } 10855 int counter = 0; 10856 String numberedName; 10857 do { 10858 numberedName = getNumberedName(name, counter); 10859 counter += 1; 10860 } while (usedNames.contains(numberedName)); 10861 return numberedName; 10862 } 10863 10864 /** 10865 * Returns the lock manager instance.<p> 10866 * 10867 * @return the lock manager instance 10868 */ 10869 protected CmsLockManager getLockManager() { 10870 10871 return m_lockManager; 10872 } 10873 10874 /** 10875 * Adds a numeric suffix to the end of a string, unless the number passed as a parameter is 0.<p> 10876 * 10877 * @param name the base name 10878 * @param number the number from which to form the suffix 10879 * 10880 * @return the concatenation of the base name and possibly the numeric suffix 10881 */ 10882 protected String getNumberedName(String name, int number) { 10883 10884 if (number == 0) { 10885 return name; 10886 } 10887 PrintfFormat fmt = new PrintfFormat("%0.6d"); 10888 return name + "_" + fmt.sprintf(number); 10889 } 10890 10891 /** 10892 * Resets the resources in a project to their online state.<p> 10893 * 10894 * @param dbc the database context 10895 * @param projectId the project id 10896 * @param modifiedFiles the modified files 10897 * @param modifiedFolders the modified folders 10898 * @throws CmsException if something goes wrong 10899 * @throws CmsSecurityException if we don't have the permissions 10900 * @throws CmsDataAccessException if something goes wrong with the database 10901 */ 10902 protected void resetResourcesInProject( 10903 CmsDbContext dbc, 10904 CmsUUID projectId, 10905 List<CmsResource> modifiedFiles, 10906 List<CmsResource> modifiedFolders) 10907 throws CmsException, CmsSecurityException, CmsDataAccessException { 10908 10909 // all resources inside the project have to be be reset to their online state. 10910 // 1. step: delete all new files 10911 for (int i = 0; i < modifiedFiles.size(); i++) { 10912 CmsResource currentFile = modifiedFiles.get(i); 10913 if (currentFile.getState().isNew()) { 10914 CmsLock lock = getLock(dbc, currentFile); 10915 if (lock.isNullLock()) { 10916 // lock the resource 10917 lockResource(dbc, currentFile, CmsLockType.EXCLUSIVE); 10918 } else if (!lock.isOwnedBy(dbc.currentUser()) || !lock.isInProject(dbc.currentProject())) { 10919 changeLock(dbc, currentFile, CmsLockType.EXCLUSIVE); 10920 } 10921 // delete the properties 10922 getVfsDriver(dbc).deletePropertyObjects( 10923 dbc, 10924 projectId, 10925 currentFile, 10926 CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES); 10927 // delete the file 10928 getVfsDriver(dbc).removeFile(dbc, dbc.currentProject().getUuid(), currentFile); 10929 // remove the access control entries 10930 getUserDriver(dbc).removeAccessControlEntries(dbc, dbc.currentProject(), currentFile.getResourceId()); 10931 // fire the corresponding event 10932 OpenCms.fireCmsEvent( 10933 new CmsEvent( 10934 I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, 10935 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, currentFile))); 10936 } 10937 } 10938 10939 // 2. step: delete all new folders 10940 for (int i = 0; i < modifiedFolders.size(); i++) { 10941 CmsResource currentFolder = modifiedFolders.get(i); 10942 if (currentFolder.getState().isNew()) { 10943 // delete the properties 10944 getVfsDriver(dbc).deletePropertyObjects( 10945 dbc, 10946 projectId, 10947 currentFolder, 10948 CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES); 10949 // delete the folder 10950 getVfsDriver(dbc).removeFolder(dbc, dbc.currentProject(), currentFolder); 10951 // remove the access control entries 10952 getUserDriver(dbc).removeAccessControlEntries(dbc, dbc.currentProject(), currentFolder.getResourceId()); 10953 // fire the corresponding event 10954 OpenCms.fireCmsEvent( 10955 new CmsEvent( 10956 I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, 10957 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, currentFolder))); 10958 } 10959 } 10960 10961 // 3. step: undo changes on all changed or deleted folders 10962 for (int i = 0; i < modifiedFolders.size(); i++) { 10963 CmsResource currentFolder = modifiedFolders.get(i); 10964 if ((currentFolder.getState().isChanged()) || (currentFolder.getState().isDeleted())) { 10965 CmsLock lock = getLock(dbc, currentFolder); 10966 if (lock.isNullLock()) { 10967 // lock the resource 10968 lockResource(dbc, currentFolder, CmsLockType.EXCLUSIVE); 10969 } else if (!lock.isOwnedBy(dbc.currentUser()) || !lock.isInProject(dbc.currentProject())) { 10970 changeLock(dbc, currentFolder, CmsLockType.EXCLUSIVE); 10971 } 10972 // undo all changes in the folder 10973 undoChanges(dbc, currentFolder, CmsResource.UNDO_CONTENT); 10974 // fire the corresponding event 10975 OpenCms.fireCmsEvent( 10976 new CmsEvent( 10977 I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, 10978 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, currentFolder))); 10979 } 10980 } 10981 10982 // 4. step: undo changes on all changed or deleted files 10983 for (int i = 0; i < modifiedFiles.size(); i++) { 10984 CmsResource currentFile = modifiedFiles.get(i); 10985 if (currentFile.getState().isChanged() || currentFile.getState().isDeleted()) { 10986 CmsLock lock = getLock(dbc, currentFile); 10987 if (lock.isNullLock()) { 10988 // lock the resource 10989 lockResource(dbc, currentFile, CmsLockType.EXCLUSIVE); 10990 } else if (!lock.isOwnedInProjectBy(dbc.currentUser(), dbc.currentProject())) { 10991 if (lock.isLockableBy(dbc.currentUser())) { 10992 changeLock(dbc, currentFile, CmsLockType.EXCLUSIVE); 10993 } 10994 } 10995 // undo all changes in the file 10996 undoChanges(dbc, currentFile, CmsResource.UNDO_CONTENT); 10997 // fire the corresponding event 10998 OpenCms.fireCmsEvent( 10999 new CmsEvent( 11000 I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, 11001 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, currentFile))); 11002 } 11003 } 11004 } 11005 11006 /** 11007 * Counts the total number of users which fit the given criteria.<p> 11008 * 11009 * @param dbc the database context 11010 * @param searchParams the user search criteria 11011 * 11012 * @return the total number of users matching the criteria 11013 * 11014 * @throws CmsDataAccessException if something goes wrong 11015 */ 11016 long countUsers(CmsDbContext dbc, CmsUserSearchParameters searchParams) throws CmsDataAccessException { 11017 11018 return getUserDriver(dbc).countUsers(dbc, searchParams); 11019 } 11020 11021 /** 11022 * Adds a pool to the static pool map.<p> 11023 * 11024 * @param pool the pool to add 11025 */ 11026 private void addPool(CmsDbPoolV11 pool) { 11027 11028 m_pools.put(pool.getPoolUrl(), pool); 11029 } 11030 11031 /** 11032 * Adds all sub-resources of the given resource to the publish list.<p> 11033 * 11034 * @param dbc the database context 11035 * @param publishList the publish list 11036 * @param directPublishResource the resource to get the sub-resources for 11037 * @param additionalFilter an additional test for resources to pass before they are added to the publish list 11038 * 11039 * @throws CmsDataAccessException if something goes wrong accessing the database 11040 */ 11041 private void addSubResources( 11042 CmsDbContext dbc, 11043 CmsPublishList publishList, 11044 CmsResource directPublishResource, 11045 Predicate<CmsResource> additionalFilter) 11046 throws CmsDataAccessException { 11047 11048 int flags = CmsDriverManager.READMODE_INCLUDE_TREE | CmsDriverManager.READMODE_EXCLUDE_STATE; 11049 if (!directPublishResource.getState().isDeleted()) { 11050 // fix for org.opencms.file.TestPublishIssues#testPublishFolderWithDeletedFileFromOtherProject 11051 flags = flags | CmsDriverManager.READMODE_INCLUDE_PROJECT; 11052 } 11053 11054 // add all sub resources of the folder 11055 List<CmsResource> folderList = getVfsDriver(dbc).readResourceTree( 11056 dbc, 11057 dbc.currentProject().getUuid(), 11058 directPublishResource.getRootPath(), 11059 CmsDriverManager.READ_IGNORE_TYPE, 11060 CmsResource.STATE_UNCHANGED, 11061 CmsDriverManager.READ_IGNORE_TIME, 11062 CmsDriverManager.READ_IGNORE_TIME, 11063 CmsDriverManager.READ_IGNORE_TIME, 11064 CmsDriverManager.READ_IGNORE_TIME, 11065 CmsDriverManager.READ_IGNORE_TIME, 11066 CmsDriverManager.READ_IGNORE_TIME, 11067 flags | CmsDriverManager.READMODE_ONLY_FOLDERS); 11068 11069 publishList.addAll( 11070 filterResources(dbc, publishList, folderList).stream().filter(additionalFilter).collect( 11071 Collectors.toList()), 11072 true); 11073 11074 List<CmsResource> fileList = getVfsDriver(dbc).readResourceTree( 11075 dbc, 11076 dbc.currentProject().getUuid(), 11077 directPublishResource.getRootPath(), 11078 CmsDriverManager.READ_IGNORE_TYPE, 11079 CmsResource.STATE_UNCHANGED, 11080 CmsDriverManager.READ_IGNORE_TIME, 11081 CmsDriverManager.READ_IGNORE_TIME, 11082 CmsDriverManager.READ_IGNORE_TIME, 11083 CmsDriverManager.READ_IGNORE_TIME, 11084 CmsDriverManager.READ_IGNORE_TIME, 11085 CmsDriverManager.READ_IGNORE_TIME, 11086 flags | CmsDriverManager.READMODE_ONLY_FILES); 11087 11088 publishList.addAll( 11089 filterResources(dbc, publishList, fileList).stream().filter(additionalFilter).collect(Collectors.toList()), 11090 true); 11091 } 11092 11093 /** 11094 * Helper method to check whether we should bother with reading the group for a given role in a given OU.<p> 11095 * 11096 * This is important because webuser OUs don't have most role groups, and their absence is not cached, so we want to avoid reading them. 11097 * 11098 * @param ou the OU 11099 * @param role the role 11100 * @return true if we should read the role in the OU 11101 */ 11102 private boolean canReadRoleInOu(CmsOrganizationalUnit ou, CmsRole role) { 11103 11104 if (ou.hasFlagWebuser() && !role.getRoleName().equals(CmsRole.ACCOUNT_MANAGER.getRoleName())) { 11105 return false; 11106 } 11107 return true; 11108 } 11109 11110 /** 11111 * Checks the parent of a resource during publishing.<p> 11112 * 11113 * @param dbc the current database context 11114 * @param deletedFolders a list of deleted folders 11115 * @param res a resource to check the parent for 11116 * 11117 * @return <code>true</code> if the parent resource will be deleted during publishing 11118 */ 11119 private boolean checkDeletedParentFolder(CmsDbContext dbc, List<CmsResource> deletedFolders, CmsResource res) { 11120 11121 String parentPath = CmsResource.getParentFolder(res.getRootPath()); 11122 11123 if (parentPath == null) { 11124 // resource has no parent 11125 return false; 11126 } 11127 11128 CmsResource parent; 11129 try { 11130 parent = readResource(dbc, parentPath, CmsResourceFilter.ALL); 11131 } catch (Exception e) { 11132 // failure: if we cannot read the parent, we should not publish the resource 11133 return false; 11134 } 11135 11136 if (!parent.getState().isDeleted()) { 11137 // parent is not deleted 11138 return false; 11139 } 11140 11141 for (int j = 0; j < deletedFolders.size(); j++) { 11142 if ((deletedFolders.get(j)).getStructureId().equals(parent.getStructureId())) { 11143 // parent is deleted, and it will get published 11144 return true; 11145 } 11146 } 11147 11148 // parent is new, but it will not get published 11149 return false; 11150 } 11151 11152 /** 11153 * Checks that no one of the resources to be published has a 'new' parent (that has not been published yet).<p> 11154 * 11155 * @param dbc the db context 11156 * @param publishList the publish list to check 11157 * 11158 * @throws CmsVfsException if there is a resource to be published with a 'new' parent 11159 */ 11160 private void checkParentFolders(CmsDbContext dbc, CmsPublishList publishList) throws CmsVfsException { 11161 11162 boolean directPublish = publishList.isDirectPublish(); 11163 // if we direct publish a file, check if all parent folders are already published 11164 if (directPublish) { 11165 // first get the names of all parent folders 11166 Iterator<CmsResource> it = publishList.getDirectPublishResources().iterator(); 11167 List<String> parentFolderNames = new ArrayList<String>(); 11168 while (it.hasNext()) { 11169 CmsResource res = it.next(); 11170 String parentFolderName = CmsResource.getParentFolder(res.getRootPath()); 11171 if (parentFolderName != null) { 11172 parentFolderNames.add(parentFolderName); 11173 } 11174 } 11175 // remove duplicate parent folder names 11176 parentFolderNames = CmsFileUtil.removeRedundancies(parentFolderNames); 11177 String parentFolderName = null; 11178 try { 11179 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 11180 // now check all folders if they exist in the online project 11181 Iterator<String> parentIt = parentFolderNames.iterator(); 11182 while (parentIt.hasNext()) { 11183 parentFolderName = parentIt.next(); 11184 vfsDriver.readFolder(dbc, CmsProject.ONLINE_PROJECT_ID, parentFolderName); 11185 } 11186 } catch (CmsException e) { 11187 throw new CmsVfsException( 11188 Messages.get().container(Messages.RPT_PARENT_FOLDER_NOT_PUBLISHED_1, parentFolderName)); 11189 } 11190 } 11191 } 11192 11193 /** 11194 * Checks the parent of a resource during publishing.<p> 11195 * 11196 * @param dbc the current database context 11197 * @param folderList a list of folders 11198 * @param res a resource to check the parent for 11199 * 11200 * @return true if the resource should be published 11201 */ 11202 private boolean checkParentResource(CmsDbContext dbc, List<CmsResource> folderList, CmsResource res) { 11203 11204 String parentPath = CmsResource.getParentFolder(res.getRootPath()); 11205 11206 if (parentPath == null) { 11207 // resource has no parent 11208 return true; 11209 } 11210 11211 CmsResource parent; 11212 try { 11213 parent = readResource(dbc, parentPath, CmsResourceFilter.ALL); 11214 } catch (Exception e) { 11215 // failure: if we cannot read the parent, we should not publish the resource 11216 return false; 11217 } 11218 11219 if (!parent.getState().isNew()) { 11220 // parent is already published 11221 return true; 11222 } 11223 11224 for (int j = 0; j < folderList.size(); j++) { 11225 if (folderList.get(j).getStructureId().equals(parent.getStructureId())) { 11226 // parent is new, but it will get published 11227 return true; 11228 } 11229 } 11230 11231 // parent is new, but it will not get published 11232 return false; 11233 } 11234 11235 /** 11236 * Copies all relations from the source resource to the target resource.<p> 11237 * 11238 * @param dbc the database context 11239 * @param source the source 11240 * @param target the target 11241 * 11242 * @throws CmsException if something goes wrong 11243 */ 11244 private void copyRelations(CmsDbContext dbc, CmsResource source, CmsResource target) throws CmsException { 11245 11246 // copy relations all relations 11247 CmsObject cms = new CmsObject(getSecurityManager(), dbc.getRequestContext()); 11248 Iterator<CmsRelation> itRelations = getRelationsForResource( 11249 dbc, 11250 source, 11251 CmsRelationFilter.TARGETS.filterNotDefinedInContent()).iterator(); 11252 while (itRelations.hasNext()) { 11253 CmsRelation relation = itRelations.next(); 11254 if (relation.getType().getCopyBehavior() == CopyBehavior.copy) { 11255 try { 11256 CmsResource relTarget = relation.getTarget(cms, CmsResourceFilter.ALL); 11257 addRelationToResource(dbc, target, relTarget, relation.getType(), true); 11258 } catch (CmsVfsResourceNotFoundException e) { 11259 // ignore this broken relation 11260 if (LOG.isWarnEnabled()) { 11261 LOG.warn(e.getLocalizedMessage(), e); 11262 } 11263 } 11264 } 11265 } 11266 // repair categories 11267 repairCategories(dbc, getProjectIdForContext(dbc), target); 11268 } 11269 11270 /** 11271 * Filters the given list of resources, removes all resources where the current user 11272 * does not have READ permissions, plus the filter is applied.<p> 11273 * 11274 * @param dbc the current database context 11275 * @param resourceList a list of CmsResources 11276 * @param filter the resource filter to use 11277 * 11278 * @return the filtered list of resources 11279 * 11280 * @throws CmsException in case errors testing the permissions 11281 */ 11282 private List<CmsResource> filterPermissions( 11283 CmsDbContext dbc, 11284 List<CmsResource> resourceList, 11285 CmsResourceFilter filter) 11286 throws CmsException { 11287 11288 if (filter.requireTimerange()) { 11289 // never check time range here - this must be done later in #updateContextDates(...) 11290 filter = filter.addExcludeTimerange(); 11291 } 11292 ArrayList<CmsResource> result = new ArrayList<CmsResource>(resourceList.size()); 11293 for (int i = 0; i < resourceList.size(); i++) { 11294 // check the permission of all resources 11295 CmsResource currentResource = resourceList.get(i); 11296 if (m_securityManager.hasPermissions( 11297 dbc, 11298 currentResource, 11299 CmsPermissionSet.ACCESS_READ, 11300 LockCheck.yes, 11301 filter).isAllowed()) { 11302 // only return resources where permission was granted 11303 result.add(currentResource); 11304 } 11305 } 11306 // return the result 11307 return result; 11308 } 11309 11310 /** 11311 * Returns a filtered list of resources for publishing.<p> 11312 * Contains all resources, which are not locked 11313 * and which have a parent folder that is already published or will be published, too.<p> 11314 * 11315 * @param dbc the current database context 11316 * @param publishList the filling publish list 11317 * @param resourceList the list of resources to filter 11318 * 11319 * @return a filtered list of resources 11320 */ 11321 private List<CmsResource> filterResources( 11322 CmsDbContext dbc, 11323 CmsPublishList publishList, 11324 List<CmsResource> resourceList) { 11325 11326 List<CmsResource> result = new ArrayList<CmsResource>(); 11327 11328 // local folder list for adding new publishing subfolders 11329 // this solves the {@link org.opencms.file.TestPublishIssues#testPublishScenarioD} problem. 11330 List<CmsResource> newFolderList = new ArrayList<CmsResource>( 11331 publishList == null ? resourceList : publishList.getFolderList()); 11332 11333 for (int i = 0; i < resourceList.size(); i++) { 11334 CmsResource res = resourceList.get(i); 11335 try { 11336 CmsLock lock = getLock(dbc, res); 11337 if (lock.isPublish()) { 11338 // if already enqueued 11339 continue; 11340 } 11341 if (!lock.isLockableBy(dbc.currentUser())) { 11342 // checks if there is a shared lock and if the resource is deleted 11343 // this solves the {@link org.opencms.file.TestPublishIssues#testPublishScenarioE} problem. 11344 if (lock.isShared() && (publishList != null)) { 11345 if (!res.getState().isDeleted() 11346 || !checkDeletedParentFolder(dbc, publishList.getDeletedFolderList(), res)) { 11347 continue; 11348 } 11349 } else { 11350 // don't add locked resources 11351 continue; 11352 } 11353 } 11354 if (!"/".equals(res.getRootPath()) && !checkParentResource(dbc, newFolderList, res)) { 11355 continue; 11356 } 11357 // check permissions 11358 try { 11359 m_securityManager.checkPermissions( 11360 dbc, 11361 res, 11362 CmsPermissionSet.ACCESS_DIRECT_PUBLISH, 11363 false, 11364 CmsResourceFilter.ALL); 11365 } catch (CmsException e) { 11366 // skip if not enough permissions 11367 continue; 11368 } 11369 if (res.isFolder()) { 11370 newFolderList.add(res); 11371 } 11372 result.add(res); 11373 } catch (Exception e) { 11374 // should never happen 11375 LOG.error(e.getLocalizedMessage(), e); 11376 } 11377 } 11378 return result; 11379 } 11380 11381 /** 11382 * Returns a filtered list of sibling resources for publishing.<p> 11383 * 11384 * Contains all siblings of the given resources, which are not locked 11385 * and which have a parent folder that is already published or will be published, too.<p> 11386 * 11387 * @param dbc the current database context 11388 * @param publishList the unfinished publish list 11389 * @param resourceList the list of siblings to filter 11390 * 11391 * @return a filtered list of sibling resources for publishing 11392 */ 11393 private List<CmsResource> filterSiblings( 11394 CmsDbContext dbc, 11395 CmsPublishList publishList, 11396 Collection<CmsResource> resourceList) { 11397 11398 List<CmsResource> result = new ArrayList<CmsResource>(); 11399 11400 // removed internal extendible folder list, since iterated (sibling) resources are files in any case, never folders 11401 11402 for (CmsResource res : resourceList) { 11403 try { 11404 CmsLock lock = getLock(dbc, res); 11405 if (lock.isPublish()) { 11406 // if already enqueued 11407 continue; 11408 } 11409 if (!lock.isLockableBy(dbc.currentUser())) { 11410 // checks if there is a shared lock and if the resource is deleted 11411 // this solves the {@link org.opencms.file.TestPublishIssues#testPublishScenarioE} problem. 11412 if (lock.isShared() && (publishList != null)) { 11413 if (!res.getState().isDeleted() 11414 || !checkDeletedParentFolder(dbc, publishList.getDeletedFolderList(), res)) { 11415 continue; 11416 } 11417 } else { 11418 // don't add locked resources 11419 continue; 11420 } 11421 } 11422 if (!"/".equals(res.getRootPath()) && !checkParentResource(dbc, publishList.getFolderList(), res)) { 11423 // don't add resources that have no parent in the online project 11424 continue; 11425 } 11426 // check permissions 11427 try { 11428 m_securityManager.checkPermissions( 11429 dbc, 11430 res, 11431 CmsPermissionSet.ACCESS_DIRECT_PUBLISH, 11432 false, 11433 CmsResourceFilter.ALL); 11434 } catch (CmsException e) { 11435 // skip if not enough permissions 11436 continue; 11437 } 11438 result.add(res); 11439 } catch (Exception e) { 11440 // should never happen 11441 LOG.error(e.getLocalizedMessage(), e); 11442 } 11443 } 11444 return result; 11445 } 11446 11447 /** 11448 * Returns the access control list of a given resource.<p> 11449 * 11450 * @param dbc the current database context 11451 * @param resource the resource 11452 * @param forFolder should be true if resource is a folder 11453 * @param depth the depth to include non-inherited access entries, also 11454 * @param inheritedOnly flag indicates to collect inherited permissions only 11455 * 11456 * @return the access control list of the resource 11457 * 11458 * @throws CmsException if something goes wrong 11459 */ 11460 private CmsAccessControlList getAccessControlList( 11461 CmsDbContext dbc, 11462 CmsResource resource, 11463 boolean inheritedOnly, 11464 boolean forFolder, 11465 int depth) 11466 throws CmsException { 11467 11468 String cacheKey = getCacheKey( 11469 new String[] { 11470 inheritedOnly ? "+" : "-", 11471 forFolder ? "+" : "-", 11472 Integer.toString(depth), 11473 resource.getStructureId().toString()}, 11474 dbc); 11475 11476 CmsAccessControlList acl = m_monitor.getCachedACL(cacheKey); 11477 11478 // return the cached acl if already available 11479 if ((acl != null) && dbc.getProjectId().isNullUUID()) { 11480 return acl; 11481 } 11482 11483 List<CmsAccessControlEntry> aces = getUserDriver(dbc).readAccessControlEntries( 11484 dbc, 11485 dbc.currentProject(), 11486 resource.getResourceId(), 11487 (depth > 1) || ((depth > 0) && forFolder)); 11488 11489 // sort the list of aces 11490 boolean overwriteAll = sortAceList(aces); 11491 11492 // if no 'overwrite all' ace was found 11493 if (!overwriteAll) { 11494 // get the acl of the parent 11495 CmsResource parentResource = null; 11496 try { 11497 // try to recurse over the id 11498 parentResource = getVfsDriver(dbc).readParentFolder( 11499 dbc, 11500 dbc.currentProject().getUuid(), 11501 resource.getStructureId()); 11502 } catch (CmsVfsResourceNotFoundException e) { 11503 // should never happen, but try with the path 11504 String parentPath = CmsResource.getParentFolder(resource.getRootPath()); 11505 if (parentPath != null) { 11506 parentResource = getVfsDriver(dbc).readFolder(dbc, dbc.currentProject().getUuid(), parentPath); 11507 } 11508 } 11509 if (parentResource != null) { 11510 acl = (CmsAccessControlList)getAccessControlList( 11511 dbc, 11512 parentResource, 11513 inheritedOnly, 11514 forFolder, 11515 depth + 1).clone(); 11516 } 11517 } 11518 if (acl == null) { 11519 acl = new CmsAccessControlList(); 11520 } 11521 11522 if (!((depth == 0) && inheritedOnly)) { 11523 Iterator<CmsAccessControlEntry> itAces = aces.iterator(); 11524 while (itAces.hasNext()) { 11525 CmsAccessControlEntry acEntry = itAces.next(); 11526 if (depth > 0) { 11527 acEntry.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_INHERITED); 11528 } 11529 11530 acl.add(acEntry); 11531 11532 // if the overwrite flag is set, reset the allowed permissions to the permissions of this entry 11533 // denied permissions are kept or extended 11534 if ((acEntry.getFlags() & CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE) > 0) { 11535 acl.setAllowedPermissions(acEntry); 11536 } 11537 } 11538 } 11539 if (dbc.getProjectId().isNullUUID()) { 11540 m_monitor.cacheACL(cacheKey, acl); 11541 } 11542 return acl; 11543 } 11544 11545 /** 11546 * Return a cache key build from the provided information.<p> 11547 * 11548 * @param prefix a prefix for the key 11549 * @param flag a boolean flag for the key (only used if prefix is not null) 11550 * @param projectId the project for which to generate the key 11551 * @param resource the resource for which to generate the key 11552 * 11553 * @return String a cache key build from the provided information 11554 */ 11555 private String getCacheKey(String prefix, boolean flag, CmsUUID projectId, String resource) { 11556 11557 StringBuffer b = new StringBuffer(64); 11558 if (prefix != null) { 11559 b.append(prefix); 11560 b.append(flag ? '+' : '-'); 11561 } 11562 b.append(CmsProject.isOnlineProject(projectId) ? '+' : '-'); 11563 return b.append(resource).toString(); 11564 } 11565 11566 /** 11567 * Return a cache key build from the provided information.<p> 11568 * 11569 * @param keys an array of keys to generate the cache key from 11570 * @param dbc the database context for which to generate the key 11571 * 11572 * @return String a cache key build from the provided information 11573 */ 11574 private String getCacheKey(String[] keys, CmsDbContext dbc) { 11575 11576 if (!dbc.getProjectId().isNullUUID()) { 11577 return ""; 11578 } 11579 StringBuffer b = new StringBuffer(64); 11580 int len = keys.length; 11581 if (len > 0) { 11582 for (int i = 0; i < len; i++) { 11583 b.append(keys[i]); 11584 b.append('_'); 11585 } 11586 } 11587 if (dbc.currentProject().isOnlineProject()) { 11588 b.append("+"); 11589 } else { 11590 b.append("-"); 11591 } 11592 return b.toString(); 11593 } 11594 11595 /** 11596 * Gets the correct driver interface to use for proxying a specific driver instance.<p> 11597 * 11598 * @param obj the driver instance 11599 * @return the interface to use for proxying 11600 */ 11601 private Class<?> getDriverInterfaceForProxy(Object obj) { 11602 11603 for (Class<?> interfaceClass : new Class[] { 11604 I_CmsUserDriver.class, 11605 I_CmsVfsDriver.class, 11606 I_CmsProjectDriver.class, 11607 I_CmsHistoryDriver.class, 11608 I_CmsSubscriptionDriver.class}) { 11609 if (interfaceClass.isAssignableFrom(obj.getClass())) { 11610 return interfaceClass; 11611 } 11612 } 11613 return null; 11614 } 11615 11616 /** 11617 * Returns the correct project id.<p> 11618 * 11619 * @param dbc the database context 11620 * 11621 * @return the correct project id 11622 */ 11623 private CmsUUID getProjectIdForContext(CmsDbContext dbc) { 11624 11625 CmsUUID projectId = dbc.getProjectId(); 11626 if (projectId.isNullUUID()) { 11627 projectId = dbc.currentProject().getUuid(); 11628 } 11629 return projectId; 11630 } 11631 11632 /** 11633 * Returns if and what state needs to be updated.<p> 11634 * 11635 * @param dbc the db context 11636 * @param resource the resource 11637 * @param properties the properties to check 11638 * 11639 * @return 0: none, 1: structure, 2: resource 11640 * 11641 * @throws CmsDataAccessException if something goes wrong 11642 */ 11643 private int getUpdateState(CmsDbContext dbc, CmsResource resource, List<CmsProperty> properties) 11644 throws CmsDataAccessException { 11645 11646 int updateState = 0; 11647 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 11648 Iterator<CmsProperty> it = properties.iterator(); 11649 while (it.hasNext() && (updateState < 2)) { 11650 CmsProperty property = it.next(); 11651 11652 // read existing property 11653 CmsProperty existingProperty = vfsDriver.readPropertyObject( 11654 dbc, 11655 property.getName(), 11656 dbc.currentProject(), 11657 resource); 11658 11659 // check the shared property 11660 if (property.getResourceValue() != null) { 11661 if (property.isDeleteResourceValue()) { 11662 if (existingProperty.getResourceValue() != null) { 11663 updateState = 2; // deleted 11664 } 11665 } else { 11666 if (existingProperty.getResourceValue() == null) { 11667 updateState = 2; // created 11668 } else { 11669 if (!property.getResourceValue().equals(existingProperty.getResourceValue())) { 11670 updateState = 2; // updated 11671 } 11672 } 11673 } 11674 } 11675 if (updateState == 0) { 11676 // check the individual property only if needed 11677 if (property.getStructureValue() != null) { 11678 if (property.isDeleteStructureValue()) { 11679 if (existingProperty.getStructureValue() != null) { 11680 updateState = 1; // deleted 11681 } 11682 } else { 11683 if (existingProperty.getStructureValue() == null) { 11684 updateState = 1; // created 11685 } else { 11686 if (!property.getStructureValue().equals(existingProperty.getStructureValue())) { 11687 updateState = 1; // updated 11688 } 11689 } 11690 } 11691 } 11692 } 11693 } 11694 return updateState; 11695 } 11696 11697 /** 11698 * Returns all groups that are virtualizing the given role in the given ou.<p> 11699 * 11700 * @param dbc the database context 11701 * @param role the role 11702 * 11703 * @return all groups that are virtualizing the given role (or a child of it) 11704 * 11705 * @throws CmsException if something goes wrong 11706 */ 11707 private List<CmsGroup> getVirtualGroupsForRole(CmsDbContext dbc, CmsRole role) throws CmsException { 11708 11709 Set<Integer> roleFlags = new HashSet<Integer>(); 11710 // add role flag 11711 Integer flags = new Integer(role.getVirtualGroupFlags()); 11712 roleFlags.add(flags); 11713 // collect all child role flags 11714 Iterator<CmsRole> itChildRoles = role.getChildren(true).iterator(); 11715 while (itChildRoles.hasNext()) { 11716 CmsRole child = itChildRoles.next(); 11717 flags = new Integer(child.getVirtualGroupFlags()); 11718 roleFlags.add(flags); 11719 } 11720 // iterate all groups matching the flags 11721 List<CmsGroup> groups = new ArrayList<CmsGroup>(); 11722 Iterator<CmsGroup> it = getGroups(dbc, readOrganizationalUnit(dbc, role.getOuFqn()), false, false).iterator(); 11723 while (it.hasNext()) { 11724 CmsGroup group = it.next(); 11725 if (group.isVirtual()) { 11726 CmsRole r = CmsRole.valueOf(group); 11727 if (roleFlags.contains(new Integer(r.getVirtualGroupFlags()))) { 11728 groups.add(group); 11729 } 11730 } 11731 } 11732 return groups; 11733 } 11734 11735 /** 11736 * Returns a list of users in a group.<p> 11737 * 11738 * @param dbc the current database context 11739 * @param ouFqn the organizational unit to get the users from 11740 * @param groupname the name of the group to list users from 11741 * @param includeOtherOuUsers include users of other organizational units 11742 * @param directUsersOnly if set only the direct assigned users will be returned, 11743 * if not also indirect users, ie. members of parent roles, 11744 * this parameter only works with roles 11745 * @param readRoles if to read roles or groups 11746 * 11747 * @return all <code>{@link CmsUser}</code> objects in the group 11748 * 11749 * @throws CmsException if operation was not successful 11750 */ 11751 private List<CmsUser> internalUsersOfGroup( 11752 CmsDbContext dbc, 11753 String ouFqn, 11754 String groupname, 11755 boolean includeOtherOuUsers, 11756 boolean directUsersOnly, 11757 boolean readRoles) 11758 throws CmsException { 11759 11760 CmsGroup group = readGroup(dbc, groupname); // check that the group really exists 11761 if ((group == null) || (!((!readRoles && !group.isRole()) || (readRoles && group.isRole())))) { 11762 throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, groupname)); 11763 } 11764 11765 String prefix = "_" + includeOtherOuUsers + "_" + directUsersOnly + "_" + ouFqn; 11766 String cacheKey = m_keyGenerator.getCacheKeyForGroupUsers(prefix, dbc, group); 11767 List<CmsUser> allUsers = m_monitor.getCachedUserList(cacheKey); 11768 if (allUsers == null) { 11769 Set<CmsUser> users = new HashSet<CmsUser>( 11770 getUserDriver(dbc).readUsersOfGroup(dbc, groupname, includeOtherOuUsers)); 11771 if (readRoles && !directUsersOnly) { 11772 CmsRole role = CmsRole.valueOf(group); 11773 if (role.getParentRole() != null) { 11774 try { 11775 String parentGroup = role.getParentRole().getGroupName(); 11776 readGroup(dbc, parentGroup); 11777 // iterate the parent roles 11778 users.addAll( 11779 internalUsersOfGroup( 11780 dbc, 11781 ouFqn, 11782 parentGroup, 11783 includeOtherOuUsers, 11784 directUsersOnly, 11785 readRoles)); 11786 } catch (CmsDbEntryNotFoundException e) { 11787 // ignore, this may happen while deleting an orgunit 11788 if (LOG.isDebugEnabled()) { 11789 LOG.debug(e.getLocalizedMessage(), e); 11790 } 11791 } 11792 } 11793 String parentOu = CmsOrganizationalUnit.getParentFqn(group.getOuFqn()); 11794 if (parentOu != null) { 11795 // iterate the parent ou's 11796 users.addAll( 11797 internalUsersOfGroup( 11798 dbc, 11799 ouFqn, 11800 parentOu + group.getSimpleName(), 11801 includeOtherOuUsers, 11802 directUsersOnly, 11803 readRoles)); 11804 } 11805 } else if (!readRoles && !directUsersOnly) { 11806 List<CmsGroup> groups = getChildren(dbc, group, false); 11807 for (CmsGroup parentGroup : groups) { 11808 try { 11809 // iterate the parent groups 11810 users.addAll( 11811 internalUsersOfGroup( 11812 dbc, 11813 ouFqn, 11814 parentGroup.getName(), 11815 includeOtherOuUsers, 11816 directUsersOnly, 11817 readRoles)); 11818 } catch (CmsDbEntryNotFoundException e) { 11819 // ignore, this may happen while deleting an orgunit 11820 if (LOG.isDebugEnabled()) { 11821 LOG.debug(e.getLocalizedMessage(), e); 11822 } 11823 } 11824 } 11825 } 11826 // filter users from other ous 11827 if (!includeOtherOuUsers) { 11828 Iterator<CmsUser> itUsers = users.iterator(); 11829 while (itUsers.hasNext()) { 11830 CmsUser user = itUsers.next(); 11831 if (!user.getOuFqn().equals(ouFqn)) { 11832 itUsers.remove(); 11833 } 11834 } 11835 } 11836 11837 // make user list unmodifiable for caching 11838 allUsers = Collections.unmodifiableList(new ArrayList<CmsUser>(users)); 11839 if (dbc.getProjectId().isNullUUID()) { 11840 m_monitor.cacheUserList(cacheKey, allUsers); 11841 } 11842 } 11843 return allUsers; 11844 } 11845 11846 /** 11847 * Reads all resources that are inside and changed in a specified project.<p> 11848 * 11849 * @param dbc the current database context 11850 * @param projectId the ID of the project 11851 * @param mode one of the {@link CmsReadChangedProjectResourceMode} constants 11852 * 11853 * @return a List with all resources inside the specified project 11854 * 11855 * @throws CmsException if something goes wrong 11856 */ 11857 private List<CmsResource> readChangedResourcesInsideProject( 11858 CmsDbContext dbc, 11859 CmsUUID projectId, 11860 CmsReadChangedProjectResourceMode mode) 11861 throws CmsException { 11862 11863 String cacheKey = projectId + "_" + mode.toString(); 11864 List<CmsResource> result = m_monitor.getCachedProjectResources(cacheKey); 11865 if (result != null) { 11866 return result; 11867 } 11868 List<String> projectResources = readProjectResources(dbc, readProject(dbc, projectId)); 11869 result = new ArrayList<CmsResource>(); 11870 String currentProjectResource = null; 11871 List<CmsResource> resources = new ArrayList<CmsResource>(); 11872 CmsResource currentResource = null; 11873 CmsLock currentLock = null; 11874 11875 for (int i = 0; i < projectResources.size(); i++) { 11876 // read all resources that are inside the project by visiting each project resource 11877 currentProjectResource = projectResources.get(i); 11878 11879 try { 11880 currentResource = readResource(dbc, currentProjectResource, CmsResourceFilter.ALL); 11881 11882 if (currentResource.isFolder()) { 11883 resources.addAll(readResources(dbc, currentResource, CmsResourceFilter.ALL, true)); 11884 } else { 11885 resources.add(currentResource); 11886 } 11887 } catch (CmsException e) { 11888 // the project resource probably doesn't exist (anymore)... 11889 if (!(e instanceof CmsVfsResourceNotFoundException)) { 11890 throw e; 11891 } 11892 } 11893 } 11894 11895 for (int j = 0; j < resources.size(); j++) { 11896 currentResource = resources.get(j); 11897 currentLock = getLock(dbc, currentResource).getEditionLock(); 11898 11899 if (!currentResource.getState().isUnchanged()) { 11900 if ((currentLock.isNullLock() && (currentResource.getProjectLastModified().equals(projectId))) 11901 || (currentLock.isOwnedBy(dbc.currentUser()) && (currentLock.getProjectId().equals(projectId)))) { 11902 // add only resources that are 11903 // - inside the project, 11904 // - changed in the project, 11905 // - either unlocked, or locked for the current user in the project 11906 if ((mode == RCPRM_FILES_AND_FOLDERS_MODE) 11907 || (currentResource.isFolder() && (mode == RCPRM_FOLDERS_ONLY_MODE)) 11908 || (currentResource.isFile() && (mode == RCPRM_FILES_ONLY_MODE))) { 11909 result.add(currentResource); 11910 } 11911 } 11912 } 11913 } 11914 11915 resources.clear(); 11916 resources = null; 11917 11918 m_monitor.cacheProjectResources(cacheKey, result); 11919 return result; 11920 } 11921 11922 /** 11923 * Sorts the given list of {@link CmsAccessControlEntry} objects.<p> 11924 * 11925 * The the 'all others' ace in first place, the 'overwrite all' ace in second.<p> 11926 * 11927 * @param aces the list of ACEs to sort 11928 * 11929 * @return <code>true</code> if the list contains the 'overwrite all' ace 11930 */ 11931 private boolean sortAceList(List<CmsAccessControlEntry> aces) { 11932 11933 // sort the list of entries 11934 Collections.sort(aces, CmsAccessControlEntry.COMPARATOR_ACE); 11935 // after sorting just the first 2 positions come in question 11936 for (int i = 0; i < Math.min(aces.size(), 2); i++) { 11937 CmsAccessControlEntry acEntry = aces.get(i); 11938 if (acEntry.getPrincipal().equals(CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID)) { 11939 return true; 11940 } 11941 } 11942 return false; 11943 } 11944 11945 /** 11946 * All permissions and resources attributes of the principal 11947 * are transfered to a replacement principal.<p> 11948 * 11949 * @param dbc the current database context 11950 * @param project the current project 11951 * @param principalId the id of the principal to be replaced 11952 * @param replacementId the user to be transfered 11953 * @param withACEs flag to signal if the ACEs should also be transfered or just deleted 11954 * 11955 * @throws CmsException if operation was not successful 11956 */ 11957 private void transferPrincipalResources( 11958 CmsDbContext dbc, 11959 CmsProject project, 11960 CmsUUID principalId, 11961 CmsUUID replacementId, 11962 boolean withACEs) 11963 throws CmsException { 11964 11965 // get all resources for the given user including resources associated by ACEs or attributes 11966 I_CmsUserDriver userDriver = getUserDriver(dbc); 11967 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 11968 Set<CmsResource> resources = getResourcesForPrincipal(dbc, project, principalId, null, true); 11969 Iterator<CmsResource> it = resources.iterator(); 11970 while (it.hasNext()) { 11971 CmsResource resource = it.next(); 11972 // check resource attributes 11973 boolean attrModified = false; 11974 CmsUUID createdUser = null; 11975 if (resource.getUserCreated().equals(principalId)) { 11976 createdUser = replacementId; 11977 attrModified = true; 11978 } 11979 CmsUUID lastModUser = null; 11980 if (resource.getUserLastModified().equals(principalId)) { 11981 lastModUser = replacementId; 11982 attrModified = true; 11983 } 11984 if (attrModified) { 11985 vfsDriver.transferResource(dbc, project, resource, createdUser, lastModUser); 11986 // clear the cache 11987 m_monitor.clearResourceCache(); 11988 } 11989 boolean aceModified = false; 11990 // check aces 11991 if (withACEs) { 11992 Iterator<CmsAccessControlEntry> itAces = userDriver.readAccessControlEntries( 11993 dbc, 11994 project, 11995 resource.getResourceId(), 11996 false).iterator(); 11997 while (itAces.hasNext()) { 11998 CmsAccessControlEntry ace = itAces.next(); 11999 if (ace.getPrincipal().equals(principalId)) { 12000 CmsAccessControlEntry newAce = new CmsAccessControlEntry( 12001 ace.getResource(), 12002 replacementId, 12003 ace.getAllowedPermissions(), 12004 ace.getDeniedPermissions(), 12005 ace.getFlags()); 12006 // write the new ace 12007 userDriver.writeAccessControlEntry(dbc, project, newAce); 12008 aceModified = true; 12009 } 12010 } 12011 if (aceModified) { 12012 // clear the cache 12013 m_monitor.clearAccessControlListCache(); 12014 } 12015 } 12016 if (attrModified || aceModified) { 12017 // fire the event 12018 Map<String, Object> data = new HashMap<String, Object>(2); 12019 data.put(I_CmsEventListener.KEY_RESOURCE, resource); 12020 data.put( 12021 I_CmsEventListener.KEY_CHANGE, 12022 new Integer(((attrModified) ? CHANGED_RESOURCE : 0) | ((aceModified) ? CHANGED_ACCESSCONTROL : 0))); 12023 OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); 12024 } 12025 } 12026 } 12027 12028 /** 12029 * Undoes all content changes of a resource.<p> 12030 * 12031 * @param dbc the database context 12032 * @param onlineProject the online project 12033 * @param offlineResource the offline resource, or <code>null</code> if deleted 12034 * @param onlineResource the online resource 12035 * @param newState the new resource state 12036 * @param moveUndone is a move operation on the same resource has been made 12037 * 12038 * @throws CmsException if something goes wrong 12039 */ 12040 private void undoContentChanges( 12041 CmsDbContext dbc, 12042 CmsProject onlineProject, 12043 CmsResource offlineResource, 12044 CmsResource onlineResource, 12045 CmsResourceState newState, 12046 boolean moveUndone) 12047 throws CmsException { 12048 12049 String path = ((moveUndone || (offlineResource == null)) 12050 ? onlineResource.getRootPath() 12051 : offlineResource.getRootPath()); 12052 12053 // change folder or file? 12054 I_CmsUserDriver userDriver = getUserDriver(dbc); 12055 I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); 12056 if (onlineResource.isFolder()) { 12057 CmsFolder restoredFolder = new CmsFolder( 12058 onlineResource.getStructureId(), 12059 onlineResource.getResourceId(), 12060 path, 12061 onlineResource.getTypeId(), 12062 onlineResource.getFlags(), 12063 dbc.currentProject().getUuid(), 12064 newState, 12065 onlineResource.getDateCreated(), 12066 onlineResource.getUserCreated(), 12067 onlineResource.getDateLastModified(), 12068 onlineResource.getUserLastModified(), 12069 onlineResource.getDateReleased(), 12070 onlineResource.getDateExpired(), 12071 onlineResource.getVersion()); // version number does not matter since it will be computed later 12072 12073 // write the folder in the offline project 12074 // this sets a flag so that the folder date is not set to the current time 12075 restoredFolder.setDateLastModified(onlineResource.getDateLastModified()); 12076 12077 // write the folder 12078 vfsDriver.writeResource(dbc, dbc.currentProject().getUuid(), restoredFolder, NOTHING_CHANGED); 12079 12080 // restore the properties from the online project 12081 vfsDriver.deletePropertyObjects( 12082 dbc, 12083 dbc.currentProject().getUuid(), 12084 restoredFolder, 12085 CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES); 12086 12087 List<CmsProperty> propertyInfos = vfsDriver.readPropertyObjects(dbc, onlineProject, onlineResource); 12088 vfsDriver.writePropertyObjects(dbc, dbc.currentProject(), restoredFolder, propertyInfos); 12089 12090 // restore the access control entries from the online project 12091 userDriver.removeAccessControlEntries(dbc, dbc.currentProject(), onlineResource.getResourceId()); 12092 ListIterator<CmsAccessControlEntry> aceList = userDriver.readAccessControlEntries( 12093 dbc, 12094 onlineProject, 12095 onlineResource.getResourceId(), 12096 false).listIterator(); 12097 12098 while (aceList.hasNext()) { 12099 CmsAccessControlEntry ace = aceList.next(); 12100 userDriver.createAccessControlEntry( 12101 dbc, 12102 dbc.currentProject(), 12103 onlineResource.getResourceId(), 12104 ace.getPrincipal(), 12105 ace.getPermissions().getAllowedPermissions(), 12106 ace.getPermissions().getDeniedPermissions(), 12107 ace.getFlags()); 12108 } 12109 } else { 12110 byte[] onlineContent = vfsDriver.readContent( 12111 dbc, 12112 CmsProject.ONLINE_PROJECT_ID, 12113 onlineResource.getResourceId()); 12114 12115 CmsFile restoredFile = new CmsFile( 12116 onlineResource.getStructureId(), 12117 onlineResource.getResourceId(), 12118 path, 12119 onlineResource.getTypeId(), 12120 onlineResource.getFlags(), 12121 dbc.currentProject().getUuid(), 12122 newState, 12123 onlineResource.getDateCreated(), 12124 onlineResource.getUserCreated(), 12125 onlineResource.getDateLastModified(), 12126 onlineResource.getUserLastModified(), 12127 onlineResource.getDateReleased(), 12128 onlineResource.getDateExpired(), 12129 0, 12130 onlineResource.getLength(), 12131 onlineResource.getDateContent(), 12132 onlineResource.getVersion(), // version number does not matter since it will be computed later 12133 onlineContent); 12134 12135 // write the file in the offline project 12136 // this sets a flag so that the file date is not set to the current time 12137 restoredFile.setDateLastModified(onlineResource.getDateLastModified()); 12138 12139 // collect the old properties 12140 List<CmsProperty> properties = vfsDriver.readPropertyObjects(dbc, onlineProject, onlineResource); 12141 12142 if (offlineResource != null) { 12143 // bug fix 1020: delete all properties (inclum_rejectStructureIdded shared), 12144 // shared properties will be recreated by the next call of #createResource(...) 12145 vfsDriver.deletePropertyObjects( 12146 dbc, 12147 dbc.currentProject().getUuid(), 12148 onlineResource, 12149 CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES); 12150 12151 // implementation notes: 12152 // undo changes can become complex e.g. if a resource was deleted, and then 12153 // another resource was copied over the deleted file as a sibling 12154 // therefore we must "clean" delete the offline resource, and then create 12155 // an new resource with the create method 12156 // note that this does NOT apply to folders, since a folder cannot be replaced 12157 // like a resource anyway 12158 deleteResource(dbc, offlineResource, CmsResource.DELETE_PRESERVE_SIBLINGS); 12159 } 12160 CmsResource res = createResource( 12161 dbc, 12162 restoredFile.getRootPath(), 12163 restoredFile, 12164 restoredFile.getContents(), 12165 properties, 12166 false); 12167 12168 // copy the access control entries from the online project 12169 if (offlineResource != null) { 12170 userDriver.removeAccessControlEntries(dbc, dbc.currentProject(), onlineResource.getResourceId()); 12171 } 12172 ListIterator<CmsAccessControlEntry> aceList = userDriver.readAccessControlEntries( 12173 dbc, 12174 onlineProject, 12175 onlineResource.getResourceId(), 12176 false).listIterator(); 12177 12178 while (aceList.hasNext()) { 12179 CmsAccessControlEntry ace = aceList.next(); 12180 userDriver.createAccessControlEntry( 12181 dbc, 12182 dbc.currentProject(), 12183 res.getResourceId(), 12184 ace.getPrincipal(), 12185 ace.getPermissions().getAllowedPermissions(), 12186 ace.getPermissions().getDeniedPermissions(), 12187 ace.getFlags()); 12188 } 12189 12190 vfsDriver.deleteUrlNameMappingEntries( 12191 dbc, 12192 false, 12193 CmsUrlNameMappingFilter.ALL.filterStructureId(res.getStructureId()).filterStates( 12194 CmsUrlNameMappingEntry.MAPPING_STATUS_NEW, 12195 CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH)); 12196 // restore the state to unchanged 12197 res.setState(newState); 12198 m_vfsDriver.writeResourceState(dbc, dbc.currentProject(), res, UPDATE_ALL, false); 12199 } 12200 12201 // delete all offline relations 12202 if (offlineResource != null) { 12203 vfsDriver.deleteRelations(dbc, dbc.currentProject().getUuid(), offlineResource, CmsRelationFilter.TARGETS); 12204 } 12205 // get online relations 12206 List<CmsRelation> relations = vfsDriver.readRelations( 12207 dbc, 12208 CmsProject.ONLINE_PROJECT_ID, 12209 onlineResource, 12210 CmsRelationFilter.TARGETS); 12211 // write offline relations 12212 Iterator<CmsRelation> itRelations = relations.iterator(); 12213 while (itRelations.hasNext()) { 12214 CmsRelation relation = itRelations.next(); 12215 vfsDriver.createRelation(dbc, dbc.currentProject().getUuid(), relation); 12216 } 12217 12218 // update the cache 12219 m_monitor.clearResourceCache(); 12220 m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); 12221 12222 if ((offlineResource == null) || offlineResource.getRootPath().equals(onlineResource.getRootPath())) { 12223 log( 12224 dbc, 12225 new CmsLogEntry( 12226 dbc, 12227 onlineResource.getStructureId(), 12228 CmsLogEntryType.RESOURCE_RESTORED, 12229 new String[] {onlineResource.getRootPath()}), 12230 false); 12231 } else { 12232 log( 12233 dbc, 12234 new CmsLogEntry( 12235 dbc, 12236 offlineResource.getStructureId(), 12237 CmsLogEntryType.RESOURCE_MOVE_RESTORED, 12238 new String[] {offlineResource.getRootPath(), onlineResource.getRootPath()}), 12239 false); 12240 } 12241 if (offlineResource != null) { 12242 OpenCms.fireCmsEvent( 12243 new CmsEvent( 12244 I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, 12245 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, offlineResource))); 12246 } else { 12247 OpenCms.fireCmsEvent( 12248 new CmsEvent( 12249 I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, 12250 Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, onlineResource))); 12251 } 12252 } 12253 12254 /** 12255 * Updates the current users context dates with the given resource.<p> 12256 * 12257 * This checks the date information of the resource based on 12258 * {@link CmsResource#getDateLastModified()} as well as 12259 * {@link CmsResource#getDateReleased()} and {@link CmsResource#getDateExpired()}. 12260 * The current users request context is updated with the the "latest" dates found.<p> 12261 * 12262 * This is required in order to ensure proper setting of <code>"last-modified"</code> http headers 12263 * and also for expiration of cached elements in the Flex cache. 12264 * Consider the following use case: Page A is generated from resources x, y and z. 12265 * If either x, y or z has an expiration / release date set, then page A must expire at a certain point 12266 * in time. This is ensured by the context date check here.<p> 12267 * 12268 * @param dbc the current database context 12269 * @param resource the resource to get the date information from 12270 */ 12271 private void updateContextDates(CmsDbContext dbc, CmsResource resource) { 12272 12273 CmsFlexRequestContextInfo info = dbc.getFlexRequestContextInfo(); 12274 if (info != null) { 12275 info.updateFromResource(resource); 12276 } 12277 } 12278 12279 /** 12280 * Updates the current users context dates with each {@link CmsResource} object in the given list.<p> 12281 * 12282 * The given input list is returned unmodified.<p> 12283 * 12284 * Please see {@link #updateContextDates(CmsDbContext, CmsResource)} for an explanation of what this method does.<p> 12285 * 12286 * @param dbc the current database context 12287 * @param resourceList a list of {@link CmsResource} objects 12288 * 12289 * @return the original list of CmsResources with the full resource name set 12290 */ 12291 private List<CmsResource> updateContextDates(CmsDbContext dbc, List<CmsResource> resourceList) { 12292 12293 CmsFlexRequestContextInfo info = dbc.getFlexRequestContextInfo(); 12294 if (info != null) { 12295 for (int i = 0; i < resourceList.size(); i++) { 12296 CmsResource resource = resourceList.get(i); 12297 info.updateFromResource(resource); 12298 } 12299 } 12300 return resourceList; 12301 } 12302 12303 /** 12304 * Returns a List of {@link CmsResource} objects generated when applying the given filter to the given list, 12305 * also updates the current users context dates with each {@link CmsResource} object in the given list, 12306 * also applies the selected resource filter to all resources in the list and returns the remaining resources.<p> 12307 * 12308 * Please see {@link #updateContextDates(CmsDbContext, CmsResource)} for an explanation of what this method does.<p> 12309 * 12310 * @param dbc the current database context 12311 * @param resourceList a list of {@link CmsResource} objects 12312 * @param filter the resource filter to use 12313 * 12314 * @return a List of {@link CmsResource} objects generated when applying the given filter to the given list 12315 */ 12316 private List<CmsResource> updateContextDates( 12317 CmsDbContext dbc, 12318 List<CmsResource> resourceList, 12319 CmsResourceFilter filter) { 12320 12321 if (CmsResourceFilter.ALL == filter) { 12322 // if there is no filter required, then use the simpler method that does not apply the filter 12323 return new ArrayList<CmsResource>(updateContextDates(dbc, resourceList)); 12324 } 12325 12326 CmsFlexRequestContextInfo info = dbc.getFlexRequestContextInfo(); 12327 List<CmsResource> result = new ArrayList<CmsResource>(resourceList.size()); 12328 for (int i = 0; i < resourceList.size(); i++) { 12329 CmsResource resource = resourceList.get(i); 12330 if (filter.isValid(dbc.getRequestContext(), resource)) { 12331 result.add(resource); 12332 } 12333 // must also include "invalid" resources for the update of context dates 12334 // since a resource may be invalid because of release / expiration date 12335 if (info != null) { 12336 info.updateFromResource(resource); 12337 } 12338 } 12339 return result; 12340 } 12341 12342 /** 12343 * Updates the state of a resource, depending on the <code>resourceState</code> parameter.<p> 12344 * 12345 * @param dbc the db context 12346 * @param resource the resource 12347 * @param resourceState if <code>true</code> the resource state will be updated, if not just the structure state. 12348 * 12349 * @throws CmsDataAccessException if something goes wrong 12350 */ 12351 private void updateState(CmsDbContext dbc, CmsResource resource, boolean resourceState) 12352 throws CmsDataAccessException { 12353 12354 CmsUUID projectId = ((dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) 12355 ? dbc.currentProject().getUuid() 12356 : dbc.getProjectId(); 12357 resource.setUserLastModified(dbc.currentUser().getId()); 12358 if (resourceState) { 12359 // update the whole resource state 12360 getVfsDriver(dbc).writeResource(dbc, projectId, resource, UPDATE_RESOURCE_STATE); 12361 } else { 12362 // update the structure state 12363 getVfsDriver(dbc).writeResource(dbc, projectId, resource, UPDATE_STRUCTURE_STATE); 12364 } 12365 } 12366 12367 /** 12368 * Wraps a driver object with a dynamic proxy that counts method calls and their durations.<p> 12369 * 12370 * @param newDriverInstance the driver instance to wrap 12371 * @return the proxy 12372 */ 12373 private Object wrapDriverInProfilingProxy(Object newDriverInstance) { 12374 12375 Class<?> cls = getDriverInterfaceForProxy(newDriverInstance); 12376 if (cls == null) { 12377 return newDriverInstance; 12378 } 12379 return Proxy.newProxyInstance( 12380 Thread.currentThread().getContextClassLoader(), 12381 new Class[] {cls}, 12382 new CmsProfilingInvocationHandler(newDriverInstance, CmsDefaultProfilingHandler.INSTANCE)); 12383 } 12384 12385}