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