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