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