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