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