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