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