All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.db.CmsDriverManager Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

The newest version!
/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software GmbH & Co. KG, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.db;

import org.opencms.ade.publish.CmsTooManyPublishResourcesException;
import org.opencms.configuration.CmsConfigurationManager;
import org.opencms.configuration.CmsParameterConfiguration;
import org.opencms.configuration.CmsSystemConfiguration;
import org.opencms.db.generic.CmsPublishHistoryCleanupFilter;
import org.opencms.db.generic.CmsUserDriver;
import org.opencms.db.log.CmsLogEntry;
import org.opencms.db.log.CmsLogEntryType;
import org.opencms.db.log.CmsLogFilter;
import org.opencms.db.timing.CmsDefaultProfilingHandler;
import org.opencms.db.timing.CmsProfilingInvocationHandler;
import org.opencms.db.urlname.CmsUrlNameMappingEntry;
import org.opencms.db.urlname.CmsUrlNameMappingFilter;
import org.opencms.db.userpublishlist.A_CmsLogPublishListConverter;
import org.opencms.db.userpublishlist.CmsLogPublishListConverterAllUsers;
import org.opencms.db.userpublishlist.CmsLogPublishListConverterCurrentUser;
import org.opencms.file.CmsDataAccessException;
import org.opencms.file.CmsFile;
import org.opencms.file.CmsFolder;
import org.opencms.file.CmsGroup;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsProject;
import org.opencms.file.CmsProperty;
import org.opencms.file.CmsPropertyDefinition;
import org.opencms.file.CmsRequestContext;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.CmsUser;
import org.opencms.file.CmsUserSearchParameters;
import org.opencms.file.CmsVfsException;
import org.opencms.file.CmsVfsResourceAlreadyExistsException;
import org.opencms.file.CmsVfsResourceNotFoundException;
import org.opencms.file.I_CmsResource;
import org.opencms.file.history.CmsHistoryFile;
import org.opencms.file.history.CmsHistoryFolder;
import org.opencms.file.history.CmsHistoryPrincipal;
import org.opencms.file.history.CmsHistoryProject;
import org.opencms.file.history.I_CmsHistoryResource;
import org.opencms.file.types.CmsResourceTypeFolder;
import org.opencms.file.types.CmsResourceTypeJsp;
import org.opencms.file.types.I_CmsResourceType;
import org.opencms.flex.CmsFlexRequestContextInfo;
import org.opencms.gwt.shared.alias.CmsAliasImportResult;
import org.opencms.gwt.shared.alias.CmsAliasImportStatus;
import org.opencms.gwt.shared.alias.CmsAliasMode;
import org.opencms.i18n.CmsLocaleManager;
import org.opencms.i18n.CmsMessageContainer;
import org.opencms.jsp.CmsJspNavBuilder;
import org.opencms.lock.CmsLock;
import org.opencms.lock.CmsLockException;
import org.opencms.lock.CmsLockFilter;
import org.opencms.lock.CmsLockManager;
import org.opencms.lock.CmsLockType;
import org.opencms.main.CmsEvent;
import org.opencms.main.CmsException;
import org.opencms.main.CmsIllegalArgumentException;
import org.opencms.main.CmsIllegalStateException;
import org.opencms.main.CmsInitException;
import org.opencms.main.CmsLog;
import org.opencms.main.CmsMultiException;
import org.opencms.main.I_CmsEventListener;
import org.opencms.main.OpenCms;
import org.opencms.module.CmsModule;
import org.opencms.monitor.CmsMemoryMonitor;
import org.opencms.monitor.CmsMemoryMonitor.CacheType;
import org.opencms.publish.CmsPublishEngine;
import org.opencms.publish.CmsPublishJobInfoBean;
import org.opencms.publish.CmsPublishReport;
import org.opencms.relations.CmsCategoryService;
import org.opencms.relations.CmsLink;
import org.opencms.relations.CmsRelation;
import org.opencms.relations.CmsRelationFilter;
import org.opencms.relations.CmsRelationSystemValidator;
import org.opencms.relations.CmsRelationType;
import org.opencms.relations.CmsRelationType.CopyBehavior;
import org.opencms.relations.I_CmsLinkParseable;
import org.opencms.report.CmsLogReport;
import org.opencms.report.I_CmsReport;
import org.opencms.security.CmsAccessControlEntry;
import org.opencms.security.CmsAccessControlList;
import org.opencms.security.CmsAuthentificationException;
import org.opencms.security.CmsOrganizationalUnit;
import org.opencms.security.CmsPasswordEncryptionException;
import org.opencms.security.CmsPermissionSet;
import org.opencms.security.CmsPermissionSetCustom;
import org.opencms.security.CmsPrincipal;
import org.opencms.security.CmsRole;
import org.opencms.security.CmsSecurityException;
import org.opencms.security.I_CmsPermissionHandler;
import org.opencms.security.I_CmsPermissionHandler.LockCheck;
import org.opencms.security.I_CmsPrincipal;
import org.opencms.security.twofactor.CmsSecondFactorInfo;
import org.opencms.security.twofactor.CmsSecondFactorSetupException;
import org.opencms.security.twofactor.CmsTwoFactorAuthenticationHandler;
import org.opencms.site.CmsSiteMatcher;
import org.opencms.util.CmsFileUtil;
import org.opencms.util.CmsPath;
import org.opencms.util.CmsStringUtil;
import org.opencms.util.CmsUUID;
import org.opencms.util.PrintfFormat;
import org.opencms.workflow.CmsDefaultWorkflowManager;
import org.opencms.workplace.threads.A_CmsProgressThread;

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;

import org.apache.commons.logging.Log;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;

/**
 * The OpenCms driver manager.

* * @since 6.0.0 */ public final class CmsDriverManager implements I_CmsEventListener { /** * Enum for distinguishing between login modes. */ public static enum LoginUserMode { /** Check mode, where the user is not logged in, but the password check and other checks are still done (however not the second factor check for 2FA). */ checkOnly, /** Normal login process. */ standard } /** * Resource list which additionally knows whether it should be cacheable in the resource list cache or not. */ public static class ResourceListWithCacheability extends ArrayList { /** Serial version id. */ private static final long serialVersionUID = 1L; /** True if the list should be cacheable. */ private boolean m_cacheable = true; /** * Creates a new instance. */ public ResourceListWithCacheability() { super(); } /** * Creates a new instance. * @param initialCapacity the initial capacity */ public ResourceListWithCacheability(int initialCapacity) { super(initialCapacity); } /** * Returns true if the resource list is cacheable. * * @return true if the list is cacheable */ public boolean isCacheable() { return m_cacheable; } /** * Enables/disables cacheability for the resource list. * @param cacheable true if the list should be cacheable */ public void setCacheable(boolean cacheable) { m_cacheable = cacheable; } } /** * Special key class for caching the resource OU data with a Guava LoadingCache.

* * In principle, the actual cache key is just the current project, but because of how cache loaders work, * the key must contain everything that varies between calls and is required to load the value. So we also store the DB context * for use by the cache loader. The project (offline/online) must still be stored, because the DB context gets invalidated * eventually, i.e. its project id gets nulled. */ public static class ResourceOUCacheKey { /** The actual cache key. */ private String m_actualKey; /** The DB context. */ private CmsDbContext m_dbc; /** The driver manager to use. */ private CmsDriverManager m_driverManager; /** * Creates a new instance. * * @param driverManager the driver manager to use * @param dbc the current DB context */ public ResourceOUCacheKey(CmsDriverManager driverManager, CmsDbContext dbc) { m_dbc = dbc; m_driverManager = driverManager; m_actualKey = CmsProject.ONLINE_PROJECT_ID.equals(dbc.currentProject().getId()) ? "ONLINE" : "OFFLINE"; } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { return (obj instanceof ResourceOUCacheKey) && ((ResourceOUCacheKey)obj).getActualKey().equals(getActualKey()); } /** * Gets the stored DB context.

* * Note that the DB contex returned by this may have been invalidated! * * @return the stored DB context */ public CmsDbContext getDbContext() { return m_dbc; } /** * Gets the current driver manager. * * @return the driver manager to use **/ public CmsDriverManager getDriverManager() { return m_driverManager; } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return getActualKey().hashCode(); } /** * Gets the actual key data. * * @return the actual key data */ private String getActualKey() { return m_actualKey; } } /** * Helper class used to store information about resources assigned to OUs in a cache. */ public static class ResourceOUMap { /** Multimap from the paths of resources to the OUs to which they are assigned as OU resources. */ private Multimap m_ousByAssignedResourcePaths = ArrayListMultimap.create(); /** The organizational units, with their UUIDs as keys. */ private Map m_ousById = new HashMap<>(); /** * Gets the list of organizational units to which a given root path belongs, according to the cached * OU resource assignments. * * @param rootPath the root path * @return the organizational units to which the path belongs */ public List getResourceOrgUnits(String rootPath) { Set result = new HashSet<>(); String currentPath = rootPath; while (currentPath != null) { result.addAll(m_ousByAssignedResourcePaths.get(new CmsPath(currentPath))); currentPath = CmsResource.getParentFolder(currentPath); } return new ArrayList<>(result); } /** * Reads the OU resource data from the VFS and initializes this instance with it. * * @param driverManager the driver manager to use * @param dbc the current DB context * @throws CmsException if something goes wrong */ public void init(CmsDriverManager driverManager, CmsDbContext dbc) throws CmsException { List relations = driverManager.getRelationsForResource( dbc, null, CmsRelationFilter.ALL.filterType(CmsRelationType.OU_RESOURCE)); CmsOrganizationalUnit root = driverManager.readOrganizationalUnit(dbc, ""); List children = driverManager.getOrganizationalUnits(dbc, root, true); Set ous = new HashSet<>(); ous.add(root); ous.addAll(children); init(relations, ous); } /** * Initializes the OU resource data. * * @param ouRelations the current list of OU relations * @param ous the current list of OUs */ public void init(Collection ouRelations, Collection ous) { m_ousById.clear(); m_ousByAssignedResourcePaths.clear(); for (CmsOrganizationalUnit ou : ous) { m_ousById.put(ou.getId(), ou); } for (CmsRelation rel : ouRelations) { CmsOrganizationalUnit ou = m_ousById.get(rel.getSourceId()); if (ou != null) { m_ousByAssignedResourcePaths.put(new CmsPath(rel.getTargetPath()), ou); } } } } /** * The comparator used for comparing url name mapping entries by date.

*/ class UrlNameMappingComparator implements Comparator { /** * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ public int compare(CmsUrlNameMappingEntry o1, CmsUrlNameMappingEntry o2) { long date1 = o1.getDateChanged(); long date2 = o2.getDateChanged(); if (date1 < date2) { return -1; } if (date1 > date2) { return +1; } return 0; } } /** * Enumeration class for the mode parameter in the * {@link CmsDriverManager#readChangedResourcesInsideProject(CmsDbContext, CmsUUID, CmsReadChangedProjectResourceMode)} * method.

*/ private static class CmsReadChangedProjectResourceMode { /** * Default constructor.

*/ protected CmsReadChangedProjectResourceMode() { // noop } } /** Request context attribute used to override the time used for time-based exclusive access checks. */ public static final String ATTR_EXCLUSIVE_ACCESS_CLOCK = "ATTR_EXCLUSIVE_ACCESS_CLOCK"; /** Attribute for signaling to the user driver that a specific OU should be initialized by fillDefaults. */ public static final String ATTR_INIT_OU = "INIT_OU"; /** DB context attribute used to communicate information about resource cacheability between various methods. */ public static final String ATTR_PERMISSION_NOCACHE = "ATTR_PERMISSION_NOCACHE"; /** Attribute login. */ public static final String ATTRIBUTE_LOGIN = "A_LOGIN"; /** Cache key for all properties. */ public static final String CACHE_ALL_PROPERTIES = "_CAP_"; /** * Values indicating changes of a resource, * ordered according to the scope of the change. */ /** Value to indicate a change in access control entries of a resource. */ public static final int CHANGED_ACCESSCONTROL = 1; /** Value to indicate a content change. */ public static final int CHANGED_CONTENT = 16; /** Value to indicate a change in the lastmodified settings of a resource. */ public static final int CHANGED_LASTMODIFIED = 4; /** Value to indicate a project change. */ public static final int CHANGED_PROJECT = 32; /** Value to indicate a change in the resource data. */ public static final int CHANGED_RESOURCE = 8; /** Value to indicate a change in the availability timeframe. */ public static final int CHANGED_TIMEFRAME = 2; /** "cache" string in the configuration-file. */ public static final String CONFIGURATION_CACHE = "cache"; /** "db" string in the configuration-file. */ public static final String CONFIGURATION_DB = "db"; /** "driver.history" string in the configuration-file. */ public static final String CONFIGURATION_HISTORY = "driver.history"; /** "driver.project" string in the configuration-file. */ public static final String CONFIGURATION_PROJECT = "driver.project"; /** "subscription.vfs" string in the configuration file. */ public static final String CONFIGURATION_SUBSCRIPTION = "driver.subscription"; /** "driver.user" string in the configuration-file. */ public static final String CONFIGURATION_USER = "driver.user"; /** "driver.vfs" string in the configuration-file. */ public static final String CONFIGURATION_VFS = "driver.vfs"; /** DBC attribute key needed to fix publishing behavior involving siblings. */ public static final String KEY_CHANGED_AND_DELETED = "changedAndDeleted"; /** The vfs path of the loast and found folder. */ public static final String LOST_AND_FOUND_FOLDER = "/system/lost-found"; /** The maximum length of a VFS resource path. */ public static final int MAX_VFS_RESOURCE_PATH_LENGTH = 512; /** Key for indicating no changes. */ public static final int NOTHING_CHANGED = 0; /** Name of the configuration parameter to enable/disable logging to the CMS_LOG table. */ public static final String PARAM_LOG_TABLE_ENABLED = "log.table.enabled"; /** Indicates to ignore the resource path when matching resources. */ public static final String READ_IGNORE_PARENT = null; /** Indicates to ignore the time value. */ public static final long READ_IGNORE_TIME = 0L; /** Indicates to ignore the resource type when matching resources. */ public static final int READ_IGNORE_TYPE = -1; /** Indicates to match resources NOT having the given state. */ public static final int READMODE_EXCLUDE_STATE = 8; /** Indicates to match immediate children only. */ public static final int READMODE_EXCLUDE_TREE = 1; /** Indicates to match resources NOT having the given type. */ public static final int READMODE_EXCLUDE_TYPE = 4; /** Mode for reading project resources from the db. */ public static final int READMODE_IGNORESTATE = 0; /** Indicates to match resources in given project only. */ public static final int READMODE_INCLUDE_PROJECT = 2; /** Indicates to match all successors. */ public static final int READMODE_INCLUDE_TREE = 0; /** Mode for reading project resources from the db. */ public static final int READMODE_MATCHSTATE = 1; /** Indicates if only file resources should be read. */ public static final int READMODE_ONLY_FILES = 128; /** Indicates if only folder resources should be read. */ public static final int READMODE_ONLY_FOLDERS = 64; /** Mode for reading project resources from the db. */ public static final int READMODE_UNMATCHSTATE = 2; /** Flag that can be used to disable the resource OU caching if necessary. */ public static boolean resourceOrgUnitCachingEnabled = true; /** Prefix char for temporary files in the VFS. */ public static final String TEMP_FILE_PREFIX = "~"; /** Key to indicate complete update. */ public static final int UPDATE_ALL = 3; /** Key to indicate update of resource record. */ public static final int UPDATE_RESOURCE = 4; /** Key to indicate update of last modified project reference. */ public static final int UPDATE_RESOURCE_PROJECT = 6; /** Key to indicate update of resource state. */ public static final int UPDATE_RESOURCE_STATE = 1; /** Key to indicate update of resource state including the content date. */ public static final int UPDATE_RESOURCE_STATE_CONTENT = 7; /** Key to indicate update of structure record. */ public static final int UPDATE_STRUCTURE = 5; /** Key to indicate update of structure state. */ public static final int UPDATE_STRUCTURE_STATE = 2; /** Map of pools defined in opencms.properties. */ protected static ConcurrentMap m_pools = Maps.newConcurrentMap(); /** The log object for this class. */ private static final Log LOG = CmsLog.getLog(CmsDriverManager.class); /** Constant mode parameter to read all files and folders in the {@link #readChangedResourcesInsideProject(CmsDbContext, CmsUUID, CmsReadChangedProjectResourceMode)}} method. */ private static final CmsReadChangedProjectResourceMode RCPRM_FILES_AND_FOLDERS_MODE = new CmsReadChangedProjectResourceMode(); /** Constant mode parameter to read all files and folders in the {@link #readChangedResourcesInsideProject(CmsDbContext, CmsUUID, CmsReadChangedProjectResourceMode)}} method. */ private static final CmsReadChangedProjectResourceMode RCPRM_FILES_ONLY_MODE = new CmsReadChangedProjectResourceMode(); /** Constant mode parameter to read all files and folders in the {@link #readChangedResourcesInsideProject(CmsDbContext, CmsUUID, CmsReadChangedProjectResourceMode)}} method. */ private static final CmsReadChangedProjectResourceMode RCPRM_FOLDERS_ONLY_MODE = new CmsReadChangedProjectResourceMode(); /** The history driver. */ private I_CmsHistoryDriver m_historyDriver; /** The HTML link validator. */ private CmsRelationSystemValidator m_htmlLinkValidator; /** The class used for cache key generation. */ private I_CmsCacheKey m_keyGenerator; /** The lock manager. */ private CmsLockManager m_lockManager; /** The log entry cache. */ private List m_log = new ArrayList(); /** Local reference to the memory monitor to avoid multiple lookups through the OpenCms singleton. */ private CmsMemoryMonitor m_monitor; /** The project driver. */ private I_CmsProjectDriver m_projectDriver; /** The the configuration read from the opencms.properties file. */ private CmsParameterConfiguration m_propertyConfiguration; /** the publish engine. */ private CmsPublishEngine m_publishEngine; /** Object used for synchronizing updates to the user publish list. */ private Object m_publishListUpdateLock = new Object(); /** The security manager (for access checks). */ private CmsSecurityManager m_securityManager; /** The sql manager. */ private CmsSqlManager m_sqlManager; /** The subscription driver. */ private I_CmsSubscriptionDriver m_subscriptionDriver; /** The user driver. */ private I_CmsUserDriver m_userDriver; /** The VFS driver. */ private I_CmsVfsDriver m_vfsDriver; /** * Private constructor, initializes some required member variables.

*/ private CmsDriverManager() { // intentionally left blank } /** * Reads the required configurations from the opencms.properties file and creates * the various drivers to access the cms resources.

* * The initialization process of the driver manager and its drivers is split into * the following phases: *

    *
  • the database pool configuration is read
  • *
  • a plain and empty driver manager instance is created
  • *
  • an instance of each driver is created
  • *
  • the driver manager is passed to each driver during initialization
  • *
  • finally, the driver instances are passed to the driver manager during initialization
  • *
* * @param configurationManager the configuration manager * @param securityManager the security manager * @param runtimeInfoFactory the initialized OpenCms runtime info factory * @param publishEngine the publish engine * * @return CmsDriverManager the instantiated driver manager * @throws CmsInitException if the driver manager couldn't be instantiated */ public static CmsDriverManager newInstance( CmsConfigurationManager configurationManager, CmsSecurityManager securityManager, I_CmsDbContextFactory runtimeInfoFactory, CmsPublishEngine publishEngine) throws CmsInitException { // read the opencms.properties from the configuration CmsParameterConfiguration config = configurationManager.getConfiguration(); CmsDriverManager driverManager = null; try { // create a driver manager instance driverManager = new CmsDriverManager(); if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_PHASE1_0)); } if (runtimeInfoFactory == null) { throw new CmsInitException( org.opencms.main.Messages.get().container(org.opencms.main.Messages.ERR_CRITICAL_NO_DB_CONTEXT_0)); } } catch (Exception exc) { CmsMessageContainer message = Messages.get().container(Messages.LOG_ERR_DRIVER_MANAGER_START_0); if (LOG.isFatalEnabled()) { LOG.fatal(message.key(), exc); } throw new CmsInitException(message, exc); } // store the configuration driverManager.m_propertyConfiguration = config; // set the security manager driverManager.m_securityManager = securityManager; // set the lock manager driverManager.m_lockManager = new CmsLockManager(driverManager); // create and set the sql manager driverManager.m_sqlManager = new CmsSqlManager(driverManager); // set the publish engine driverManager.m_publishEngine = publishEngine; if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_PHASE2_0)); } // read the pool names to initialize List driverPoolNames = config.getList(CmsDriverManager.CONFIGURATION_DB + ".pools"); if (CmsLog.INIT.isInfoEnabled()) { String names = ""; for (String name : driverPoolNames) { names += name + " "; } CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_POOLS_1, names)); } // initialize each pool for (String name : driverPoolNames) { driverManager.newPoolInstance(config, name); } // initialize the runtime info factory with the generated driver manager runtimeInfoFactory.initialize(driverManager); if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_PHASE3_0)); } // store the access objects CmsDbContext dbc = runtimeInfoFactory.getDbContext(); driverManager.m_vfsDriver = (I_CmsVfsDriver)driverManager.createDriver( dbc, configurationManager, config, CONFIGURATION_VFS, ".vfs.driver"); dbc.clear(); dbc = runtimeInfoFactory.getDbContext(); driverManager.m_userDriver = (I_CmsUserDriver)driverManager.createDriver( dbc, configurationManager, config, CONFIGURATION_USER, ".user.driver"); dbc.clear(); dbc = runtimeInfoFactory.getDbContext(); driverManager.m_projectDriver = (I_CmsProjectDriver)driverManager.createDriver( dbc, configurationManager, config, CONFIGURATION_PROJECT, ".project.driver"); dbc.clear(); dbc = runtimeInfoFactory.getDbContext(); driverManager.m_historyDriver = (I_CmsHistoryDriver)driverManager.createDriver( dbc, configurationManager, config, CONFIGURATION_HISTORY, ".history.driver"); dbc.clear(); dbc = runtimeInfoFactory.getDbContext(); try { // we wrap this in a try-catch because otherwise it would fail during the update // process, since the subscription driver configuration does not exist at that point. driverManager.m_subscriptionDriver = (I_CmsSubscriptionDriver)driverManager.createDriver( dbc, configurationManager, config, CONFIGURATION_SUBSCRIPTION, ".subscription.driver"); } catch (IndexOutOfBoundsException npe) { LOG.warn("Could not instantiate subscription driver!"); LOG.warn(npe.getLocalizedMessage(), npe); } dbc.clear(); // register the driver manager for required events org.opencms.main.OpenCms.addCmsEventListener( driverManager, new int[] { I_CmsEventListener.EVENT_UPDATE_EXPORTS, I_CmsEventListener.EVENT_CLEAR_CACHES, I_CmsEventListener.EVENT_CLEAR_PRINCIPAL_CACHES, I_CmsEventListener.EVENT_USER_MODIFIED, I_CmsEventListener.EVENT_PUBLISH_PROJECT}); // return the configured driver manager return driverManager; } /** * Adds an alias entry.

* * @param dbc the database context * @param project the current project * @param alias the alias to add * * @throws CmsException if something goes wrong */ public void addAlias(CmsDbContext dbc, CmsProject project, CmsAlias alias) throws CmsException { I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); vfsDriver.insertAlias(dbc, project, alias); } /** * Adds a new relation to the given resource.

* * @param dbc the database context * @param resource the resource to add the relation to * @param target the target of the relation * @param type the type of the relation * @param importCase if importing relations * * @throws CmsException if something goes wrong */ public void addRelationToResource( CmsDbContext dbc, CmsResource resource, CmsResource target, CmsRelationType type, boolean importCase) throws CmsException { if (type.isDefinedInContent()) { throw new CmsIllegalArgumentException( Messages.get().container( Messages.ERR_ADD_RELATION_IN_CONTENT_3, dbc.removeSiteRoot(resource.getRootPath()), dbc.removeSiteRoot(target.getRootPath()), type.getLocalizedName(dbc.getRequestContext().getLocale()))); } CmsRelation relation = new CmsRelation(resource, target, type); getVfsDriver(dbc).createRelation(dbc, dbc.currentProject().getUuid(), relation); if (importCase) { // fire the reindexing event, since - if offline indexing is not stopped, // the content could be indexed without relations already and thus miss categories. Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_PROJECTID, dbc.currentProject().getId()); data.put(I_CmsEventListener.KEY_RESOURCES, Collections.singletonList(resource)); I_CmsReport report = null; if (dbc.getRequestContext() != null) { report = new CmsLogReport(dbc.getRequestContext().getLocale(), getClass()); } else { report = new CmsLogReport(CmsLocaleManager.getDefaultLocale(), getClass()); } data.put(I_CmsEventListener.KEY_REPORT, report); data.put(I_CmsEventListener.KEY_REINDEX_RELATED, Boolean.TRUE); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_REINDEX_OFFLINE, data)); } else { // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_ADD_RELATION, new String[] {relation.getSourcePath(), relation.getTargetPath()}), false); // touch the resource setDateLastModified(dbc, resource, System.currentTimeMillis()); } } /** * Adds a resource to the given organizational unit.

* * @param dbc the current db context * @param orgUnit the organizational unit to add the resource to * @param resource the resource that is to be added to the organizational unit * * @throws CmsException if something goes wrong * * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String) * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String) */ public void addResourceToOrgUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, CmsResource resource) throws CmsException { m_monitor.flushCache(CmsMemoryMonitor.CacheType.HAS_ROLE, CmsMemoryMonitor.CacheType.ROLE_LIST); getUserDriver(dbc).addResourceToOrganizationalUnit(dbc, orgUnit, resource); } /** * Adds a user to a group.

* * @param dbc the current database context * @param username the name of the user that is to be added to the group * @param groupname the name of the group * @param readRoles if reading roles or groups * * @throws CmsException if operation was not successful * @throws CmsDbEntryNotFoundException if the given user or the given group was not found * * @see #removeUserFromGroup(CmsDbContext, String, String, boolean) */ public void addUserToGroup(CmsDbContext dbc, String username, String groupname, boolean readRoles) throws CmsException, CmsDbEntryNotFoundException { //check if group exists CmsGroup group = readGroup(dbc, groupname); if (group == null) { // the group does not exists throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, groupname)); } if (group.isVirtual() && !readRoles) { String roleName = CmsRole.valueOf(group).getGroupName(); if (!userInGroup(dbc, username, roleName, true)) { addUserToGroup(dbc, username, roleName, true); return; } } if (group.isVirtual()) { // this is an hack to prevent unlimited recursive calls readRoles = false; } if ((readRoles && !group.isRole()) || (!readRoles && group.isRole())) { // we want a role but we got a group, or the other way throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, groupname)); } if (userInGroup(dbc, username, groupname, readRoles)) { // the user is already member of the group return; } //check if the user exists CmsUser user = readUser(dbc, username); if (user == null) { // the user does not exists throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_USER_1, username)); } // if adding an user to a role if (readRoles) { CmsRole role = CmsRole.valueOf(group); // a role can only be set if the user has the given role m_securityManager.checkRole(dbc, role); // now we check if we already have the role if (m_securityManager.hasRole(dbc, user, role)) { // do nothing return; } // and now we need to remove all possible child-roles List children = role.getChildren(true); Iterator itUserGroups = getGroupsOfUser( dbc, username, group.getOuFqn(), true, true, true, dbc.getRequestContext().getRemoteAddress()).iterator(); while (itUserGroups.hasNext()) { CmsGroup roleGroup = itUserGroups.next(); if (children.contains(CmsRole.valueOf(roleGroup))) { // remove only child roles removeUserFromGroup(dbc, username, roleGroup.getName(), true); } } // update virtual groups Iterator it = getVirtualGroupsForRole(dbc, role).iterator(); while (it.hasNext()) { CmsGroup virtualGroup = it.next(); // here we say readroles = true, to prevent an unlimited recursive calls addUserToGroup(dbc, username, virtualGroup.getName(), true); } } //add this user to the group getUserDriver(dbc).createUserInGroup(dbc, user.getId(), group.getId()); // flush the cache if (readRoles) { m_monitor.flushCache(CmsMemoryMonitor.CacheType.HAS_ROLE, CmsMemoryMonitor.CacheType.ROLE_LIST); } m_monitor.flushUserGroups(user.getId()); m_monitor.flushCache(CmsMemoryMonitor.CacheType.USER_LIST); if (!dbc.getProjectId().isNullUUID() && !CmsProject.ONLINE_PROJECT_ID.equals(dbc.getProjectId())) { // user modified event is not needed return; } // fire user modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); eventData.put(I_CmsEventListener.KEY_USER_NAME, user.getName()); eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); eventData.put(I_CmsEventListener.KEY_GROUP_NAME, group.getName()); eventData.put( I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_ADD_USER_TO_GROUP); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); } /** * Changes the lock of a resource to the current user, * that is "steals" the lock from another user.

* * @param dbc the current database context * @param resource the resource to change the lock for * @param lockType the new lock type to set * * @throws CmsException if something goes wrong * @throws CmsSecurityException if something goes wrong * * * @see CmsObject#changeLock(String) * @see I_CmsResourceType#changeLock(CmsObject, CmsSecurityManager, CmsResource) * * @see CmsSecurityManager#hasPermissions(CmsRequestContext, CmsResource, CmsPermissionSet, boolean, CmsResourceFilter) */ public void changeLock(CmsDbContext dbc, CmsResource resource, CmsLockType lockType) throws CmsException, CmsSecurityException { // get the current lock CmsLock currentLock = getLock(dbc, resource); // check if the resource is locked at all if (currentLock.getEditionLock().isUnlocked() && currentLock.getSystemLock().isUnlocked()) { throw new CmsLockException( Messages.get().container( Messages.ERR_CHANGE_LOCK_UNLOCKED_RESOURCE_1, dbc.getRequestContext().getSitePath(resource))); } else if ((lockType == CmsLockType.EXCLUSIVE) && currentLock.isExclusiveOwnedInProjectBy(dbc.currentUser(), dbc.currentProject())) { // the current lock requires no change return; } // duplicate logic from CmsSecurityManager#hasPermissions() because lock state can't be ignored // if another user has locked the file, the current user can never get WRITE permissions with the default check int denied = 0; // check if the current user is vfs manager boolean canIgnorePermissions = m_securityManager.hasRoleForResource( dbc, dbc.currentUser(), CmsRole.VFS_MANAGER, resource); // if the resource type is jsp // write is only allowed for developers if (!canIgnorePermissions && (CmsResourceTypeJsp.isJsp(resource))) { if (!m_securityManager.hasRoleForResource(dbc, dbc.currentUser(), CmsRole.VFS_MANAGER, resource)) { denied |= CmsPermissionSet.PERMISSION_WRITE; } } CmsPermissionSetCustom permissions; if (canIgnorePermissions) { // if the current user is administrator, anything is allowed permissions = new CmsPermissionSetCustom(~0); } else { // otherwise, get the permissions from the access control list permissions = getPermissions(dbc, resource, dbc.currentUser()); } // revoke the denied permissions permissions.denyPermissions(denied); // now check if write permission is granted if ((CmsPermissionSet.ACCESS_WRITE.getPermissions() & permissions.getPermissions()) != CmsPermissionSet.ACCESS_WRITE.getPermissions()) { // check failed, throw exception m_securityManager.checkPermissions( dbc.getRequestContext(), resource, CmsPermissionSet.ACCESS_WRITE, I_CmsPermissionHandler.PERM_DENIED); } // if we got here write permission is granted on the target // remove the old lock m_lockManager.removeResource(dbc, resource, true, lockType.isSystem()); // apply the new lock lockResource(dbc, resource, lockType); } /** * Returns a list with all sub resources of a given folder that have set the given property, * matching the current property's value with the given old value and replacing it by a given new value.

* * @param dbc the current database context * @param resource the resource on which property definition values are changed * @param propertyDefinition the name of the propertydefinition to change the value * @param oldValue the old value of the propertydefinition * @param newValue the new value of the propertydefinition * @param recursive if true, change the property value on the resource and recursively all property values on * sub-resources (only for folders) * @return a list with the {@link CmsResource}'s where the property value has been changed * * @throws CmsVfsException for now only when the search for the oldvalue failed. * @throws CmsException if operation was not successful */ public List changeResourcesInFolderWithProperty( CmsDbContext dbc, CmsResource resource, String propertyDefinition, String oldValue, String newValue, boolean recursive) throws CmsVfsException, CmsException { CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION; // collect the resources to look up List resources = new ArrayList(); if (recursive) { // read the files in the folder resources = readResourcesWithProperty(dbc, resource, propertyDefinition, null, filter); // add the folder itself resources.add(resource); } else { resources.add(resource); } Pattern oldPattern; try { // remove the place holder if available String tmpOldValue = oldValue; if (tmpOldValue.contains(CmsStringUtil.PLACEHOLDER_START) && tmpOldValue.contains(CmsStringUtil.PLACEHOLDER_END)) { tmpOldValue = tmpOldValue.replace(CmsStringUtil.PLACEHOLDER_START, ""); tmpOldValue = tmpOldValue.replace(CmsStringUtil.PLACEHOLDER_END, ""); } // compile regular expression pattern oldPattern = Pattern.compile(tmpOldValue); } catch (PatternSyntaxException e) { throw new CmsVfsException( Messages.get().container( Messages.ERR_CHANGE_RESOURCES_IN_FOLDER_WITH_PROP_4, new Object[] {propertyDefinition, oldValue, newValue, resource.getRootPath()}), e); } List changedResources = new ArrayList(resources.size()); // create permission set and filter to check each resource CmsPermissionSet perm = CmsPermissionSet.ACCESS_WRITE; for (int i = 0; i < resources.size(); i++) { // loop through found resources and check property values CmsResource res = resources.get(i); // check resource state and permissions try { m_securityManager.checkPermissions(dbc, res, perm, true, filter); } catch (Exception e) { // resource is deleted or not writable for current user continue; } CmsProperty property = readPropertyObject(dbc, res, propertyDefinition, false); String propertyValue = property.getValue(); boolean changed = false; if ((propertyValue != null) && oldPattern.matcher(propertyValue).matches()) { // apply the place holder content String tmpNewValue = CmsStringUtil.transformValues(oldValue, newValue, propertyValue); // change structure value property.setStructureValue(tmpNewValue); changed = true; } if (changed) { // write property object if something has changed writePropertyObject(dbc, res, property); changedResources.add(res); } } return changedResources; } /** * Changes the resource flags of a resource.

* * The resource flags are used to indicate various "special" conditions * for a resource. Most notably, the "internal only" setting which signals * that a resource can not be directly requested with it's URL.

* * @param dbc the current database context * @param resource the resource to change the flags for * @param flags the new resource flags for this resource * * @throws CmsException if something goes wrong * * @see CmsObject#chflags(String, int) * @see I_CmsResourceType#chflags(CmsObject, CmsSecurityManager, CmsResource, int) */ public void chflags(CmsDbContext dbc, CmsResource resource, int flags) throws CmsException { // must operate on a clone to ensure resource is not modified in case permissions are not granted CmsResource clone = (CmsResource)resource.clone(); clone.setFlags(flags); // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_FLAGS, new String[] {resource.getRootPath()}), false); // write it writeResource(dbc, clone); } /** * Changes the resource type of a resource.

* * OpenCms handles resources according to the resource type, * not the file suffix. This is e.g. why a JSP in OpenCms can have the * suffix ".html" instead of ".jsp" only. Changing the resource type * makes sense e.g. if you want to make a plain text file a JSP resource, * or a binary file an image, etc.

* * @param dbc the current database context * @param resource the resource to change the type for * @param type the new resource type for this resource * * @throws CmsException if something goes wrong * * @see CmsObject#chtype(String, int) * @see I_CmsResourceType#chtype(CmsObject, CmsSecurityManager, CmsResource, int) */ @SuppressWarnings({"javadoc", "deprecation"}) public void chtype(CmsDbContext dbc, CmsResource resource, int type) throws CmsException { // must operate on a clone to ensure resource is not modified in case permissions are not granted CmsResource clone = (CmsResource)resource.clone(); I_CmsResourceType newType = OpenCms.getResourceManager().getResourceType(type); clone.setType(newType.getTypeId()); // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_TYPE, new String[] {resource.getRootPath()}), false); // write it writeResource(dbc, clone); } /** * Cleans up the publish history entries according to the given filter. * * @param dbc the database context * @param filter the filter * @return the number of cleaned up rows * @throws CmsDataAccessException if something goes wrong */ public int cleanupPublishHistory(CmsDbContext dbc, CmsPublishHistoryCleanupFilter filter) throws CmsDataAccessException { int result = m_projectDriver.cleanupPublishHistory(dbc, filter); if (filter.getMode() == CmsPublishHistoryCleanupFilter.Mode.single) { OpenCms.getMemoryMonitor().cachePublishedResources(filter.getHistoryId().toString(), null); } else { OpenCms.getMemoryMonitor().flushCache(CmsMemoryMonitor.CacheType.PUBLISHED_RESOURCES); } return result; } /** * @see org.opencms.main.I_CmsEventListener#cmsEvent(org.opencms.main.CmsEvent) */ public void cmsEvent(CmsEvent event) { if (LOG.isDebugEnabled()) { LOG.debug(Messages.get().getBundle().key(Messages.LOG_CMS_EVENT_1, Integer.valueOf(event.getType()))); } I_CmsReport report; CmsDbContext dbc; switch (event.getType()) { case I_CmsEventListener.EVENT_UPDATE_EXPORTS: dbc = (CmsDbContext)event.getData().get(I_CmsEventListener.KEY_DBCONTEXT); updateExportPoints(dbc); break; case I_CmsEventListener.EVENT_PUBLISH_PROJECT: CmsUUID publishHistoryId = new CmsUUID((String)event.getData().get(I_CmsEventListener.KEY_PUBLISHID)); report = (I_CmsReport)event.getData().get(I_CmsEventListener.KEY_REPORT); dbc = (CmsDbContext)event.getData().get(I_CmsEventListener.KEY_DBCONTEXT); m_monitor.clearCacheForPublishing(); writeExportPoints(dbc, report, publishHistoryId); break; case I_CmsEventListener.EVENT_CLEAR_CACHES: m_monitor.clearCache(); break; case I_CmsEventListener.EVENT_CLEAR_PRINCIPAL_CACHES: m_monitor.clearPrincipalsCache(); break; case I_CmsEventListener.EVENT_USER_MODIFIED: String action = (String)event.getData().get(I_CmsEventListener.KEY_USER_ACTION); m_monitor.flushCache( CacheType.USER, CacheType.GROUP, CacheType.ORG_UNIT, CacheType.ACL, CacheType.PERMISSION, CacheType.USER_LIST); if (I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_ADD_USER_TO_GROUP.equals(action) || I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_REMOVE_USER_FROM_GROUP.equals(action) || I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_SET_OU.equals(action)) { Object userIdObj = event.getData().get(I_CmsEventListener.KEY_USER_ID); if (userIdObj != null) { CmsUUID userId = null; if (userIdObj instanceof CmsUUID) { userId = (CmsUUID)userIdObj; } else if (userIdObj instanceof String) { try { userId = new CmsUUID(userIdObj.toString()); } catch (Exception e) { LOG.error(e.getLocalizedMessage(), e); } } if (userId != null) { m_monitor.flushUserGroups(userId); } } else { m_monitor.flushCache(CacheType.USERGROUPS); } m_monitor.flushCache(CacheType.HAS_ROLE, CacheType.ROLE_LIST); } break; default: // noop } } /** * Copies the access control entries of a given resource to a destination resource.

* * Already existing access control entries of the destination resource are removed.

* * @param dbc the current database context * @param source the resource to copy the access control entries from * @param destination the resource to which the access control entries are copied * @param updateLastModifiedInfo if true, user and date "last modified" information on the target resource will be updated * * @throws CmsException if something goes wrong */ public void copyAccessControlEntries( CmsDbContext dbc, CmsResource source, CmsResource destination, boolean updateLastModifiedInfo) throws CmsException { // get the entries to copy ListIterator aceList = getUserDriver( dbc).readAccessControlEntries(dbc, dbc.currentProject(), source.getResourceId(), false).listIterator(); // remove the current entries from the destination getUserDriver(dbc).removeAccessControlEntries(dbc, dbc.currentProject(), destination.getResourceId()); // now write the new entries while (aceList.hasNext()) { CmsAccessControlEntry ace = aceList.next(); getUserDriver(dbc).createAccessControlEntry( dbc, dbc.currentProject(), destination.getResourceId(), ace.getPrincipal(), ace.getPermissions().getAllowedPermissions(), ace.getPermissions().getDeniedPermissions(), ace.getFlags()); } // log it log( dbc, new CmsLogEntry( dbc, destination.getStructureId(), CmsLogEntryType.RESOURCE_PERMISSIONS, new String[] {destination.getRootPath()}), false); // update the "last modified" information if (updateLastModifiedInfo) { setDateLastModified(dbc, destination, destination.getDateLastModified()); } // clear the cache m_monitor.clearAccessControlListCache(); // fire a resource modification event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, destination); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_ACCESSCONTROL)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Copies a resource.

* * You must ensure that the destination path is an absolute, valid and * existing VFS path. Relative paths from the source are currently not supported.

* * In case the target resource already exists, it is overwritten with the * source resource.

* * The siblingMode parameter controls how to handle siblings * during the copy operation. * Possible values for this parameter are: *

    *
  • {@link org.opencms.file.CmsResource#COPY_AS_NEW}
  • *
  • {@link org.opencms.file.CmsResource#COPY_AS_SIBLING}
  • *
  • {@link org.opencms.file.CmsResource#COPY_PRESERVE_SIBLING}
  • *

* * @param dbc the current database context * @param source the resource to copy * @param destination the name of the copy destination with complete path * @param siblingMode indicates how to handle siblings during copy * * @throws CmsException if something goes wrong * @throws CmsIllegalArgumentException if the source argument is null * * @see CmsObject#copyResource(String, String, CmsResource.CmsResourceCopyMode) * @see I_CmsResourceType#copyResource(CmsObject, CmsSecurityManager, CmsResource, String, CmsResource.CmsResourceCopyMode) */ public void copyResource( CmsDbContext dbc, CmsResource source, String destination, CmsResource.CmsResourceCopyMode siblingMode) throws CmsException, CmsIllegalArgumentException { // check the sibling mode to see if this resource has to be copied as a sibling boolean copyAsSibling = false; // siblings of folders are not supported if (!source.isFolder()) { // if the "copy as sibling" mode is used, set the flag to true if (siblingMode == CmsResource.COPY_AS_SIBLING) { copyAsSibling = true; } // if the mode is "preserve siblings", we have to check the sibling counter if (siblingMode == CmsResource.COPY_PRESERVE_SIBLING) { if (source.getSiblingCount() > 1) { copyAsSibling = true; } } } // read the source properties List properties = readPropertyObjects(dbc, source, false); if (copyAsSibling) { // create a sibling of the source file at the destination createSibling(dbc, source, destination, properties); // after the sibling is created the copy operation is finished return; } // prepare the content if required byte[] content = null; if (source.isFile()) { if (source instanceof CmsFile) { // resource already is a file content = ((CmsFile)source).getContents(); } if ((content == null) || (content.length < 1)) { // no known content yet - read from database content = getVfsDriver(dbc).readContent(dbc, dbc.currentProject().getUuid(), source.getResourceId()); } } // determine destination folder String destinationFoldername = CmsResource.getParentFolder(destination); // read the destination folder (will also check read permissions) CmsFolder destinationFolder = m_securityManager.readFolder( dbc, destinationFoldername, CmsResourceFilter.IGNORE_EXPIRATION); // no further permission check required here, will be done in createResource() // set user and creation time stamps long currentTime = System.currentTimeMillis(); long dateLastModified; CmsUUID userLastModified; if (source.isFolder()) { // folders always get a new date and user when they are copied dateLastModified = currentTime; userLastModified = dbc.currentUser().getId(); } else { // files keep the date and user last modified from the source dateLastModified = source.getDateLastModified(); userLastModified = source.getUserLastModified(); } // check the resource flags int flags = source.getFlags(); if (source.isLabeled()) { // reset "labeled" link flag for new resource flags &= ~CmsResource.FLAG_LABELED; } // create the new resource CmsResource newResource = new CmsResource( new CmsUUID(), new CmsUUID(), destination, source.getTypeId(), source.isFolder(), flags, dbc.currentProject().getUuid(), CmsResource.STATE_NEW, currentTime, dbc.currentUser().getId(), dateLastModified, userLastModified, source.getDateReleased(), source.getDateExpired(), 1, source.getLength(), source.getDateContent(), source.getVersion()); // version number does not matter since it will be computed later // trigger "is touched" state on resource (will ensure modification date is kept unchanged) newResource.setDateLastModified(dateLastModified); // log it log( dbc, new CmsLogEntry( dbc, newResource.getStructureId(), CmsLogEntryType.RESOURCE_COPIED, new String[] {newResource.getRootPath()}), false); // create the resource newResource = createResource(dbc, destination, newResource, content, properties, false); // copy relations copyRelations(dbc, source, newResource); // copy the access control entries to the created resource copyAccessControlEntries(dbc, source, newResource, false); // clear the cache m_monitor.clearAccessControlListCache(); List modifiedResources = new ArrayList(); modifiedResources.add(source); modifiedResources.add(newResource); modifiedResources.add(destinationFolder); OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCE_COPIED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCES, modifiedResources))); } /** * Copies a resource to the current project of the user.

* * @param dbc the current database context * @param resource the resource to apply this operation to * * @throws CmsException if something goes wrong * * @see CmsObject#copyResourceToProject(String) * @see I_CmsResourceType#copyResourceToProject(CmsObject, CmsSecurityManager, CmsResource) */ public void copyResourceToProject(CmsDbContext dbc, CmsResource resource) throws CmsException { // copy the resource to the project only if the resource is not already in the project if (!isInsideCurrentProject(dbc, resource.getRootPath())) { // check if there are already any subfolders of this resource I_CmsProjectDriver projectDriver = getProjectDriver(dbc); if (resource.isFolder()) { List projectResources = projectDriver.readProjectResources(dbc, dbc.currentProject()); for (int i = 0; i < projectResources.size(); i++) { String resname = projectResources.get(i); if (resname.startsWith(resource.getRootPath())) { // delete the existing project resource first projectDriver.deleteProjectResource(dbc, dbc.currentProject().getUuid(), resname); } } } try { projectDriver.createProjectResource(dbc, dbc.currentProject().getUuid(), resource.getRootPath()); } catch (CmsException exc) { // if the subfolder exists already - all is ok } finally { m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROJECT_RESOURCES); OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_PROJECT_MODIFIED, Collections. singletonMap("project", dbc.currentProject()))); } } } /** * Counts the locked resources in this project.

* * @param project the project to count the locked resources in * * @return the amount of locked resources in this project */ public int countLockedResources(CmsProject project) { // count locks return m_lockManager.countExclusiveLocksInProject(project); } /** * Add a new group to the Cms.

* * Only the admin can do this. * Only users, which are in the group "administrators" are granted.

* * @param dbc the current database context * @param id the id of the new group * @param name the name of the new group * @param description the description for the new group * @param flags the flags for the new group * @param parent the name of the parent group (or null) * * @return new created group * * @throws CmsException if the creation of the group failed * @throws CmsIllegalArgumentException if the length of the given name was below 1 */ public CmsGroup createGroup(CmsDbContext dbc, CmsUUID id, String name, String description, int flags, String parent) throws CmsIllegalArgumentException, CmsException { // check the group name OpenCms.getValidationHandler().checkGroupName(CmsOrganizationalUnit.getSimpleName(name)); // trim the name name = name.trim(); // check the OU readOrganizationalUnit(dbc, CmsOrganizationalUnit.getParentFqn(name)); // get the id of the parent group if necessary if (CmsStringUtil.isNotEmpty(parent)) { CmsGroup parentGroup = readGroup(dbc, parent); if (!parentGroup.isRole() && !CmsOrganizationalUnit.getParentFqn(parent).equals(CmsOrganizationalUnit.getParentFqn(name))) { throw new CmsDataAccessException( Messages.get().container( Messages.ERR_PARENT_GROUP_MUST_BE_IN_SAME_OU_3, CmsOrganizationalUnit.getSimpleName(name), CmsOrganizationalUnit.getParentFqn(name), parent)); } } // create the group CmsGroup group = getUserDriver(dbc).createGroup(dbc, id, name, description, flags, parent); // if the group is in fact a role, initialize it if (group.isVirtual()) { // get all users that have the given role String groupname = CmsRole.valueOf(group).getGroupName(); Iterator it = getUsersOfGroup(dbc, groupname, true, false, true).iterator(); while (it.hasNext()) { CmsUser user = it.next(); // put them in the new group addUserToGroup(dbc, user.getName(), group.getName(), true); } } // put it into the cache m_monitor.cacheGroup(group); if (!dbc.getProjectId().isNullUUID()) { // group modified event is not needed return group; } // fire group modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_GROUP_NAME, group.getName()); eventData.put(I_CmsEventListener.KEY_GROUP_ID, group.getId().toString()); eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_GROUP_MODIFIED_ACTION_CREATE); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_GROUP_MODIFIED, eventData)); // return it return group; } /** * Creates a new organizational unit.

* * @param dbc the current db context * @param ouFqn the fully qualified name of the new organizational unit * @param description the description of the new organizational unit * @param flags the flags for the new organizational unit * @param resource the first associated resource * * @return a {@link CmsOrganizationalUnit} object representing * the newly created organizational unit * * @throws CmsException if operation was not successful * * @see org.opencms.security.CmsOrgUnitManager#createOrganizationalUnit(CmsObject, String, String, int, String) */ public CmsOrganizationalUnit createOrganizationalUnit( CmsDbContext dbc, String ouFqn, String description, int flags, CmsResource resource) throws CmsException { // normal case CmsOrganizationalUnit parent = readOrganizationalUnit(dbc, CmsOrganizationalUnit.getParentFqn(ouFqn)); String name = CmsOrganizationalUnit.getSimpleName(ouFqn); if (name.endsWith(CmsOrganizationalUnit.SEPARATOR)) { name = name.substring(0, name.length() - 1); } // check the name CmsResource.checkResourceName(name); // trim the name name = name.trim(); // check the description if (CmsStringUtil.isEmptyOrWhitespaceOnly(description)) { throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_BAD_OU_DESCRIPTION_EMPTY_0)); } // create the organizational unit CmsOrganizationalUnit orgUnit = getUserDriver(dbc).createOrganizationalUnit( dbc, name, description, flags, parent, resource != null ? resource.getRootPath() : null); // put the new created org unit into the cache m_monitor.cacheOrgUnit(orgUnit); // flush relevant caches m_monitor.clearPrincipalsCache(); m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); // create a publish list for the 'virtual' publish event CmsResource ouRes = readResource( dbc, CmsUserDriver.ORGUNIT_BASE_FOLDER + orgUnit.getName(), CmsResourceFilter.DEFAULT); CmsPublishList pl = new CmsPublishList(ouRes, false); pl.add(ouRes, false); getProjectDriver(dbc).writePublishHistory( dbc, pl.getPublishHistoryId(), new CmsPublishedResource(ouRes, -1, CmsResourceState.STATE_NEW)); // fire the 'virtual' publish event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_PUBLISHID, pl.getPublishHistoryId().toString()); eventData.put(I_CmsEventListener.KEY_PROJECTID, dbc.currentProject().getUuid()); eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); CmsEvent afterPublishEvent = new CmsEvent(I_CmsEventListener.EVENT_PUBLISH_PROJECT, eventData); OpenCms.fireCmsEvent(afterPublishEvent); if (!dbc.getProjectId().isNullUUID()) { // OU modified event is not needed return orgUnit; } // fire OU modified event Map event2Data = new HashMap(); event2Data.put(I_CmsEventListener.KEY_OU_NAME, orgUnit.getName()); event2Data.put(I_CmsEventListener.KEY_OU_ID, orgUnit.getId().toString()); event2Data.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_OU_MODIFIED_ACTION_CREATE); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_OU_MODIFIED, event2Data)); // return it return orgUnit; } /** * Creates a project.

* * @param dbc the current database context * @param name the name of the project to create * @param description the description of the project * @param groupname the project user group to be set * @param managergroupname the project manager group to be set * @param projecttype the type of the project * * @return the created project * * @throws CmsIllegalArgumentException if the chosen name is already used * by the online project, or if the name is not valid * @throws CmsException if something goes wrong */ public CmsProject createProject( CmsDbContext dbc, String name, String description, String groupname, String managergroupname, CmsProject.CmsProjectType projecttype) throws CmsIllegalArgumentException, CmsException { if (CmsProject.ONLINE_PROJECT_NAME.equals(name)) { throw new CmsIllegalArgumentException( Messages.get().container( Messages.ERR_CREATE_PROJECT_ONLINE_PROJECT_NAME_1, CmsProject.ONLINE_PROJECT_NAME)); } // check the name CmsProject.checkProjectName(CmsOrganizationalUnit.getSimpleName(name)); // check the ou readOrganizationalUnit(dbc, CmsOrganizationalUnit.getParentFqn(name)); // read the needed groups from the cms CmsGroup group = readGroup(dbc, groupname); CmsGroup managergroup = readGroup(dbc, managergroupname); return getProjectDriver(dbc).createProject( dbc, new CmsUUID(), dbc.currentUser(), group, managergroup, name, description, projecttype.getDefaultFlags(), projecttype); } /** * Creates a property definition.

* * Property definitions are valid for all resource types.

* * @param dbc the current database context * @param name the name of the property definition to create * * @return the created property definition * * @throws CmsException if something goes wrong */ public CmsPropertyDefinition createPropertyDefinition(CmsDbContext dbc, String name) throws CmsException { CmsPropertyDefinition propertyDefinition = null; name = name.trim(); // validate the property name CmsPropertyDefinition.checkPropertyName(name); // TODO: make the type a parameter try { try { propertyDefinition = getVfsDriver(dbc).readPropertyDefinition( dbc, name, dbc.currentProject().getUuid()); } catch (CmsException e) { propertyDefinition = getVfsDriver(dbc).createPropertyDefinition( dbc, dbc.currentProject().getUuid(), name, CmsPropertyDefinition.TYPE_NORMAL); } try { getVfsDriver(dbc).readPropertyDefinition(dbc, name, CmsProject.ONLINE_PROJECT_ID); } catch (CmsException e) { getVfsDriver(dbc).createPropertyDefinition( dbc, CmsProject.ONLINE_PROJECT_ID, name, CmsPropertyDefinition.TYPE_NORMAL); } try { getHistoryDriver(dbc).readPropertyDefinition(dbc, name); } catch (CmsException e) { getHistoryDriver(dbc).createPropertyDefinition(dbc, name, CmsPropertyDefinition.TYPE_NORMAL); } } finally { // fire an event that a property of a resource has been deleted OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_PROPERTY_DEFINITION_CREATED, Collections. singletonMap("propertyDefinition", propertyDefinition))); } return propertyDefinition; } /** * Creates a new publish job.

* * @param dbc the current database context * @param publishJob the publish job to create * * @throws CmsException if something goes wrong */ public void createPublishJob(CmsDbContext dbc, CmsPublishJobInfoBean publishJob) throws CmsException { getProjectDriver(dbc).createPublishJob(dbc, publishJob); } /** * Creates a new resource with the provided content and properties.

* * The content parameter may be null if the resource id * already exists. If so, the created resource will be a sibling of the existing * resource, the existing content will remain unchanged.

* * This is used during file import for import of siblings as the * manifest.xml only contains one binary copy per file.

* * If the resource id exists but the content is not null, * the created resource will be made a sibling of the existing resource, * and both will share the new content.

* * @param dbc the current database context * @param resourcePath the name of the resource to create (full path) * @param resource the new resource to create * @param content the content for the new resource * @param properties the properties for the new resource * @param importCase if true, signals that this operation is done while * importing resource, causing different lock behavior and * potential "lost and found" usage * * @return the created resource * * @throws CmsException if something goes wrong */ public CmsResource createResource( CmsDbContext dbc, String resourcePath, CmsResource resource, byte[] content, List properties, boolean importCase) throws CmsException { CmsResource newResource = null; if (resource.isFolder()) { resourcePath = CmsFileUtil.addTrailingSeparator(resourcePath); } try { synchronized (this) { // need to provide the parent folder id for resource creation String parentFolderName = CmsResource.getParentFolder(resourcePath); CmsResource parentFolder = readFolder(dbc, parentFolderName, CmsResourceFilter.IGNORE_EXPIRATION); CmsLock parentLock = getLock(dbc, parentFolder); // it is not allowed to create a resource in a folder locked by other user if (!parentLock.isUnlocked() && !parentLock.isOwnedBy(dbc.currentUser())) { // one exception is if the admin user tries to create a temporary resource if (!CmsResource.getName(resourcePath).startsWith(TEMP_FILE_PREFIX) || !m_securityManager.hasRole(dbc, dbc.currentUser(), CmsRole.ROOT_ADMIN)) { throw new CmsLockException( Messages.get().container( Messages.ERR_CREATE_RESOURCE_PARENT_LOCK_1, dbc.removeSiteRoot(resourcePath))); } } if (CmsResourceTypeJsp.isJsp(resource)) { // security check when trying to create a new jsp file m_securityManager.checkRoleForResource(dbc, CmsRole.VFS_MANAGER, parentFolder); } // check import configuration of "lost and found" folder boolean useLostAndFound = importCase && !OpenCms.getImportExportManager().overwriteCollidingResources(); // check if the resource already exists by name CmsResource currentResourceByName = null; try { currentResourceByName = readResource(dbc, resourcePath, CmsResourceFilter.ALL); } catch (CmsVfsResourceNotFoundException e) { // if the resource does exist, we have to check the id later to decide what to do } // check if the resource already exists by id try { CmsResource currentResourceById = readResource( dbc, resource.getStructureId(), CmsResourceFilter.ALL); // it is not allowed to import resources when there is already a resource with the same id but different path if (!currentResourceById.getRootPath().equals(resourcePath)) { throw new CmsVfsResourceAlreadyExistsException( Messages.get().container( Messages.ERR_RESOURCE_WITH_ID_ALREADY_EXISTS_3, dbc.removeSiteRoot(resourcePath), dbc.removeSiteRoot(currentResourceById.getRootPath()), currentResourceById.getStructureId())); } } catch (CmsVfsResourceNotFoundException e) { // if the resource does exist, we have to check the id later to decide what to do } // check the permissions if (currentResourceByName == null) { // resource does not exist - check parent folder m_securityManager.checkPermissions( dbc, parentFolder, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.IGNORE_EXPIRATION); } else { // resource already exists - check existing resource m_securityManager.checkPermissions( dbc, currentResourceByName, CmsPermissionSet.ACCESS_WRITE, !importCase, CmsResourceFilter.ALL); } // now look for the resource by name if (currentResourceByName != null) { boolean overwrite = true; if (currentResourceByName.getState().isDeleted()) { if (!currentResourceByName.isFolder()) { // if a non-folder resource was deleted it's treated like a new resource overwrite = false; } } else { if (!importCase) { // direct "overwrite" of a resource is possible only during import, // or if the resource has been deleted throw new CmsVfsResourceAlreadyExistsException( org.opencms.db.generic.Messages.get().container( org.opencms.db.generic.Messages.ERR_RESOURCE_WITH_NAME_ALREADY_EXISTS_1, dbc.removeSiteRoot(resource.getRootPath()))); } // the resource already exists if (!resource.isFolder() && useLostAndFound && (!currentResourceByName.getResourceId().equals(resource.getResourceId()))) { // semantic change: the current resource is moved to L&F and the imported resource will overwrite the old one // will leave the resource with state deleted, // but it does not matter, since the state will be set later again moveToLostAndFound(dbc, currentResourceByName, false); } } if (!overwrite) { // lock the resource, will throw an exception if not lockable lockResource(dbc, currentResourceByName, CmsLockType.EXCLUSIVE); // trigger createResource instead of writeResource currentResourceByName = null; } } // if null, create new resource, if not null write resource CmsResource overwrittenResource = currentResourceByName; // extract the name (without path) String targetName = CmsResource.getName(resourcePath); int contentLength; // modify target name and content length in case of folder creation if (resource.isFolder()) { // folders never have any content contentLength = -1; // must cut of trailing '/' for folder creation (or name check fails) if (CmsResource.isFolder(targetName)) { targetName = targetName.substring(0, targetName.length() - 1); } } else { // otherwise ensure content and content length are set correctly if (content != null) { // if a content is provided, in each case the length is the length of this content contentLength = content.length; } else if (overwrittenResource != null) { // we have no content, but an already existing resource - length remains unchanged contentLength = overwrittenResource.getLength(); } else { // we have no content - length is used as set in the resource contentLength = resource.getLength(); } } // check if the target name is valid (forbidden chars etc.), // if not throw an exception // must do this here since targetName is modified in folder case (see above) CmsResource.checkResourceName(targetName); // set structure and resource ids as given CmsUUID structureId = resource.getStructureId(); CmsUUID resourceId = resource.getResourceId(); // decide which structure id to use if (overwrittenResource != null) { // resource exists, re-use existing ids structureId = overwrittenResource.getStructureId(); } if (structureId.isNullUUID()) { // need a new structure id structureId = new CmsUUID(); } // decide which resource id to use if (overwrittenResource != null) { // if we are overwriting we have to assure the resource id is the same resourceId = overwrittenResource.getResourceId(); } if (resourceId.isNullUUID()) { // need a new resource id resourceId = new CmsUUID(); } try { // check online resource CmsResource onlineResource = getVfsDriver( dbc).readResource(dbc, CmsProject.ONLINE_PROJECT_ID, resourcePath, true); // only allow to overwrite with different id if importing (createResource will set the right id) try { CmsResource offlineResource = getVfsDriver(dbc).readResource( dbc, dbc.currentProject().getUuid(), onlineResource.getStructureId(), true); if (!offlineResource.getRootPath().equals(onlineResource.getRootPath())) { throw new CmsVfsOnlineResourceAlreadyExistsException( Messages.get().container( Messages.ERR_ONLINE_RESOURCE_EXISTS_2, dbc.removeSiteRoot(resourcePath), dbc.removeSiteRoot(offlineResource.getRootPath()))); } } catch (CmsVfsResourceNotFoundException e) { // there is no problem for now // but should never happen if (LOG.isErrorEnabled()) { LOG.error(e.getLocalizedMessage(), e); } } } catch (CmsVfsResourceNotFoundException e) { // ok, there is no online entry to worry about } // now create a resource object with all informations newResource = new CmsResource( structureId, resourceId, resourcePath, resource.getTypeId(), resource.isFolder(), resource.getFlags(), dbc.currentProject().getUuid(), resource.getState(), resource.getDateCreated(), resource.getUserCreated(), resource.getDateLastModified(), resource.getUserLastModified(), resource.getDateReleased(), resource.getDateExpired(), 1, contentLength, resource.getDateContent(), resource.getVersion()); // version number does not matter since it will be computed later // ensure date is updated only if required if (resource.isTouched()) { // this will trigger the internal "is touched" state on the new resource newResource.setDateLastModified(resource.getDateLastModified()); } if (resource.isFile()) { // check if a sibling to the imported resource lies in a marked site if (labelResource(dbc, resource, resourcePath, 2)) { int flags = resource.getFlags(); flags |= CmsResource.FLAG_LABELED; resource.setFlags(flags); } // ensure siblings don't overwrite existing resource records if (content == null) { newResource.setState(CmsResource.STATE_KEEP); } } // delete all relations for the resource, before writing the content getVfsDriver( dbc).deleteRelations(dbc, dbc.currentProject().getUuid(), newResource, CmsRelationFilter.TARGETS); if (overwrittenResource == null) { CmsLock lock = getLock(dbc, newResource); if (lock.getEditionLock().isExclusive()) { unlockResource(dbc, newResource, true, false); } // resource does not exist. newResource = getVfsDriver( dbc).createResource(dbc, dbc.currentProject().getUuid(), newResource, content); } else { // resource already exists. // probably the resource is a merged page file that gets overwritten during import, or it gets // overwritten by a copy operation. if so, the structure & resource state are not modified to changed. int updateStates = (overwrittenResource.getState().isNew() ? CmsDriverManager.NOTHING_CHANGED : CmsDriverManager.UPDATE_ALL); getVfsDriver(dbc).writeResource(dbc, dbc.currentProject().getUuid(), newResource, updateStates); if ((content != null) && resource.isFile()) { // also update file content if required getVfsDriver(dbc).writeContent(dbc, newResource.getResourceId(), content); } } // write the properties (internal operation, no events or duplicate permission checks) writePropertyObjects(dbc, newResource, properties, false); // lock the created resource try { // if it is locked by another user (copied or moved resource) this lock should be preserved and // the exception is OK: locks on created resources are a slave feature to original locks lockResource(dbc, newResource, CmsLockType.EXCLUSIVE); } catch (CmsLockException cle) { if (LOG.isDebugEnabled()) { LOG.debug( Messages.get().getBundle().key( Messages.ERR_CREATE_RESOURCE_LOCK_1, new Object[] {dbc.removeSiteRoot(newResource.getRootPath())})); } } if (!importCase) { log( dbc, new CmsLogEntry( dbc, newResource.getStructureId(), CmsLogEntryType.RESOURCE_CREATED, new String[] {resource.getRootPath()}), false); } else { log( dbc, new CmsLogEntry( dbc, newResource.getStructureId(), CmsLogEntryType.RESOURCE_IMPORTED, new String[] {resource.getRootPath()}), false); } } } finally { // clear the internal caches m_monitor.clearAccessControlListCache(); m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); if (newResource != null) { // fire an event that a new resource has been created OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCE_CREATED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCE, newResource))); } } return newResource; } /** * Creates a new resource of the given resource type * with the provided content and properties.

* * If the provided content is null and the resource is not a folder, * the content will be set to an empty byte array.

* * @param dbc the current database context * @param resourcename the name of the resource to create (full path) * @param type the type of the resource to create * @param content the content for the new resource * @param properties the properties for the new resource * * @return the created resource * * @throws CmsException if something goes wrong * @throws CmsIllegalArgumentException if the resourcename argument is null or of length 0 * * @see CmsObject#createResource(String, int, byte[], List) * @see CmsObject#createResource(String, int) * @see I_CmsResourceType#createResource(CmsObject, CmsSecurityManager, String, byte[], List) */ @SuppressWarnings("javadoc") public CmsResource createResource( CmsDbContext dbc, String resourcename, int type, byte[] content, List properties) throws CmsException, CmsIllegalArgumentException { String targetName = resourcename; if (content == null) { // name based resource creation MUST have a content content = new byte[0]; } int size; if (CmsFolder.isFolderType(type)) { // must cut of trailing '/' for folder creation if (CmsResource.isFolder(targetName)) { targetName = targetName.substring(0, targetName.length() - 1); } size = -1; } else { size = content.length; } // create a new resource CmsResource newResource = new CmsResource( CmsUUID.getNullUUID(), // uuids will be "corrected" later CmsUUID.getNullUUID(), targetName, type, CmsFolder.isFolderType(type), 0, dbc.currentProject().getUuid(), CmsResource.STATE_NEW, 0, dbc.currentUser().getId(), 0, dbc.currentUser().getId(), CmsResource.DATE_RELEASED_DEFAULT, CmsResource.DATE_EXPIRED_DEFAULT, 1, size, 0, // version number does not matter since it will be computed later 0); // content time will be corrected later return createResource(dbc, targetName, newResource, content, properties, false); } /** * Creates a new sibling of the source resource.

* * @param dbc the current database context * @param source the resource to create a sibling for * @param destination the name of the sibling to create with complete path * @param properties the individual properties for the new sibling * * @return the new created sibling * * @throws CmsException if something goes wrong * * @see CmsObject#createSibling(String, String, List) * @see I_CmsResourceType#createSibling(CmsObject, CmsSecurityManager, CmsResource, String, List) */ public CmsResource createSibling( CmsDbContext dbc, CmsResource source, String destination, List properties) throws CmsException { if (source.isFolder()) { throw new CmsVfsException(Messages.get().container(Messages.ERR_VFS_FOLDERS_DONT_SUPPORT_SIBLINGS_0)); } // determine destination folder and resource name String destinationFoldername = CmsResource.getParentFolder(destination); // read the destination folder (will also check read permissions) CmsFolder destinationFolder = readFolder(dbc, destinationFoldername, CmsResourceFilter.IGNORE_EXPIRATION); // no further permission check required here, will be done in createResource() // check the resource flags int flags = source.getFlags(); if (labelResource(dbc, source, destination, 1)) { // set "labeled" link flag for new resource flags |= CmsResource.FLAG_LABELED; } // create the new resource CmsResource newResource = new CmsResource( new CmsUUID(), source.getResourceId(), destination, source.getTypeId(), source.isFolder(), flags, dbc.currentProject().getUuid(), CmsResource.STATE_KEEP, source.getDateCreated(), // ensures current resource record remains untouched source.getUserCreated(), source.getDateLastModified(), source.getUserLastModified(), source.getDateReleased(), source.getDateExpired(), source.getSiblingCount() + 1, source.getLength(), source.getDateContent(), source.getVersion()); // version number does not matter since it will be computed later // trigger "is touched" state on resource (will ensure modification date is kept unchanged) newResource.setDateLastModified(newResource.getDateLastModified()); log( dbc, new CmsLogEntry( dbc, newResource.getStructureId(), CmsLogEntryType.RESOURCE_CLONED, new String[] {newResource.getRootPath()}), false); // create the resource (null content signals creation of sibling) newResource = createResource(dbc, destination, newResource, null, properties, false); // copy relations copyRelations(dbc, source, newResource); // clear the caches m_monitor.clearAccessControlListCache(); List modifiedResources = new ArrayList(); modifiedResources.add(source); modifiedResources.add(newResource); modifiedResources.add(destinationFolder); Map eventData = new HashMap<>(); eventData.put(I_CmsEventListener.KEY_RESOURCES, modifiedResources); eventData.put(I_CmsEventListener.KEY_CHANGE, I_CmsEventListener.VALUE_CREATE_SIBLING); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCES_AND_PROPERTIES_MODIFIED, eventData)); return newResource; } /** * Creates the project for the temporary workplace files.

* * @param dbc the current database context * * @return the created project for the temporary workplace files * * @throws CmsException if something goes wrong */ public CmsProject createTempfileProject(CmsDbContext dbc) throws CmsException { // read the needed groups from the cms CmsGroup projectUserGroup = readGroup(dbc, dbc.currentProject().getGroupId()); CmsGroup projectManagerGroup = readGroup(dbc, dbc.currentProject().getManagerGroupId()); CmsProject tempProject = getProjectDriver(dbc).createProject( dbc, new CmsUUID(), dbc.currentUser(), projectUserGroup, projectManagerGroup, I_CmsProjectDriver.TEMP_FILE_PROJECT_NAME, Messages.get().getBundle(dbc.getRequestContext().getLocale()).key( Messages.GUI_WORKPLACE_TEMPFILE_PROJECT_DESC_0), CmsProject.PROJECT_FLAG_HIDDEN, CmsProject.PROJECT_TYPE_NORMAL); getProjectDriver(dbc).createProjectResource(dbc, tempProject.getUuid(), "/"); OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_PROJECT_MODIFIED, Collections. singletonMap("project", tempProject))); return tempProject; } /** * Creates a new user.

* * @param dbc the current database context * @param name the name for the new user * @param password the password for the new user * @param description the description for the new user * @param additionalInfos the additional infos for the user * * @return the created user * * @see CmsObject#createUser(String, String, String, Map) * * @throws CmsException if something goes wrong * @throws CmsIllegalArgumentException if the name for the user is not valid */ public CmsUser createUser( CmsDbContext dbc, String name, String password, String description, Map additionalInfos) throws CmsException, CmsIllegalArgumentException { // no space before or after the name name = name.trim(); // check the user name String userName = CmsOrganizationalUnit.getSimpleName(name); OpenCms.getValidationHandler().checkUserName(userName); if (CmsStringUtil.isEmptyOrWhitespaceOnly(userName)) { throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_BAD_USER_1, userName)); } // check the ou CmsOrganizationalUnit ou = readOrganizationalUnit(dbc, CmsOrganizationalUnit.getParentFqn(name)); // check the password validatePassword(password); Map info = new HashMap(); if (additionalInfos != null) { info.putAll(additionalInfos); } if (description != null) { info.put(CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION, description); } int flags = 0; if (ou.hasFlagWebuser()) { flags += I_CmsPrincipal.FLAG_USER_WEBUSER; } CmsUser user = getUserDriver(dbc).createUser( dbc, new CmsUUID(), name, OpenCms.getPasswordHandler().digest(password), " ", " ", " ", 0, I_CmsPrincipal.FLAG_ENABLED + flags, 0, info); if (!dbc.getProjectId().isNullUUID()) { // user modified event is not needed return user; } // fire user modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_CREATE_USER); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); return user; } /** * Deletes aliases indicated by a filter.

* * @param dbc the current database context * @param project the current project * @param filter the filter which describes which aliases to delete * * @throws CmsException if something goes wrong */ public void deleteAliases(CmsDbContext dbc, CmsProject project, CmsAliasFilter filter) throws CmsException { I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); vfsDriver.deleteAliases(dbc, project, filter); } /** * Deletes all property values of a file or folder.

* * If there are no other siblings than the specified resource, * both the structure and resource property values get deleted. * If the specified resource has siblings, only the structure * property values get deleted.

* * @param dbc the current database context * @param resourcename the name of the resource for which all properties should be deleted * * @throws CmsException if operation was not successful */ public void deleteAllProperties(CmsDbContext dbc, String resourcename) throws CmsException { CmsResource resource = null; List resources = new ArrayList(); try { // read the resource resource = readResource(dbc, resourcename, CmsResourceFilter.IGNORE_EXPIRATION); // check the security m_securityManager.checkPermissions( dbc, resource, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL); // delete the property values if (resource.getSiblingCount() > 1) { // the resource has siblings- delete only the (structure) properties of this sibling getVfsDriver(dbc).deletePropertyObjects( dbc, dbc.currentProject().getUuid(), resource, CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_VALUES); resources.addAll(readSiblings(dbc, resource, CmsResourceFilter.ALL)); } else { // the resource has no other siblings- delete all (structure+resource) properties getVfsDriver(dbc).deletePropertyObjects( dbc, dbc.currentProject().getUuid(), resource, CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES); resources.add(resource); } } finally { // clear the driver manager cache m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); // fire an event that all properties of a resource have been deleted OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCES_AND_PROPERTIES_MODIFIED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCES, resources))); } } /** * Deletes all entries in the published resource table.

* * @param dbc the current database context * @param linkType the type of resource deleted (0= non-paramter, 1=parameter) * * @throws CmsException if something goes wrong */ public void deleteAllStaticExportPublishedResources(CmsDbContext dbc, int linkType) throws CmsException { getProjectDriver(dbc).deleteAllStaticExportPublishedResources(dbc, linkType); } /** * Deletes a group, where all permissions, users and children of the group * are transfered to a replacement group.

* * @param dbc the current request context * @param group the id of the group to be deleted * @param replacementId the id of the group to be transfered, can be null * * @throws CmsException if operation was not successful * @throws CmsDataAccessException if group to be deleted contains user */ public void deleteGroup(CmsDbContext dbc, CmsGroup group, CmsUUID replacementId) throws CmsDataAccessException, CmsException { CmsGroup replacementGroup = null; if (replacementId != null) { replacementGroup = readGroup(dbc, replacementId); } // get all child groups of the group List children = getChildren(dbc, group, false); // get all users in this group List users = getUsersOfGroup(dbc, group.getName(), true, true, group.isRole()); // get online project CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); if (replacementGroup == null) { // remove users Iterator itUsers = users.iterator(); while (itUsers.hasNext()) { CmsUser user = itUsers.next(); if (userInGroup(dbc, user.getName(), group.getName(), group.isRole())) { removeUserFromGroup(dbc, user.getName(), group.getName(), group.isRole()); } } // transfer children to grandfather if possible CmsUUID parentId = group.getParentId(); if (parentId == null) { parentId = CmsUUID.getNullUUID(); } Iterator itChildren = children.iterator(); while (itChildren.hasNext()) { CmsGroup child = itChildren.next(); child.setParentId(parentId); writeGroup(dbc, child); } } else { // move children Iterator itChildren = children.iterator(); while (itChildren.hasNext()) { CmsGroup child = itChildren.next(); child.setParentId(replacementId); writeGroup(dbc, child); } // move users Iterator itUsers = users.iterator(); while (itUsers.hasNext()) { CmsUser user = itUsers.next(); addUserToGroup(dbc, user.getName(), replacementGroup.getName(), group.isRole()); removeUserFromGroup(dbc, user.getName(), group.getName(), group.isRole()); } // transfer for offline transferPrincipalResources(dbc, dbc.currentProject(), group.getId(), replacementId, true); // transfer for online transferPrincipalResources(dbc, onlineProject, group.getId(), replacementId, true); } // remove the group getUserDriver( dbc).removeAccessControlEntriesForPrincipal(dbc, dbc.currentProject(), onlineProject, group.getId()); getUserDriver(dbc).deleteGroup(dbc, group.getName()); // backup the group getHistoryDriver(dbc).writePrincipal(dbc, group); if (OpenCms.getSubscriptionManager().isEnabled()) { // delete all subscribed resources for group unsubscribeAllResourcesFor(dbc, OpenCms.getSubscriptionManager().getPoolName(), group); } // clear the relevant caches m_monitor.uncacheGroup(group); m_monitor.flushCache( CmsMemoryMonitor.CacheType.USERGROUPS, CmsMemoryMonitor.CacheType.USER_LIST, CmsMemoryMonitor.CacheType.ACL); if (!dbc.getProjectId().isNullUUID()) { // group modified event is not needed return; } // fire group modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_GROUP_ID, group.getId().toString()); eventData.put(I_CmsEventListener.KEY_GROUP_NAME, group.getName()); eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_GROUP_MODIFIED_ACTION_DELETE); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_GROUP_MODIFIED, eventData)); } /** * Deletes the versions from the history tables, keeping the given number of versions per resource.

* * if the cleanUp option is set, additionally versions of deleted resources will be removed.

* * @param dbc the current database context * @param versionsToKeep number of versions to keep, is ignored if negative * @param versionsDeleted number of versions to keep for deleted resources, is ignored if negative * @param timeDeleted deleted resources older than this will also be deleted, is ignored if negative * @param report the report for output logging * * @throws CmsException if operation was not successful */ public void deleteHistoricalVersions( CmsDbContext dbc, int versionsToKeep, int versionsDeleted, long timeDeleted, I_CmsReport report) throws CmsException { report.println(Messages.get().container(Messages.RPT_START_DELETE_VERSIONS_0), I_CmsReport.FORMAT_HEADLINE); if (versionsToKeep >= 0) { report.println( Messages.get().container(Messages.RPT_START_DELETE_ACT_VERSIONS_1, Integer.valueOf(versionsToKeep)), I_CmsReport.FORMAT_HEADLINE); List resources = getHistoryDriver(dbc).getAllNotDeletedEntries(dbc); if (resources.isEmpty()) { report.println(Messages.get().container(Messages.RPT_DELETE_NOTHING_0), I_CmsReport.FORMAT_OK); } int n = resources.size(); int m = 1; Iterator itResources = resources.iterator(); while (itResources.hasNext()) { I_CmsHistoryResource histResource = itResources.next(); report.print( org.opencms.report.Messages.get().container( org.opencms.report.Messages.RPT_SUCCESSION_2, String.valueOf(m), String.valueOf(n)), I_CmsReport.FORMAT_NOTE); report.print( org.opencms.report.Messages.get().container( org.opencms.report.Messages.RPT_ARGUMENT_1, dbc.removeSiteRoot(histResource.getRootPath()))); report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); try { int deleted = getHistoryDriver(dbc).deleteEntries(dbc, histResource, versionsToKeep, -1); report.print( Messages.get().container(Messages.RPT_VERSION_DELETING_1, Integer.valueOf(deleted)), I_CmsReport.FORMAT_NOTE); report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); report.println( org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), I_CmsReport.FORMAT_OK); } catch (CmsDataAccessException e) { report.println( org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_ERROR_0), I_CmsReport.FORMAT_ERROR); if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } m++; } report.println( Messages.get().container(Messages.RPT_END_DELETE_ACT_VERSIONS_0), I_CmsReport.FORMAT_HEADLINE); } if ((versionsDeleted >= 0) || (timeDeleted >= 0)) { if (timeDeleted >= 0) { report.println( Messages.get().container( Messages.RPT_START_DELETE_DEL_VERSIONS_2, Integer.valueOf(versionsDeleted), new Date(timeDeleted)), I_CmsReport.FORMAT_HEADLINE); } else { report.println( Messages.get().container( Messages.RPT_START_DELETE_DEL_VERSIONS_1, Integer.valueOf(versionsDeleted)), I_CmsReport.FORMAT_HEADLINE); } List resources = getHistoryDriver(dbc).getAllDeletedEntries(dbc); if (resources.isEmpty()) { report.println(Messages.get().container(Messages.RPT_DELETE_NOTHING_0), I_CmsReport.FORMAT_OK); } int n = resources.size(); int m = 1; Iterator itResources = resources.iterator(); while (itResources.hasNext()) { I_CmsHistoryResource histResource = itResources.next(); report.print( org.opencms.report.Messages.get().container( org.opencms.report.Messages.RPT_SUCCESSION_2, String.valueOf(m), String.valueOf(n)), I_CmsReport.FORMAT_NOTE); report.print( org.opencms.report.Messages.get().container( org.opencms.report.Messages.RPT_ARGUMENT_1, dbc.removeSiteRoot(histResource.getRootPath()))); report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); try { int deleted = getHistoryDriver(dbc).deleteEntries(dbc, histResource, versionsDeleted, timeDeleted); report.print( Messages.get().container(Messages.RPT_VERSION_DELETING_1, Integer.valueOf(deleted)), I_CmsReport.FORMAT_NOTE); report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); report.println( org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), I_CmsReport.FORMAT_OK); } catch (CmsDataAccessException e) { report.println( org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_ERROR_0), I_CmsReport.FORMAT_ERROR); if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } m++; } report.println( Messages.get().container(Messages.RPT_END_DELETE_DEL_VERSIONS_0), I_CmsReport.FORMAT_HEADLINE); } report.println(Messages.get().container(Messages.RPT_END_DELETE_VERSIONS_0), I_CmsReport.FORMAT_HEADLINE); } /** * Deletes all log entries matching the given filter.

* * @param dbc the current db context * @param filter the filter to use for deletion * * @throws CmsException if something goes wrong * * @see CmsSecurityManager#deleteLogEntries(CmsRequestContext, CmsLogFilter) */ public void deleteLogEntries(CmsDbContext dbc, CmsLogFilter filter) throws CmsException { updateLog(dbc); m_projectDriver.deleteLog(dbc, filter); } /** * Deletes an organizational unit.

* * Only organizational units that contain no suborganizational unit can be deleted.

* * The organizational unit can not be delete if it is used in the request context, * or if the current user belongs to it.

* * All users and groups in the given organizational unit will be deleted.

* * @param dbc the current db context * @param organizationalUnit the organizational unit to delete * * @throws CmsException if operation was not successful * * @see org.opencms.security.CmsOrgUnitManager#deleteOrganizationalUnit(CmsObject, String) */ public void deleteOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit organizationalUnit) throws CmsException { // check organizational unit in context if (dbc.getRequestContext().getOuFqn().equals(organizationalUnit.getName())) { throw new CmsDbConsistencyException( Messages.get().container(Messages.ERR_ORGUNIT_DELETE_IN_CONTEXT_1, organizationalUnit.getName())); } // check organizational unit for user if (dbc.currentUser().getOuFqn().equals(organizationalUnit.getName())) { throw new CmsDbConsistencyException( Messages.get().container(Messages.ERR_ORGUNIT_DELETE_CURRENT_USER_1, organizationalUnit.getName())); } // check sub organizational units if (!getOrganizationalUnits(dbc, organizationalUnit, true).isEmpty()) { throw new CmsDbConsistencyException( Messages.get().container(Messages.ERR_ORGUNIT_DELETE_SUB_ORGUNITS_1, organizationalUnit.getName())); } // check groups List groups = getGroups(dbc, organizationalUnit, true, false); Iterator itGroups = groups.iterator(); while (itGroups.hasNext()) { CmsGroup group = itGroups.next(); if (!OpenCms.getDefaultUsers().isDefaultGroup(group.getName())) { throw new CmsDbConsistencyException( Messages.get().container(Messages.ERR_ORGUNIT_DELETE_GROUPS_1, organizationalUnit.getName())); } } // check users if (!getUsers(dbc, organizationalUnit, true).isEmpty()) { throw new CmsDbConsistencyException( Messages.get().container(Messages.ERR_ORGUNIT_DELETE_USERS_1, organizationalUnit.getName())); } // delete default groups if needed itGroups = groups.iterator(); while (itGroups.hasNext()) { CmsGroup group = itGroups.next(); deleteGroup(dbc, group, null); } // delete projects Iterator itProjects = getProjectDriver(dbc).readProjects( dbc, organizationalUnit.getName()).iterator(); while (itProjects.hasNext()) { CmsProject project = itProjects.next(); deleteProject(dbc, project, false); } // delete roles Iterator itRoles = getGroups(dbc, organizationalUnit, true, true).iterator(); while (itRoles.hasNext()) { CmsGroup role = itRoles.next(); deleteGroup(dbc, role, null); } // create a publish list for the 'virtual' publish event CmsResource resource = readResource(dbc, organizationalUnit.getId(), CmsResourceFilter.DEFAULT); CmsPublishList pl = new CmsPublishList(resource, false); pl.add(resource, false); // remove the organizational unit itself getUserDriver(dbc).deleteOrganizationalUnit(dbc, organizationalUnit); // write the publish history entry getProjectDriver(dbc).writePublishHistory( dbc, pl.getPublishHistoryId(), new CmsPublishedResource(resource, -1, CmsResourceState.STATE_DELETED)); // flush relevant caches m_monitor.clearPrincipalsCache(); m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); // fire the 'virtual' publish event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_PUBLISHID, pl.getPublishHistoryId().toString()); eventData.put(I_CmsEventListener.KEY_PROJECTID, dbc.currentProject().getUuid()); eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); CmsEvent afterPublishEvent = new CmsEvent(I_CmsEventListener.EVENT_PUBLISH_PROJECT, eventData); OpenCms.fireCmsEvent(afterPublishEvent); m_lockManager.removeDeletedResource(dbc, resource.getRootPath()); if (!dbc.getProjectId().isNullUUID()) { // OU modified event is not needed return; } // fire OU modified event Map event2Data = new HashMap(); event2Data.put(I_CmsEventListener.KEY_OU_NAME, organizationalUnit.getName()); event2Data.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_OU_MODIFIED_ACTION_DELETE); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_OU_MODIFIED, event2Data)); } /** * Deletes a project.

* * Only the admin or the owner of the project can do this. * * @param dbc the current database context * @param deleteProject the project to be deleted * * @throws CmsException if something goes wrong */ public void deleteProject(CmsDbContext dbc, CmsProject deleteProject) throws CmsException { deleteProject(dbc, deleteProject, true); } /** * Deletes a project.

* * Only the admin or the owner of the project can do this. * * @param dbc the current database context * @param deleteProject the project to be deleted * @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 * * @throws CmsException if something goes wrong */ public void deleteProject(CmsDbContext dbc, CmsProject deleteProject, boolean resetResources) throws CmsException { CmsUUID projectId = deleteProject.getUuid(); if (resetResources) { // changed/new/deleted files in the specified project List modifiedFiles = readChangedResourcesInsideProject(dbc, projectId, RCPRM_FILES_ONLY_MODE); // changed/new/deleted folders in the specified project List modifiedFolders = readChangedResourcesInsideProject( dbc, projectId, RCPRM_FOLDERS_ONLY_MODE); resetResourcesInProject(dbc, projectId, modifiedFiles, modifiedFolders); } // unlock all resources in the project m_lockManager.removeResourcesInProject(deleteProject.getUuid(), true); m_monitor.clearAccessControlListCache(); m_monitor.clearResourceCache(); // set project to online project if current project is the one which will be deleted if (projectId.equals(dbc.currentProject().getUuid())) { dbc.getRequestContext().setCurrentProject(readProject(dbc, CmsProject.ONLINE_PROJECT_ID)); } // delete the project itself getProjectDriver(dbc).deleteProject(dbc, deleteProject); m_monitor.uncacheProject(deleteProject); // fire the corresponding event OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_PROJECT_MODIFIED, Collections. singletonMap("project", deleteProject))); } /** * Deletes a property definition.

* * @param dbc the current database context * @param name the name of the property definition to delete * * @throws CmsException if something goes wrong */ public void deletePropertyDefinition(CmsDbContext dbc, String name) throws CmsException { CmsPropertyDefinition propertyDefinition = null; try { // first read and then delete the metadefinition. propertyDefinition = readPropertyDefinition(dbc, name); getVfsDriver(dbc).deletePropertyDefinition(dbc, propertyDefinition); getHistoryDriver(dbc).deletePropertyDefinition(dbc, propertyDefinition); } finally { // fire an event that a property of a resource has been deleted OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_PROPERTY_DEFINITION_MODIFIED, Collections. singletonMap("propertyDefinition", propertyDefinition))); } } /** * Deletes a publish job identified by its history id.

* * @param dbc the current database context * @param publishHistoryId the history id identifying the publish job * * @throws CmsException if something goes wrong */ public void deletePublishJob(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { getProjectDriver(dbc).deletePublishJob(dbc, publishHistoryId); } /** * Deletes the publish list assigned to a publish job.

* * @param dbc the current database context * @param publishHistoryId the history id identifying the publish job * @throws CmsException if something goes wrong */ public void deletePublishList(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { getProjectDriver(dbc).deletePublishList(dbc, publishHistoryId); } /** * Deletes all relations for the given resource matching the given filter.

* * @param dbc the current db context * @param resource the resource to delete the relations for * @param filter the filter to use for deletion * * @throws CmsException if something goes wrong * * @see CmsSecurityManager#deleteRelationsForResource(CmsRequestContext, CmsResource, CmsRelationFilter) */ public void deleteRelationsForResource(CmsDbContext dbc, CmsResource resource, CmsRelationFilter filter) throws CmsException { if (filter.includesDefinedInContent()) { throw new CmsIllegalArgumentException( Messages.get().container( Messages.ERR_DELETE_RELATION_IN_CONTENT_2, dbc.removeSiteRoot(resource.getRootPath()), filter.getTypes())); } getVfsDriver(dbc).deleteRelations(dbc, dbc.currentProject().getUuid(), resource, filter); setDateLastModified(dbc, resource, System.currentTimeMillis()); log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_REMOVE_RELATION, new String[] {resource.getRootPath(), filter.toString()}), false); } /** * Deletes a resource.

* * The siblingMode parameter controls how to handle siblings * during the delete operation. * Possible values for this parameter are: *

    *
  • {@link CmsResource#DELETE_REMOVE_SIBLINGS}
  • *
  • {@link CmsResource#DELETE_PRESERVE_SIBLINGS}
  • *

* * @param dbc the current database context * @param resource the name of the resource to delete (full path) * @param siblingMode indicates how to handle siblings of the deleted resource * * @throws CmsException if something goes wrong * * @see CmsObject#deleteResource(String, CmsResource.CmsResourceDeleteMode) * @see I_CmsResourceType#deleteResource(CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceDeleteMode) */ public void deleteResource(CmsDbContext dbc, CmsResource resource, CmsResource.CmsResourceDeleteMode siblingMode) throws CmsException { // upgrade a potential inherited, non-shared lock into a common lock CmsLock currentLock = getLock(dbc, resource); if (currentLock.getEditionLock().isDirectlyInherited()) { // upgrade the lock status if required lockResource(dbc, resource, CmsLockType.EXCLUSIVE); } // check if siblings of the resource exist and must be deleted as well if (resource.isFolder()) { // folder can have no siblings siblingMode = CmsResource.DELETE_PRESERVE_SIBLINGS; } // if selected, add all siblings of this resource to the list of resources to be deleted boolean allSiblingsRemoved; List resources; if (siblingMode == CmsResource.DELETE_REMOVE_SIBLINGS) { resources = new ArrayList(readSiblings(dbc, resource, CmsResourceFilter.ALL)); allSiblingsRemoved = true; // ensure that the resource requested to be deleted is the last resource that gets actually deleted // to keep the shared locks of the siblings while those get deleted. resources.remove(resource); resources.add(resource); } else { // only delete the resource, no siblings resources = Collections.singletonList(resource); allSiblingsRemoved = false; } int size = resources.size(); // if we have only one resource no further check is required if (size > 1) { CmsMultiException me = new CmsMultiException(); // ensure that each sibling is unlocked or locked by the current user for (int i = 0; i < size; i++) { CmsResource currentResource = resources.get(i); currentLock = getLock(dbc, currentResource); if (!currentLock.getEditionLock().isUnlocked() && !currentLock.isOwnedBy(dbc.currentUser())) { // the resource is locked by a user different from the current user CmsRequestContext context = dbc.getRequestContext(); me.addException( new CmsLockException( org.opencms.lock.Messages.get().container( org.opencms.lock.Messages.ERR_SIBLING_LOCKED_2, context.getSitePath(currentResource), context.getSitePath(resource)))); } } if (!me.getExceptions().isEmpty()) { throw me; } } boolean removeAce = true; if (resource.isFolder()) { // check if the folder has any resources in it Iterator childResources = getVfsDriver( dbc).readChildResources(dbc, dbc.currentProject(), resource, true, true).iterator(); CmsUUID projectId = CmsProject.ONLINE_PROJECT_ID; if (dbc.currentProject().isOnlineProject()) { projectId = CmsUUID.getOpenCmsUUID(); // HACK: to get an offline project id } // collect the names of the resources inside the folder, excluding the moved resources StringBuffer errorResNames = new StringBuffer(128); while (childResources.hasNext()) { CmsResource errorRes = childResources.next(); if (errorRes.getState().isDeleted()) { continue; } // if deleting offline, or not moved, or just renamed inside the deleted folder // so, it may remain some orphan online entries for moved resources // which will be fixed during the publishing of the moved resources boolean error = !dbc.currentProject().isOnlineProject(); if (!error) { try { String originalPath = getVfsDriver( dbc).readResource(dbc, projectId, errorRes.getRootPath(), true).getRootPath(); error = originalPath.equals(errorRes.getRootPath()) || originalPath.startsWith(resource.getRootPath()); } catch (CmsVfsResourceNotFoundException e) { // ignore } } if (error) { if (errorResNames.length() != 0) { errorResNames.append(", "); } errorResNames.append("[" + dbc.removeSiteRoot(errorRes.getRootPath()) + "]"); } } // the current implementation only deletes empty folders if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(errorResNames.toString())) { throw new CmsVfsException( org.opencms.db.generic.Messages.get().container( org.opencms.db.generic.Messages.ERR_DELETE_NONEMTY_FOLDER_2, dbc.removeSiteRoot(resource.getRootPath()), errorResNames.toString())); } } // delete all collected resources for (int i = 0; i < size; i++) { CmsResource currentResource = resources.get(i); // try to delete/remove the resource only if the user has write access to the resource // check permissions only for the sibling, the resource it self was already checked or // is to be removed without write permissions, ie. while deleting a folder if (!currentResource.equals(resource) && (I_CmsPermissionHandler.PERM_ALLOWED != m_securityManager.hasPermissions( dbc, currentResource, CmsPermissionSet.ACCESS_WRITE, LockCheck.yes, CmsResourceFilter.ALL))) { // no write access to sibling - must keep ACE (see below) allSiblingsRemoved = false; } else { // write access to sibling granted boolean existsOnline = (getVfsDriver(dbc).validateStructureIdExists( dbc, CmsProject.ONLINE_PROJECT_ID, currentResource.getStructureId()) || !(currentResource.getState().equals(CmsResource.STATE_NEW))); if (!existsOnline) { // the resource does not exist online => remove the resource // this means the resource is "new" (blue) in the offline project // delete all properties of this resource deleteAllProperties(dbc, currentResource.getRootPath()); if (currentResource.isFolder()) { getVfsDriver(dbc).removeFolder(dbc, dbc.currentProject(), currentResource); } else { // check labels if (currentResource.isLabeled() && !labelResource(dbc, currentResource, null, 2)) { // update the resource flags to "un label" the other siblings int flags = currentResource.getFlags(); flags &= ~CmsResource.FLAG_LABELED; currentResource.setFlags(flags); } getVfsDriver(dbc).removeFile(dbc, dbc.currentProject().getUuid(), currentResource); } // ensure an exclusive lock is removed in the lock manager for a deleted new resource, // otherwise it would "stick" in the lock manager, preventing other users from creating // a file with the same name (issue with temp files in editor) m_lockManager.removeDeletedResource(dbc, currentResource.getRootPath()); // delete relations getVfsDriver(dbc).deleteRelations( dbc, dbc.currentProject().getUuid(), currentResource, CmsRelationFilter.TARGETS); getVfsDriver(dbc).deleteUrlNameMappingEntries( dbc, false, CmsUrlNameMappingFilter.ALL.filterStructureId(currentResource.getStructureId())); getVfsDriver(dbc).deleteAliases( dbc, dbc.currentProject(), new CmsAliasFilter(null, null, currentResource.getStructureId())); log( dbc, new CmsLogEntry( dbc, currentResource.getStructureId(), CmsLogEntryType.RESOURCE_NEW_DELETED, new String[] {currentResource.getRootPath()}), true); } else { // the resource exists online => mark the resource as deleted // structure record is removed during next publish // if one (or more) siblings are not removed, the ACE can not be removed removeAce = false; // set resource state to deleted currentResource.setState(CmsResource.STATE_DELETED); getVfsDriver( dbc).writeResourceState(dbc, dbc.currentProject(), currentResource, UPDATE_STRUCTURE, false); // update the project ID getVfsDriver(dbc).writeLastModifiedProjectId( dbc, dbc.currentProject(), dbc.currentProject().getUuid(), currentResource); // log it log( dbc, new CmsLogEntry( dbc, currentResource.getStructureId(), CmsLogEntryType.RESOURCE_DELETED, new String[] {currentResource.getRootPath()}), true); } } } if ((resource.getSiblingCount() <= 1) || allSiblingsRemoved) { if (removeAce) { // remove the access control entries getUserDriver(dbc).removeAccessControlEntries(dbc, dbc.currentProject(), resource.getResourceId()); } } // flush all caches m_monitor.clearAccessControlListCache(); m_monitor.flushCache( CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST, CmsMemoryMonitor.CacheType.PROJECT_RESOURCES); Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_RESOURCES, resources); eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_DELETED, eventData)); } /** * Deletes an entry in the published resource table.

* * @param dbc the current database context * @param resourceName The name of the resource to be deleted in the static export * @param linkType the type of resource deleted (0= non-parameter, 1=parameter) * @param linkParameter the parameters of the resource * * @throws CmsException if something goes wrong */ public void deleteStaticExportPublishedResource( CmsDbContext dbc, String resourceName, int linkType, String linkParameter) throws CmsException { getProjectDriver(dbc).deleteStaticExportPublishedResource(dbc, resourceName, linkType, linkParameter); } /** * Deletes a user, where all permissions and resources attributes of the user * were transfered to a replacement user, if given.

* * Only users, which are in the group "administrators" are granted.

* * @param dbc the current database context * @param project the current project * @param username the name of the user to be deleted * @param replacementUsername the name of the user to be transfered, can be null * * @throws CmsException if operation was not successful */ public void deleteUser(CmsDbContext dbc, CmsProject project, String username, String replacementUsername) throws CmsException { // Test if the users exists CmsUser user = readUser(dbc, username); CmsUser replacementUser = null; if (replacementUsername != null) { replacementUser = readUser(dbc, replacementUsername); } CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); boolean withACEs = true; if (replacementUser == null) { withACEs = false; replacementUser = readUser(dbc, OpenCms.getDefaultUsers().getUserDeletedResource()); } boolean isVfsManager = m_securityManager.hasRole(dbc, replacementUser, CmsRole.VFS_MANAGER); // iterate groups and roles for (int i = 0; i < 2; i++) { boolean readRoles = i != 0; Iterator itGroups = getGroupsOfUser( dbc, username, "", true, readRoles, true, dbc.getRequestContext().getRemoteAddress()).iterator(); while (itGroups.hasNext()) { CmsGroup group = itGroups.next(); if (!isVfsManager) { // add replacement user to user groups if (!userInGroup(dbc, replacementUser.getName(), group.getName(), readRoles)) { addUserToGroup(dbc, replacementUser.getName(), group.getName(), readRoles); } } // remove user from groups if (userInGroup(dbc, username, group.getName(), readRoles)) { // we need this additional check because removing a user from a group // may also automatically remove him from other groups if the group was // associated with a role. removeUserFromGroup(dbc, username, group.getName(), readRoles); } } } // remove all locks set for the deleted user m_lockManager.removeLocks(user.getId()); // offline if (dbc.getProjectId().isNullUUID()) { // offline project available transferPrincipalResources(dbc, project, user.getId(), replacementUser.getId(), withACEs); } // online transferPrincipalResources(dbc, onlineProject, user.getId(), replacementUser.getId(), withACEs); getUserDriver(dbc).removeAccessControlEntriesForPrincipal(dbc, project, onlineProject, user.getId()); getHistoryDriver(dbc).writePrincipal(dbc, user); getUserDriver(dbc).deleteUser(dbc, username); // delete user from cache m_monitor.clearUserCache(user); if (!dbc.getProjectId().isNullUUID()) { // user modified event is not needed return; } // fire user modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); eventData.put(I_CmsEventListener.KEY_USER_NAME, user.getName()); eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_DELETE_USER); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); } /** * Destroys this driver manager and releases all allocated resources.

*/ public void destroy() { try { if (m_projectDriver != null) { try { m_projectDriver.destroy(); } catch (Throwable t) { LOG.error(Messages.get().getBundle().key(Messages.ERR_CLOSE_PROJECT_DRIVER_0), t); } m_projectDriver = null; } if (m_userDriver != null) { try { m_userDriver.destroy(); } catch (Throwable t) { LOG.error(Messages.get().getBundle().key(Messages.ERR_CLOSE_USER_DRIVER_0), t); } m_userDriver = null; } if (m_vfsDriver != null) { try { m_vfsDriver.destroy(); } catch (Throwable t) { LOG.error(Messages.get().getBundle().key(Messages.ERR_CLOSE_VFS_DRIVER_0), t); } m_vfsDriver = null; } if (m_historyDriver != null) { try { m_historyDriver.destroy(); } catch (Throwable t) { LOG.error(Messages.get().getBundle().key(Messages.ERR_CLOSE_HISTORY_DRIVER_0), t); } m_historyDriver = null; } if (m_pools != null) { for (CmsDbPoolV11 pool : m_pools.values()) { try { pool.close(); if (CmsLog.INIT.isDebugEnabled()) { CmsLog.INIT.debug(Messages.get().getBundle().key(Messages.INIT_CLOSE_CONN_POOL_1, pool)); } } catch (Throwable t) { LOG.error(Messages.get().getBundle().key(Messages.LOG_CLOSE_CONN_POOL_ERROR_1, pool), t); } } m_pools.clear(); } m_monitor.clearCache(); m_lockManager = null; m_htmlLinkValidator = null; } catch (Throwable t) { // ignore } if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info( Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_DESTROY_1, getClass().getName())); } } /** * Tests if a resource with the given resourceId does already exist in the Database.

* * @param dbc the current database context * @param resourceId the resource id to test for * @return true if a resource with the given id was found, false otherweise * @throws CmsException if something goes wrong */ public boolean existsResourceId(CmsDbContext dbc, CmsUUID resourceId) throws CmsException { return getVfsDriver(dbc).validateResourceIdExists(dbc, dbc.currentProject().getUuid(), resourceId); } /** * Fills the given publish list with the the VFS resources that actually get published.

* * Please refer to the source code of this method for the rules on how to decide whether a * new/changed/deleted {@link CmsResource} object can be published or not.

* * @param dbc the current database context * @param publishList must be initialized with basic publish information (Project or direct publish operation), * the given publish list will be filled with all new/changed/deleted files from the current * (offline) project that will be actually published * * @throws CmsException if something goes wrong * * @see org.opencms.db.CmsPublishList */ public void fillPublishList(CmsDbContext dbc, CmsPublishList publishList) throws CmsException { if (!publishList.isDirectPublish()) { // when publishing a project // all modified resources with the last change done in the current project are candidates if unlocked List folderList = getVfsDriver(dbc).readResourceTree( dbc, dbc.currentProject().getUuid(), CmsDriverManager.READ_IGNORE_PARENT, CmsDriverManager.READ_IGNORE_TYPE, CmsResource.STATE_UNCHANGED, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READMODE_INCLUDE_TREE | CmsDriverManager.READMODE_INCLUDE_PROJECT | CmsDriverManager.READMODE_EXCLUDE_STATE | CmsDriverManager.READMODE_ONLY_FOLDERS); List fileList = getVfsDriver(dbc).readResourceTree( dbc, dbc.currentProject().getUuid(), CmsDriverManager.READ_IGNORE_PARENT, CmsDriverManager.READ_IGNORE_TYPE, CmsResource.STATE_UNCHANGED, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READMODE_INCLUDE_TREE | CmsDriverManager.READMODE_INCLUDE_PROJECT | CmsDriverManager.READMODE_EXCLUDE_STATE | CmsDriverManager.READMODE_ONLY_FILES); CmsRequestContext context = dbc.getRequestContext(); if ((context != null) && (context.getAttribute(CmsDefaultWorkflowManager.ATTR_CHECK_PUBLISH_RESOURCE_LIMIT) != null)) { // check if total size and if it exceeds the resource limit and the request // context attribute is set, throw an exception. // we do it here since filterResources() can be very expensive on large resource lists int limit = OpenCms.getWorkflowManager().getResourceLimit(); int total = fileList.size() + folderList.size(); if (total > limit) { throw new CmsTooManyPublishResourcesException(total); } } publishList.addAll(filterResources(dbc, null, folderList), true); publishList.addAll(filterResources(dbc, publishList, fileList), true); } else { // this is a direct publish Iterator it = publishList.getDirectPublishResources().iterator(); while (it.hasNext()) { // iterate all resources in the direct publish list CmsResource directPublishResource = it.next(); if (directPublishResource.isFolder()) { // when publishing a folder directly, // the folder and all modified resources within the tree below this folder // and with the last change done in the current project are candidates if lockable CmsLock lock = getLock(dbc, directPublishResource); if (!directPublishResource.getState().isUnchanged() && lock.isLockableBy(dbc.currentUser())) { try { m_securityManager.checkPermissions( dbc, directPublishResource, CmsPermissionSet.ACCESS_DIRECT_PUBLISH, false, CmsResourceFilter.ALL); publishList.add(directPublishResource, true); } catch (CmsException e) { // skip if not enough permissions } } boolean shouldPublishDeletedSubResources = publishList.isUserPublishList() && directPublishResource.getState().isDeleted(); if (publishList.isPublishSubResources() || shouldPublishDeletedSubResources) { addSubResources(dbc, publishList, directPublishResource, resource -> true); } } else if (directPublishResource.isFile() && !directPublishResource.getState().isUnchanged()) { // when publishing a file directly this file is the only candidate // if it is modified and lockable CmsLock lock = getLock(dbc, directPublishResource); if (lock.isLockableBy(dbc.currentUser())) { // check permissions try { m_securityManager.checkPermissions( dbc, directPublishResource, CmsPermissionSet.ACCESS_DIRECT_PUBLISH, false, CmsResourceFilter.ALL); publishList.add(directPublishResource, true); } catch (CmsException e) { // skip if not enough permissions } } } } } // Step 2: if desired, extend the list of files to publish with related siblings if (publishList.isPublishSiblings()) { List publishFiles = publishList.getFileList(); int size = publishFiles.size(); // Improved: first calculate closure of all siblings, then filter and add them Set siblingsClosure = new HashSet(publishFiles); for (int i = 0; i < size; i++) { CmsResource currentFile = publishFiles.get(i); if (currentFile.getSiblingCount() > 1) { siblingsClosure.addAll(readSiblings(dbc, currentFile, CmsResourceFilter.ALL_MODIFIED)); } } publishList.addAll(filterSiblings(dbc, publishList, siblingsClosure), true); } publishList.initialize(); } /** * Returns the list of access control entries of a resource given its name.

* * @param dbc the current database context * @param resource the resource to read the access control entries for * @param getInherited true if the result should include all access control entries inherited by parent folders * * @return a list of {@link CmsAccessControlEntry} objects defining all permissions for the given resource * * @throws CmsException if something goes wrong */ public List getAccessControlEntries( CmsDbContext dbc, CmsResource resource, boolean getInherited) throws CmsException { // get the ACE of the resource itself I_CmsUserDriver userDriver = getUserDriver(dbc); I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); List ace = userDriver.readAccessControlEntries( dbc, dbc.currentProject(), resource.getResourceId(), false); // sort and check if we got the 'overwrite all' ace to stop looking up boolean overwriteAll = sortAceList(ace); // get the ACE of each parent folder // Note: for the immediate parent, get non-inherited access control entries too, // if the resource is not a folder String parentPath = CmsResource.getParentFolder(resource.getRootPath()); int d = (resource.isFolder()) ? 1 : 0; while (!overwriteAll && getInherited && (parentPath != null)) { resource = vfsDriver.readFolder(dbc, dbc.currentProject().getUuid(), parentPath); List entries = userDriver.readAccessControlEntries( dbc, dbc.currentProject(), resource.getResourceId(), d > 0); // sort and check if we got the 'overwrite all' ace to stop looking up overwriteAll = sortAceList(entries); for (CmsAccessControlEntry e : entries) { e.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_INHERITED); } ace.addAll(entries); parentPath = CmsResource.getParentFolder(resource.getRootPath()); d++; } return ace; } /** * Returns the full access control list of a given resource.

* * @param dbc the current database context * @param resource the resource * * @return the access control list of the resource * * @throws CmsException if something goes wrong */ public CmsAccessControlList getAccessControlList(CmsDbContext dbc, CmsResource resource) throws CmsException { return getAccessControlList(dbc, resource, false); } /** * Returns the access control list of a given resource.

* * If inheritedOnly is set, only inherited access control entries * are returned.

* * Note: For file resources, *all* permissions set at the immediate parent folder are inherited, * not only these marked to inherit. * * @param dbc the current database context * @param resource the resource * @param inheritedOnly skip non-inherited entries if set * * @return the access control list of the resource * * @throws CmsException if something goes wrong */ public CmsAccessControlList getAccessControlList(CmsDbContext dbc, CmsResource resource, boolean inheritedOnly) throws CmsException { return getAccessControlList(dbc, resource, inheritedOnly, resource.isFolder(), 0); } /** * Returns the number of active connections managed by a pool.

* * @param dbPoolUrl the url of a pool * @return the number of active connections * @throws CmsDbException if something goes wrong */ public int getActiveConnections(String dbPoolUrl) throws CmsDbException { CmsDbPoolV11 pool = m_pools.get(dbPoolUrl); if (pool == null) { CmsMessageContainer message = Messages.get().container(Messages.ERR_UNKNOWN_POOL_URL_1, dbPoolUrl); throw new CmsDbException(message); } try { return pool.getActiveConnections(); } catch (Exception exc) { CmsMessageContainer message = Messages.get().container(Messages.ERR_ACCESSING_POOL_1, dbPoolUrl); throw new CmsDbException(message, exc); } } /** * Reads all access control entries.

* * @param dbc the current database context * @return all access control entries for the current project (offline/online) * * @throws CmsException if something goes wrong */ public List getAllAccessControlEntries(CmsDbContext dbc) throws CmsException { I_CmsUserDriver userDriver = getUserDriver(dbc); List ace = userDriver.readAccessControlEntries( dbc, dbc.currentProject(), CmsAccessControlEntry.PRINCIPAL_READALL_ID, false); return ace; } /** * Returns all projects which are owned by the current user or which are * accessible by the current user.

* * @param dbc the current database context * @param orgUnit the organizational unit to search project in * @param includeSubOus if to include sub organizational units * * @return a list of objects of type {@link CmsProject} * * @throws CmsException if something goes wrong */ public List getAllAccessibleProjects( CmsDbContext dbc, CmsOrganizationalUnit orgUnit, boolean includeSubOus) throws CmsException { Set projects = new HashSet(); // get the ous where the user has the project manager role List ous = getOrgUnitsForRole( dbc, CmsRole.PROJECT_MANAGER.forOrgUnit(orgUnit.getName()), includeSubOus); // get the groups of the user if needed Set userGroupIds = new HashSet(); Iterator itGroups = getGroupsOfUser(dbc, dbc.currentUser().getName(), false).iterator(); while (itGroups.hasNext()) { CmsGroup group = itGroups.next(); userGroupIds.add(group.getId()); } // TODO: this could be optimize if this method would have an additional parameter 'includeSubOus' // get all projects that might come in question projects.addAll(getProjectDriver(dbc).readProjects(dbc, orgUnit.getName())); // filter hidden and not accessible projects Iterator itProjects = projects.iterator(); while (itProjects.hasNext()) { CmsProject project = itProjects.next(); boolean accessible = true; // if hidden accessible = accessible && !project.isHidden(); if (!includeSubOus) { // if not exact in the given ou accessible = accessible && project.getOuFqn().equals(orgUnit.getName()); } else { // if not in the given ou accessible = accessible && project.getOuFqn().startsWith(orgUnit.getName()); } if (!accessible) { itProjects.remove(); continue; } accessible = false; // online project accessible = accessible || project.isOnlineProject(); // if owner accessible = accessible || project.getOwnerId().equals(dbc.currentUser().getId()); // project managers Iterator itOus = ous.iterator(); while (!accessible && itOus.hasNext()) { CmsOrganizationalUnit ou = itOus.next(); // for project managers check visibility accessible = accessible || project.getOuFqn().startsWith(ou.getName()); } if (!accessible) { // if direct user or manager of project CmsUUID groupId = null; if (userGroupIds.contains(project.getGroupId())) { groupId = project.getGroupId(); } else if (userGroupIds.contains(project.getManagerGroupId())) { groupId = project.getManagerGroupId(); } if (groupId != null) { String oufqn = readGroup(dbc, groupId).getOuFqn(); accessible = accessible || (oufqn.startsWith(dbc.getRequestContext().getOuFqn())); } } if (!accessible) { // remove not accessible project itProjects.remove(); } } List accessibleProjects = new ArrayList(projects); // sort the list of projects based on the project name Collections.sort(accessibleProjects); // ensure the online project is in first place CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); if (accessibleProjects.contains(onlineProject)) { accessibleProjects.remove(onlineProject); } accessibleProjects.add(0, onlineProject); return accessibleProjects; } /** * Returns a list with all projects from history.

* * @param dbc the current database context * * @return list of {@link CmsHistoryProject} objects * with all projects from history. * * @throws CmsException if operation was not successful */ public List getAllHistoricalProjects(CmsDbContext dbc) throws CmsException { // user is allowed to access all existing projects for the ous he has the project_manager role Set manOus = new HashSet( getOrgUnitsForRole(dbc, CmsRole.PROJECT_MANAGER, true)); List projects = getHistoryDriver(dbc).readProjects(dbc); Iterator itProjects = projects.iterator(); while (itProjects.hasNext()) { CmsHistoryProject project = itProjects.next(); if (project.isHidden()) { // project is hidden itProjects.remove(); continue; } if (!project.getOuFqn().startsWith(dbc.currentUser().getOuFqn())) { // project is not visible from the users ou itProjects.remove(); continue; } CmsOrganizationalUnit ou = readOrganizationalUnit(dbc, project.getOuFqn()); if (manOus.contains(ou)) { // user is project manager for this project continue; } else if (project.getOwnerId().equals(dbc.currentUser().getId())) { // user is owner of the project continue; } else { boolean found = false; Iterator itGroups = getGroupsOfUser(dbc, dbc.currentUser().getName(), false).iterator(); while (itGroups.hasNext()) { CmsGroup group = itGroups.next(); if (project.getManagerGroupId().equals(group.getId())) { found = true; break; } } if (found) { // user is member of the manager group of the project continue; } } itProjects.remove(); } return projects; } /** * Returns all projects which are owned by the current user or which are manageable * for the group of the user.

* * @param dbc the current database context * @param orgUnit the organizational unit to search project in * @param includeSubOus if to include sub organizational units * * @return a list of objects of type {@link CmsProject} * * @throws CmsException if operation was not successful */ public List getAllManageableProjects( CmsDbContext dbc, CmsOrganizationalUnit orgUnit, boolean includeSubOus) throws CmsException { Set projects = new HashSet(); // get the ous where the user has the project manager role List ous = getOrgUnitsForRole( dbc, CmsRole.PROJECT_MANAGER.forOrgUnit(orgUnit.getName()), includeSubOus); // get the groups of the user if needed Set userGroupIds = new HashSet(); Iterator itGroups = getGroupsOfUser(dbc, dbc.currentUser().getName(), false).iterator(); while (itGroups.hasNext()) { CmsGroup group = itGroups.next(); userGroupIds.add(group.getId()); } // TODO: this could be optimize if this method would have an additional parameter 'includeSubOus' // get all projects that might come in question projects.addAll(getProjectDriver(dbc).readProjects(dbc, orgUnit.getName())); // filter hidden and not manageable projects Iterator itProjects = projects.iterator(); while (itProjects.hasNext()) { CmsProject project = itProjects.next(); boolean manageable = true; // if online manageable = manageable && !project.isOnlineProject(); // if hidden manageable = manageable && !project.isHidden(); if (!includeSubOus) { // if not exact in the given ou manageable = manageable && project.getOuFqn().equals(orgUnit.getName()); } else { // if not in the given ou manageable = manageable && project.getOuFqn().startsWith(orgUnit.getName()); } if (!manageable) { itProjects.remove(); continue; } manageable = false; // if owner manageable = manageable || project.getOwnerId().equals(dbc.currentUser().getId()); // project managers Iterator itOus = ous.iterator(); while (!manageable && itOus.hasNext()) { CmsOrganizationalUnit ou = itOus.next(); // for project managers check visibility manageable = manageable || project.getOuFqn().startsWith(ou.getName()); } if (!manageable) { // if manager of project if (userGroupIds.contains(project.getManagerGroupId())) { String oufqn = readGroup(dbc, project.getManagerGroupId()).getOuFqn(); manageable = manageable || (oufqn.startsWith(dbc.getRequestContext().getOuFqn())); } } if (!manageable) { // remove not accessible project itProjects.remove(); } } List manageableProjects = new ArrayList(projects); // sort the list of projects based on the project name Collections.sort(manageableProjects); // ensure the online project is not in the list CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); if (manageableProjects.contains(onlineProject)) { manageableProjects.remove(onlineProject); } return manageableProjects; } /** * Returns all child groups of a group.

* * @param dbc the current database context * @param group the group to get the child for * @param includeSubChildren if set also returns all sub-child groups of the given group * * @return a list of all child {@link CmsGroup} objects * * @throws CmsException if operation was not successful */ public List getChildren(CmsDbContext dbc, CmsGroup group, boolean includeSubChildren) throws CmsException { if (!includeSubChildren) { return getUserDriver(dbc).readChildGroups(dbc, group.getName()); } Set allChildren = new TreeSet(); // iterate all child groups Iterator it = getUserDriver(dbc).readChildGroups(dbc, group.getName()).iterator(); while (it.hasNext()) { CmsGroup child = it.next(); // add the group itself allChildren.add(child); // now get all sub-children for each group allChildren.addAll(getChildren(dbc, child, true)); } return new ArrayList(allChildren); } /** * Returns the date when the resource was last visited by the user.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param user the user to check the date * @param resource the resource to check the date * * @return the date when the resource was last visited by the user * * @throws CmsException if something goes wrong */ public long getDateLastVisitedBy(CmsDbContext dbc, String poolName, CmsUser user, CmsResource resource) throws CmsException { return m_subscriptionDriver.getDateLastVisitedBy(dbc, poolName, user, resource); } /** * Returns all groups of the given organizational unit.

* * @param dbc the current db context * @param orgUnit the organizational unit to get the groups for * @param includeSubOus if all groups of sub-organizational units should be retrieved too * @param readRoles if to read roles or groups * * @return all {@link CmsGroup} objects in the organizational unit * * @throws CmsException if operation was not successful * * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String) * @see org.opencms.security.CmsOrgUnitManager#getGroups(CmsObject, String, boolean) */ public List getGroups( CmsDbContext dbc, CmsOrganizationalUnit orgUnit, boolean includeSubOus, boolean readRoles) throws CmsException { return getUserDriver(dbc).getGroups(dbc, orgUnit, includeSubOus, readRoles); } /** * Returns the groups of an user filtered by the specified IP address.

* * @param dbc the current database context * @param username the name of the user * @param readRoles if to read roles or groups * * @return the groups of the given user, as a list of {@link CmsGroup} objects * * @throws CmsException if something goes wrong */ public List getGroupsOfUser(CmsDbContext dbc, String username, boolean readRoles) throws CmsException { return getGroupsOfUser(dbc, username, "", true, readRoles, false, dbc.getRequestContext().getRemoteAddress()); } /** * Returns the groups of an user filtered by the specified IP address.

* * @param dbc the current database context * @param username the name of the user * @param ouFqn the fully qualified name of the organizational unit to restrict the result set for * @param includeChildOus include groups of child organizational units * @param readRoles if to read roles or groups * @param directGroupsOnly if set only the direct assigned groups will be returned, if not also indirect groups * @param remoteAddress the IP address to filter the groups in the result list * * @return a list of {@link CmsGroup} objects * * @throws CmsException if operation was not successful */ public List getGroupsOfUser( CmsDbContext dbc, String username, String ouFqn, boolean includeChildOus, boolean readRoles, boolean directGroupsOnly, String remoteAddress) throws CmsException { CmsUser user = readUser(dbc, username); String prefix = ouFqn + "_" + includeChildOus + "_" + directGroupsOnly + "_" + readRoles + "_" + remoteAddress; String cacheKey = m_keyGenerator.getCacheKeyForUserGroups(prefix, dbc, user); List groups = m_monitor.getCachedUserGroups(user.getId(), cacheKey); if (groups == null) { // get all groups of the user List directGroups = getUserDriver(dbc).readGroupsOfUser( dbc, user.getId(), readRoles ? "" : ouFqn, readRoles ? true : includeChildOus, remoteAddress, readRoles); Set allGroups = new HashSet(); if (!readRoles) { allGroups.addAll(directGroups); } if (!directGroupsOnly) { if (!readRoles) { // now get all parents of the groups for (int i = 0; i < directGroups.size(); i++) { CmsGroup parent = getParent(dbc, directGroups.get(i).getName()); while ((parent != null) && (!allGroups.contains(parent))) { if (parent.getOuFqn().startsWith(ouFqn)) { allGroups.add(parent); } // read next parent group parent = getParent(dbc, parent.getName()); } } } } if (readRoles) { // for each for role for (int i = 0; i < directGroups.size(); i++) { CmsGroup group = directGroups.get(i); CmsRole role = CmsRole.valueOf(group); if (!includeChildOus && role.getOuFqn().equals(ouFqn)) { allGroups.add(group); } if (includeChildOus && role.getOuFqn().startsWith(ouFqn)) { allGroups.add(group); } if (directGroupsOnly || (!includeChildOus && !role.getOuFqn().equals(ouFqn))) { // if roles of child OUs are not requested and the role does not belong to the requested OU don't include the role children continue; } CmsOrganizationalUnit currentOu = readOrganizationalUnit(dbc, group.getOuFqn()); boolean readChildRoleGroups = true; if (currentOu.hasFlagWebuser() && role.forOrgUnit(null).equals(CmsRole.ACCOUNT_MANAGER)) { readChildRoleGroups = false; } if (readChildRoleGroups) { // get the child roles Iterator itChildRoles = role.getChildren(true).iterator(); while (itChildRoles.hasNext()) { CmsRole childRole = itChildRoles.next(); if (childRole.isSystemRole()) { if (canReadRoleInOu(currentOu, childRole)) { // include system roles only try { allGroups.add(readGroup(dbc, childRole.getGroupName())); } catch (CmsDataAccessException e) { // should not happen, log error if it does LOG.error(e.getLocalizedMessage(), e); } } } } } else { LOG.info("Skipping child role group check for web user OU " + currentOu.getName()); } if (includeChildOus) { // if needed include the roles of child ous Iterator itSubOus = getOrganizationalUnits( dbc, readOrganizationalUnit(dbc, group.getOuFqn()), true).iterator(); while (itSubOus.hasNext()) { CmsOrganizationalUnit subOu = itSubOus.next(); // add role in child ou try { if (canReadRoleInOu(subOu, role)) { allGroups.add(readGroup(dbc, role.forOrgUnit(subOu.getName()).getGroupName())); } } catch (CmsDbEntryNotFoundException e) { // ignore, this may happen while deleting an orgunit if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } // add child roles in child ous Iterator itChildRoles = role.getChildren(true).iterator(); while (itChildRoles.hasNext()) { CmsRole childRole = itChildRoles.next(); try { if (canReadRoleInOu(subOu, childRole)) { allGroups.add( readGroup(dbc, childRole.forOrgUnit(subOu.getName()).getGroupName())); } } catch (CmsDbEntryNotFoundException e) { // ignore, this may happen while deleting an orgunit if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } } } } } } // make group list unmodifiable for caching groups = Collections.unmodifiableList(new ArrayList(allGroups)); if (dbc.getProjectId().isNullUUID()) { m_monitor.getGroupListCache().setGroups(user, cacheKey, groups); } } return groups; } /** * Returns the history driver.

* * @return the history driver */ public I_CmsHistoryDriver getHistoryDriver() { return m_historyDriver; } /** * Returns the history driver for a given database context.

* * @param dbc the database context * @return the history driver for the database context */ public I_CmsHistoryDriver getHistoryDriver(CmsDbContext dbc) { if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { return m_historyDriver; } I_CmsHistoryDriver driver = dbc.getHistoryDriver(dbc.getProjectId()); return driver != null ? driver : m_historyDriver; } /** * Returns the number of idle connections managed by a pool.

* * @param dbPoolUrl the url of a pool * @return the number of idle connections * @throws CmsDbException if something goes wrong */ public int getIdleConnections(String dbPoolUrl) throws CmsDbException { CmsDbPoolV11 pool = m_pools.get(dbPoolUrl); if (pool == null) { CmsMessageContainer message = Messages.get().container(Messages.ERR_UNKNOWN_POOL_URL_1, dbPoolUrl); throw new CmsDbException(message); } try { return pool.getIdleConnections(); } catch (Exception exc) { CmsMessageContainer message = Messages.get().container(Messages.ERR_ACCESSING_POOL_1, dbPoolUrl); throw new CmsDbException(message, exc); } } /** * Returns the lock state of a resource.

* * @param dbc the current database context * @param resource the resource to return the lock state for * * @return the lock state of the resource * * @throws CmsException if something goes wrong */ public CmsLock getLock(CmsDbContext dbc, CmsResource resource) throws CmsException { return m_lockManager.getLock(dbc, resource); } /** * Returns all locked resources in a given folder.

* * @param dbc the current database context * @param resource the folder to search in * @param filter the lock filter * * @return a list of locked resource paths (relative to current site) * * @throws CmsException if the current project is locked */ public List getLockedResources(CmsDbContext dbc, CmsResource resource, CmsLockFilter filter) throws CmsException { List lockedResources = new ArrayList(); // get locked resources Iterator it = m_lockManager.getLocks(dbc, resource.getRootPath(), filter).iterator(); while (it.hasNext()) { CmsLock lock = it.next(); lockedResources.add(dbc.removeSiteRoot(lock.getResourceName())); } Collections.sort(lockedResources); return lockedResources; } /** * Returns all locked resources in a given folder.

* * @param dbc the current database context * @param resource the folder to search in * @param filter the lock filter * * @return a list of locked resources * * @throws CmsException if the current project is locked */ public List getLockedResourcesObjects(CmsDbContext dbc, CmsResource resource, CmsLockFilter filter) throws CmsException { return m_lockManager.getLockedResources(dbc, resource, filter); } /** * Returns all locked resources in a given folder, but uses a cache for resource lookups.

* * @param dbc the current database context * @param resource the folder to search in * @param filter the lock filter * @param cache the cache to use for resource lookups * * @return a list of locked resources * * @throws CmsException if the current project is locked */ public List getLockedResourcesObjectsWithCache( CmsDbContext dbc, CmsResource resource, CmsLockFilter filter, Map cache) throws CmsException { return m_lockManager.getLockedResourcesWithCache(dbc, resource, filter, cache); } /** * Returns all log entries matching the given filter.

* * @param dbc the current db context * @param filter the filter to match the log entries * * @return all log entries matching the given filter * * @throws CmsException if something goes wrong * * @see CmsSecurityManager#getLogEntries(CmsRequestContext, CmsLogFilter) */ public List getLogEntries(CmsDbContext dbc, CmsLogFilter filter) throws CmsException { updateLog(dbc); return m_projectDriver.readLog(dbc, filter); } /** * Returns the next publish tag for the published historical resources.

* * @param dbc the current database context * * @return the next available publish tag */ public int getNextPublishTag(CmsDbContext dbc) { return getHistoryDriver(dbc).readNextPublishTag(dbc); } /** * Returns all child organizational units of the given parent organizational unit including * hierarchical deeper organization units if needed.

* * @param dbc the current db context * @param parent the parent organizational unit, or null for the root * @param includeChildren if hierarchical deeper organization units should also be returned * * @return a list of {@link CmsOrganizationalUnit} objects * * @throws CmsException if operation was not successful * * @see org.opencms.security.CmsOrgUnitManager#getOrganizationalUnits(CmsObject, String, boolean) */ public List getOrganizationalUnits( CmsDbContext dbc, CmsOrganizationalUnit parent, boolean includeChildren) throws CmsException { if (parent == null) { throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_PARENT_ORGUNIT_NULL_0)); } return getUserDriver(dbc).getOrganizationalUnits(dbc, parent, includeChildren); } /** * Returns all the organizational units for which the current user has the given role.

* * @param dbc the current database context * @param role the role to check * @param includeSubOus if sub organizational units should be included in the search * * @return a list of {@link org.opencms.security.CmsOrganizationalUnit} objects * * @throws CmsException if something goes wrong */ public List getOrgUnitsForRole(CmsDbContext dbc, CmsRole role, boolean includeSubOus) throws CmsException { String ouFqn = role.getOuFqn(); if (ouFqn == null) { ouFqn = ""; role = role.forOrgUnit(""); } CmsOrganizationalUnit ou = readOrganizationalUnit(dbc, ouFqn); List orgUnits = new ArrayList(); if (m_securityManager.hasRole(dbc, dbc.currentUser(), role)) { orgUnits.add(ou); } if (includeSubOus) { Iterator it = getOrganizationalUnits(dbc, ou, true).iterator(); while (it.hasNext()) { CmsOrganizationalUnit orgUnit = it.next(); if (m_securityManager.hasRole(dbc, dbc.currentUser(), role.forOrgUnit(orgUnit.getName()))) { orgUnits.add(orgUnit); } } } return orgUnits; } /** * Returns the parent group of a group.

* * @param dbc the current database context * @param groupname the name of the group * * @return group the parent group or null * * @throws CmsException if operation was not successful */ public CmsGroup getParent(CmsDbContext dbc, String groupname) throws CmsException { CmsGroup group = readGroup(dbc, groupname); if (group.getParentId().isNullUUID()) { return null; } // try to read from cache CmsGroup parent = m_monitor.getCachedGroup(group.getParentId().toString()); if (parent == null) { parent = getUserDriver(dbc).readGroup(dbc, group.getParentId()); m_monitor.cacheGroup(parent); } return parent; } /** * Returns the set of permissions of the current user for a given resource.

* * @param dbc the current database context * @param resource the resource * @param user the user * * @return bit set with allowed permissions * * @throws CmsException if something goes wrong */ public CmsPermissionSetCustom getPermissions(CmsDbContext dbc, CmsResource resource, CmsUser user) throws CmsException { CmsAccessControlList acList = getAccessControlList(dbc, resource, false); List groups = getGroupsOfUser(dbc, user.getName(), false); List roles = getRolesForUser(dbc, user); CmsPermissionSetCustom permissions = acList.getPermissions(user, groups, roles); if (acList.getExclusiveAccessPrincipals().size() > 0) { long now; @SuppressWarnings("unchecked") Supplier alternativeClock = (Supplier)(dbc.getRequestContext().getAttribute( ATTR_EXCLUSIVE_ACCESS_CLOCK)); if (alternativeClock != null) { // used for testing now = alternativeClock.get().longValue(); } else { // *NOT* using dbc.getRequestContext().getRequestTime(), even though that value is used for normal resource availability checks, because // that value may be manipulated by some workplace classes, and we want the real time for permission checks now = System.currentTimeMillis(); } permissions.setCacheable(false); // resources going in/out of availability can change permissions - don't cache if (!resource.isReleasedAndNotExpired(now)) { boolean hasExclusiveAccess = false; for (CmsGroup group : groups) { if (acList.getExclusiveAccessPrincipals().contains(group.getId())) { hasExclusiveAccess = true; break; } } hasExclusiveAccess |= acList.getExclusiveAccessPrincipals().contains(user.getId()); if (!hasExclusiveAccess) { permissions.denyPermissions(CmsPermissionSet.PERMISSION_FULL); } } } return permissions; } /** * Returns the project driver.

* * @return the project driver */ public I_CmsProjectDriver getProjectDriver() { return m_projectDriver; } /** * Returns the project driver for a given DB context.

* * @param dbc the database context * * @return the project driver for the database context */ public I_CmsProjectDriver getProjectDriver(CmsDbContext dbc) { if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { return m_projectDriver; } I_CmsProjectDriver driver = dbc.getProjectDriver(dbc.getProjectId()); return driver != null ? driver : m_projectDriver; } /** * Returns either the project driver for the DB context (if it has one) or a default project driver.

* * @param dbc the DB context * @param defaultDriver the driver which should be returned if there is no project driver for the DB context * * @return either the project driver for the DB context, or the default driver */ public I_CmsProjectDriver getProjectDriver(CmsDbContext dbc, I_CmsProjectDriver defaultDriver) { if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { return defaultDriver; } I_CmsProjectDriver driver = dbc.getProjectDriver(dbc.getProjectId()); return driver != null ? driver : defaultDriver; } /** * Returns the uuid id for the given id.

* * TODO: remove this method as soon as possible * * @param dbc the current database context * @param id the old project id * * @return the new uuid for the given id * * @throws CmsException if something goes wrong */ public CmsUUID getProjectId(CmsDbContext dbc, int id) throws CmsException { Iterator itProjects = getAllAccessibleProjects( dbc, readOrganizationalUnit(dbc, ""), true).iterator(); while (itProjects.hasNext()) { CmsProject project = itProjects.next(); if (project.getUuid().hashCode() == id) { return project.getUuid(); } } return null; } /** * Returns the configuration read from the opencms.properties file.

* * @return the configuration read from the opencms.properties file */ public CmsParameterConfiguration getPropertyConfiguration() { return m_propertyConfiguration; } /** * Returns a new publish list that contains the unpublished resources related * to all resources in the given publish list, the related resources exclude * all resources in the given publish list and also locked (by other users) resources.

* * @param dbc the current database context * @param publishList the publish list to exclude from result * @param filter the relation filter to use to get the related resources * * @return a new publish list that contains the related resources * * @throws CmsException if something goes wrong * * @see org.opencms.publish.CmsPublishManager#getRelatedResourcesToPublish(CmsObject, CmsPublishList) */ public CmsPublishList getRelatedResourcesToPublish( CmsDbContext dbc, CmsPublishList publishList, CmsRelationFilter filter) throws CmsException { Map relations = new HashMap(); // check if progress should be set in the thread A_CmsProgressThread thread = null; if (Thread.currentThread() instanceof A_CmsProgressThread) { thread = (A_CmsProgressThread)Thread.currentThread(); } // get all resources to publish List publishResources = publishList.getAllResources(); Iterator itCheckList = publishResources.iterator(); // iterate over them int count = 0; while (itCheckList.hasNext()) { // set progress in thread count++; if (thread != null) { if (thread.isInterrupted()) { throw new CmsIllegalStateException( org.opencms.workplace.commons.Messages.get().container( org.opencms.workplace.commons.Messages.ERR_PROGRESS_INTERRUPTED_0)); } thread.setProgress((count * 20) / publishResources.size()); thread.setDescription( org.opencms.workplace.commons.Messages.get().getBundle().key( org.opencms.workplace.commons.Messages.GUI_PROGRESS_PUBLISH_STEP1_2, Integer.valueOf(count), Integer.valueOf(publishResources.size()))); } CmsResource checkResource = itCheckList.next(); // get and iterate over all related resources Iterator itRelations = getRelationsForResource(dbc, checkResource, filter).iterator(); while (itRelations.hasNext()) { CmsRelation relation = itRelations.next(); try { // get the target of the relation, see CmsRelation#getTarget(CmsObject, CmsResourceFilter) CmsResource target; try { // first look up by id target = readResource(dbc, relation.getTargetId(), CmsResourceFilter.ALL); } catch (CmsVfsResourceNotFoundException e) { // then look up by name, but from the root site String storedSiteRoot = dbc.getRequestContext().getSiteRoot(); try { dbc.getRequestContext().setSiteRoot(""); target = readResource(dbc, relation.getTargetPath(), CmsResourceFilter.ALL); } finally { dbc.getRequestContext().setSiteRoot(storedSiteRoot); } } CmsLock lock = getLock(dbc, target); // just add resources that may come in question if (!publishResources.contains(target) // is not in the original list && !relations.containsKey(target.getRootPath()) // has not been already added by another relation && !target.getState().isUnchanged() // has been changed && lock.isLockableBy(dbc.currentUser())) { // is lockable by current user relations.put(target.getRootPath(), target); // now check the folder structure CmsResource parent = getVfsDriver(dbc).readParentFolder( dbc, dbc.currentProject().getUuid(), target.getStructureId()); while ((parent != null) && parent.getState().isNew()) { // just add resources that may come in question if (!publishResources.contains(parent) // is not in the original list && !relations.containsKey(parent.getRootPath())) { // has not been already added by another relation relations.put(parent.getRootPath(), parent); } parent = getVfsDriver(dbc).readParentFolder( dbc, dbc.currentProject().getUuid(), parent.getStructureId()); } } } catch (CmsVfsResourceNotFoundException e) { // ignore broken links if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } } } CmsPublishList ret = new CmsPublishList(publishList.getDirectPublishResources(), false, false); ret.addAll(relations.values(), false); ret.initialize(); return ret; } /** * Returns all relations for the given resource matching the given filter.

* * @param dbc the current db context * @param resource the resource to retrieve the relations for * @param filter the filter to match the relation * * @return all relations for the given resource matching the given filter * * @throws CmsException if something goes wrong * * @see CmsSecurityManager#getRelationsForResource(CmsRequestContext, CmsResource, CmsRelationFilter) */ public List getRelationsForResource(CmsDbContext dbc, CmsResource resource, CmsRelationFilter filter) throws CmsException { CmsUUID projectId = getProjectIdForContext(dbc); return getVfsDriver(dbc).readRelations(dbc, projectId, resource, filter); } /** * Returns the list of organizational units the given resource belongs to.

* * @param dbc the current database context * @param resource the resource * * @return list of {@link CmsOrganizationalUnit} objects * * @throws CmsException if something goes wrong */ public List getResourceOrgUnits(CmsDbContext dbc, CmsResource resource) throws CmsException { boolean nullDbcProjectId = (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID(); if (nullDbcProjectId && resourceOrgUnitCachingEnabled) { try { return m_monitor.getResourceOuCache().get(new ResourceOUCacheKey(this, dbc)).getResourceOrgUnits( resource.getRootPath()); } catch (ExecutionException e) { LOG.error(e.getLocalizedMessage(), e); } } List result = getVfsDriver(dbc).getResourceOus( dbc, dbc.currentProject().getUuid(), resource); return result; } /** * Returns all resources of the given organizational unit.

* * @param dbc the current db context * @param orgUnit the organizational unit to get all resources for * * @return all {@link CmsResource} objects in the organizational unit * * @throws CmsException if operation was not successful * * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String) * @see org.opencms.security.CmsOrgUnitManager#getUsers(CmsObject, String, boolean) * @see org.opencms.security.CmsOrgUnitManager#getGroups(CmsObject, String, boolean) */ public List getResourcesForOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit) throws CmsException { return getUserDriver(dbc).getResourcesForOrganizationalUnit(dbc, orgUnit); } /** * Returns all resources associated to a given principal via an ACE with the given permissions.

* * If the includeAttr flag is set it returns also all resources associated to * a given principal through some of following attributes.

* *

    *
  • User Created
  • *
  • User Last Modified
  • *

* * @param dbc the current database context * @param project the to read the entries from * @param principalId the id of the principal * @param permissions a set of permissions to match, can be null for all ACEs * @param includeAttr a flag to include resources associated by attributes * * @return a set of {@link CmsResource} objects * * @throws CmsException if something goes wrong */ public Set getResourcesForPrincipal( CmsDbContext dbc, CmsProject project, CmsUUID principalId, CmsPermissionSet permissions, boolean includeAttr) throws CmsException { Set resources = new HashSet( getVfsDriver(dbc).readResourcesForPrincipalACE(dbc, project, principalId)); if (permissions != null) { Iterator itRes = resources.iterator(); while (itRes.hasNext()) { CmsAccessControlEntry ace = readAccessControlEntry(dbc, itRes.next(), principalId); if ((ace.getPermissions().getPermissions() & permissions.getPermissions()) != permissions.getPermissions()) { // remove if permissions does not match itRes.remove(); } } } if (includeAttr) { resources.addAll(getVfsDriver(dbc).readResourcesForPrincipalAttr(dbc, project, principalId)); } return resources; } /** * Gets the rewrite aliases matching a given filter.

* * @param dbc the current database context * @param filter the filter used for filtering rewrite aliases * * @return the rewrite aliases matching the given filter * * @throws CmsException if something goes wrong */ public List getRewriteAliases(CmsDbContext dbc, CmsRewriteAliasFilter filter) throws CmsException { return getVfsDriver(dbc).readRewriteAliases(dbc, filter); } /** * Collects the groups which constitute a given role.

* * @param dbc the database context * @param roleGroupName the group related to the role * @param directUsersOnly if true, only the group belonging to the entry itself wil * * @return the set of groups which constitute the role * * @throws CmsException if something goes wrong */ public Set getRoleGroups(CmsDbContext dbc, String roleGroupName, boolean directUsersOnly) throws CmsException { return getRoleGroupsImpl(dbc, roleGroupName, directUsersOnly, new HashMap>()); } /** * Collects the groups which constitute a given role.

* * @param dbc the database context * @param roleGroupName the group related to the role * @param directUsersOnly if true, only the group belonging to the entry itself wil * @param accumulator a map for memoizing return values of recursive calls * * @return the set of groups which constitute the role * * @throws CmsException if something goes wrong */ public Set getRoleGroupsImpl( CmsDbContext dbc, String roleGroupName, boolean directUsersOnly, Map> accumulator) throws CmsException { Set result = new HashSet(); if (accumulator.get(roleGroupName) != null) { return accumulator.get(roleGroupName); } CmsGroup group = readGroup(dbc, roleGroupName); // check that the group really exists if ((group == null) || (!group.isRole())) { throw new CmsDbEntryNotFoundException( Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, roleGroupName)); } result.add(group); if (!directUsersOnly) { CmsRole role = CmsRole.valueOf(group); if (role.getParentRole() != null) { try { String parentGroup = role.getParentRole().getGroupName(); // iterate the parent roles result.addAll(getRoleGroupsImpl(dbc, parentGroup, directUsersOnly, accumulator)); } catch (CmsDbEntryNotFoundException e) { // ignore, this may happen while deleting an orgunit if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } } String parentOu = CmsOrganizationalUnit.getParentFqn(group.getOuFqn()); if (parentOu != null) { // iterate the parent ou's result.addAll(getRoleGroupsImpl(dbc, parentOu + group.getSimpleName(), directUsersOnly, accumulator)); } } accumulator.put(roleGroupName, result); return result; } /** * Returns all roles the given user has for the given resource.

* * @param dbc the current database context * @param user the user to check * @param resource the resource to check the roles for * * @return a list of {@link CmsRole} objects * * @throws CmsException if something goes wrong */ public List getRolesForResource(CmsDbContext dbc, CmsUser user, CmsResource resource) throws CmsException { // guest user has no role if (user.isGuestUser()) { return Collections.emptyList(); } // try to read from cache String key = user.getId().toString() + resource.getRootPath(); List result = m_monitor.getCachedRoleList(key); if (result != null) { return result; } result = new ArrayList(); Iterator itOus = getResourceOrgUnits(dbc, resource).iterator(); while (itOus.hasNext()) { CmsOrganizationalUnit ou = itOus.next(); // read all roles of the current user List groups = new ArrayList( getGroupsOfUser( dbc, user.getName(), ou.getName(), false, true, false, dbc.getRequestContext().getRemoteAddress())); // check the roles applying to the given resource Iterator it = groups.iterator(); while (it.hasNext()) { CmsGroup group = it.next(); CmsRole givenRole = CmsRole.valueOf(group).forOrgUnit(null); if (givenRole.isOrganizationalUnitIndependent() || result.contains(givenRole)) { // skip already added roles continue; } result.add(givenRole); } } result = Collections.unmodifiableList(result); m_monitor.cacheRoleList(key, result); return result; } /** * Returns all roles the given user has independent of the resource.

* * @param dbc the current database context * @param user the user to check * * @return a list of {@link CmsRole} objects * * @throws CmsException if something goes wrong */ public List getRolesForUser(CmsDbContext dbc, CmsUser user) throws CmsException { // guest user has no role if (user.isGuestUser()) { return Collections.emptyList(); } // try to read from cache List result = m_monitor.getGroupListCache().getBareRoles(user.getId()); if (result != null) { return result; } result = new ArrayList(); // read all roles of the current user List groups = new ArrayList( getGroupsOfUser(dbc, user.getName(), "", true, true, false, dbc.getRequestContext().getRemoteAddress())); // check the roles applying to the given resource Iterator it = groups.iterator(); while (it.hasNext()) { CmsGroup group = it.next(); CmsRole givenRole = CmsRole.valueOf(group); givenRole = givenRole.forOrgUnit(null); if (!result.contains(givenRole)) { result.add(givenRole); } } result = Collections.unmodifiableList(result); m_monitor.getGroupListCache().setBareRoles(user, result); return result; } /** * Returns the security manager this driver manager belongs to.

* * @return the security manager this driver manager belongs to */ public CmsSecurityManager getSecurityManager() { return m_securityManager; } /** * Returns an instance of the common sql manager.

* * @return an instance of the common sql manager */ public CmsSqlManager getSqlManager() { return m_sqlManager; } /** * Returns the subscription driver of this driver manager.

* * @return a subscription driver */ public I_CmsSubscriptionDriver getSubscriptionDriver() { return m_subscriptionDriver; } /** * Returns the user driver.

* * @return the user driver */ public I_CmsUserDriver getUserDriver() { return m_userDriver; } /** * Returns the user driver for a given database context.

* * @param dbc the database context * * @return the user driver for the database context */ public I_CmsUserDriver getUserDriver(CmsDbContext dbc) { if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { return m_userDriver; } I_CmsUserDriver driver = dbc.getUserDriver(dbc.getProjectId()); return driver != null ? driver : m_userDriver; } /** * Returns either the user driver for the given DB context (if it has one) or a default value instead.

* * @param dbc the DB context * @param defaultDriver the driver that should be returned if no driver for the DB context was found * * @return either the user driver for the DB context, or defaultDriver if none were found */ public I_CmsUserDriver getUserDriver(CmsDbContext dbc, I_CmsUserDriver defaultDriver) { if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { return defaultDriver; } I_CmsUserDriver driver = dbc.getUserDriver(dbc.getProjectId()); return driver != null ? driver : defaultDriver; } /** * Returns all direct users of the given organizational unit.

* * @param dbc the current db context * @param orgUnit the organizational unit to get all users for * @param recursive if all groups of sub-organizational units should be retrieved too * * @return all {@link CmsUser} objects in the organizational unit * * @throws CmsException if operation was not successful * * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String) * @see org.opencms.security.CmsOrgUnitManager#getUsers(CmsObject, String, boolean) */ public List getUsers(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, boolean recursive) throws CmsException { return getUserDriver(dbc).getUsers(dbc, orgUnit, recursive); } /** * Returns a list of users in a group.

* * @param dbc the current database context * @param groupname the name of the group to list users from * @param includeOtherOuUsers include users of other organizational units * @param directUsersOnly if set only the direct assigned users will be returned, * if not also indirect users, ie. members of parent roles, * this parameter only works with roles * @param readRoles if to read roles or groups * * @return all {@link CmsUser} objects in the group * * @throws CmsException if operation was not successful */ public List getUsersOfGroup( CmsDbContext dbc, String groupname, boolean includeOtherOuUsers, boolean directUsersOnly, boolean readRoles) throws CmsException { return internalUsersOfGroup( dbc, CmsOrganizationalUnit.getParentFqn(groupname), groupname, includeOtherOuUsers, directUsersOnly, readRoles); } /** * Returns the given user's publish list.

* * @param dbc the database context * @param userId the user's id * * @return the given user's publish list * * @throws CmsDataAccessException if something goes wrong */ public List getUsersPubList(CmsDbContext dbc, CmsUUID userId) throws CmsDataAccessException { synchronized (m_publishListUpdateLock) { updateLog(dbc); return m_projectDriver.getUsersPubList(dbc, userId); } } /** * Returns all direct users of the given organizational unit, without their additional info.

* * @param dbc the current db context * @param orgUnit the organizational unit to get all users for * @param recursive if all groups of sub-organizational units should be retrieved too * * @return all {@link CmsUser} objects in the organizational unit * * @throws CmsException if operation was not successful * * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String) * @see org.opencms.security.CmsOrgUnitManager#getUsers(CmsObject, String, boolean) */ public List getUsersWithoutAdditionalInfo( CmsDbContext dbc, CmsOrganizationalUnit orgUnit, boolean recursive) throws CmsException { return getUserDriver(dbc).getUsersWithoutAdditionalInfo(dbc, orgUnit, recursive); } /** * Returns the VFS driver.

* * @return the VFS driver */ public I_CmsVfsDriver getVfsDriver() { return m_vfsDriver; } /** * Returns the VFS driver for the given database context.

* * @param dbc the database context * * @return a VFS driver */ public I_CmsVfsDriver getVfsDriver(CmsDbContext dbc) { if ((dbc == null) || (dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) { return m_vfsDriver; } I_CmsVfsDriver driver = dbc.getVfsDriver(dbc.getProjectId()); return driver != null ? driver : m_vfsDriver; } /** * Writes a vector of access control entries as new access control entries of a given resource.

* * Already existing access control entries of this resource are removed before. * Access is granted, if:

*

    *
  • the current user has control permission on the resource
  • *
* * @param dbc the current database context * @param resource the resource * @param acEntries a list of {@link CmsAccessControlEntry} objects * * @throws CmsException if something goes wrong */ public void importAccessControlEntries( CmsDbContext dbc, CmsResource resource, List acEntries) throws CmsException { I_CmsUserDriver userDriver = getUserDriver(dbc); userDriver.removeAccessControlEntries(dbc, dbc.currentProject(), resource.getResourceId()); List fixedAces = new ArrayList<>(); for (CmsAccessControlEntry entry : acEntries) { if (entry.getResource() == null) { entry = new CmsAccessControlEntry( resource.getResourceId(), entry.getPrincipal(), entry.getPermissions(), entry.getFlags()); } fixedAces.add(entry); } Iterator i = fixedAces.iterator(); while (i.hasNext()) { userDriver.writeAccessControlEntry(dbc, dbc.currentProject(), i.next()); } m_monitor.clearAccessControlListCache(); } /** * Imports a rewrite alias.

* * @param dbc the database context * @param siteRoot the site root of the alias * @param source the source of the alias * @param target the target of the alias * @param mode the alias mode * * @return the import result * * @throws CmsException if something goes wrong */ public CmsAliasImportResult importRewriteAlias( CmsDbContext dbc, String siteRoot, String source, String target, CmsAliasMode mode) throws CmsException { I_CmsVfsDriver vfs = getVfsDriver(dbc); List existingAliases = vfs.readRewriteAliases( dbc, new CmsRewriteAliasFilter().setSiteRoot(siteRoot)); CmsUUID idToDelete = null; for (CmsRewriteAlias alias : existingAliases) { if (alias.getPatternString().equals(source)) { idToDelete = alias.getId(); } } if (idToDelete != null) { vfs.deleteRewriteAliases(dbc, new CmsRewriteAliasFilter().setId(idToDelete)); } CmsRewriteAlias alias = new CmsRewriteAlias(new CmsUUID(), siteRoot, source, target, mode); List aliases = new ArrayList(); aliases.add(alias); getVfsDriver(dbc).insertRewriteAliases(dbc, aliases); CmsAliasImportResult result = new CmsAliasImportResult( CmsAliasImportStatus.aliasNew, "OK", source, target, mode); return result; } /** * Creates a new user by import.

* * @param dbc the current database context * @param id the id of the user * @param name the new name for the user * @param password the new password for the user (already encrypted) * @param firstname the firstname of the user * @param lastname the lastname of the user * @param email the email of the user * @param flags the flags for a user (for example {@link I_CmsPrincipal#FLAG_ENABLED}) * @param dateCreated the creation date * @param additionalInfos the additional user infos * * @return the imported user * * @throws CmsException if something goes wrong */ public CmsUser importUser( CmsDbContext dbc, String id, String name, String password, String firstname, String lastname, String email, int flags, long dateCreated, Map additionalInfos) throws CmsException { // no space before or after the name name = name.trim(); // check the user name String userName = CmsOrganizationalUnit.getSimpleName(name); OpenCms.getValidationHandler().checkUserName(userName); if (CmsStringUtil.isEmptyOrWhitespaceOnly(userName)) { throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_BAD_USER_1, userName)); } // check the ou CmsOrganizationalUnit ou = readOrganizationalUnit(dbc, CmsOrganizationalUnit.getParentFqn(name)); // check webuser ou if (ou.hasFlagWebuser() && ((flags & I_CmsPrincipal.FLAG_USER_WEBUSER) == 0)) { flags += I_CmsPrincipal.FLAG_USER_WEBUSER; } CmsUser newUser = getUserDriver(dbc).createUser( dbc, new CmsUUID(id), name, password, firstname, lastname, email, 0, flags, dateCreated, additionalInfos); return newUser; } /** * Increments a counter and returns its value before incrementing.

* * @param dbc the current database context * @param name the name of the counter which should be incremented * * @return the value of the counter * * @throws CmsException if something goes wrong */ public int incrementCounter(CmsDbContext dbc, String name) throws CmsException { return getVfsDriver(dbc).incrementCounter(dbc, name); } /** * Initializes the driver and sets up all required modules and connections.

* * @param configurationManager the configuration manager * @param dbContextFactory the db context factory * * @throws CmsException if something goes wrong * @throws Exception if something goes wrong */ public void init(CmsConfigurationManager configurationManager, I_CmsDbContextFactory dbContextFactory) throws CmsException, Exception { // initialize the access-module. if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_PHASE4_0)); } // store local reference to the memory monitor to avoid multiple lookups through the OpenCms singelton m_monitor = OpenCms.getMemoryMonitor(); CmsSystemConfiguration systemConfiguation = (CmsSystemConfiguration)configurationManager.getConfiguration( CmsSystemConfiguration.class); CmsCacheSettings settings = systemConfiguation.getCacheSettings(); // initialize the key generator m_keyGenerator = (I_CmsCacheKey)Class.forName(settings.getCacheKeyGenerator()).newInstance(); // initialize the HTML link validator m_htmlLinkValidator = new CmsRelationSystemValidator(this); // fills the defaults if needed CmsDbContext dbc1 = dbContextFactory.getDbContext(); getUserDriver().fillDefaults(dbc1); getProjectDriver().fillDefaults(dbc1); // set the driver manager in the publish engine m_publishEngine.setDriverManager(this); // create the root organizational unit if needed CmsDbContext dbc2 = dbContextFactory.getDbContext( new CmsRequestContext( readUser(dbc1, OpenCms.getDefaultUsers().getUserAdmin()), readProject(dbc1, CmsProject.ONLINE_PROJECT_ID), null, CmsSiteMatcher.DEFAULT_MATCHER, "", false, null, null, null, 0, null, null, "", false)); dbc1.clear(); getUserDriver().createRootOrganizationalUnit(dbc2); dbc2.clear(); } /** * Initializes the organizational unit.

* * @param dbc the DB context * @param ou the organizational unit */ public void initOrgUnit(CmsDbContext dbc, CmsOrganizationalUnit ou) { try { dbc.setAttribute(ATTR_INIT_OU, ou); m_userDriver.fillDefaults(dbc); } finally { dbc.removeAttribute(ATTR_INIT_OU); } } /** * Checks if the specified resource is inside the current project.

* * The project "view" is determined by a set of path prefixes. * If the resource starts with any one of this prefixes, it is considered to * be "inside" the project.

* * @param dbc the current database context * @param resourcename the specified resource name (full path) * * @return true, if the specified resource is inside the current project */ public boolean isInsideCurrentProject(CmsDbContext dbc, String resourcename) { List projectResources = null; try { projectResources = readProjectResources(dbc, dbc.currentProject()); } catch (CmsException e) { if (LOG.isErrorEnabled()) { LOG.error( Messages.get().getBundle().key( Messages.LOG_CHECK_RESOURCE_INSIDE_CURRENT_PROJECT_2, resourcename, dbc.currentProject().getName()), e); } return false; } return CmsProject.isInsideProject(projectResources, resourcename); } /** * Checks whether the subscription driver is available.

* * @return true if the subscription driver is available */ public boolean isSubscriptionDriverAvailable() { return m_subscriptionDriver != null; } /** * Checks if a project is the tempfile project.

* @param project the project to test * @return true if the project is the tempfile project */ public boolean isTempfileProject(CmsProject project) { return project.getName().equals("tempFileProject"); } /** * Checks if one of the resources (except the resource itself) * is a sibling in a "labeled" site folder.

* * This method is used when creating a new sibling * (use the newResource parameter & action = 1) * or deleting/importing a resource (call with action = 2).

* * @param dbc the current database context * @param resource the resource * @param newResource absolute path for a resource sibling which will be created * @param action the action which has to be performed (1: create VFS link, 2: all other actions) * * @return true if the flag should be set for the resource, otherwise false * * @throws CmsDataAccessException if something goes wrong */ public boolean labelResource(CmsDbContext dbc, CmsResource resource, String newResource, int action) throws CmsDataAccessException { // get the list of labeled site folders from the runtime property List labeledSites = OpenCms.getWorkplaceManager().getLabelSiteFolders(); if (labeledSites.size() == 0) { // no labeled sites defined, just return false return false; } if (action == 1) { // CASE 1: a new resource is created, check the sites if (!resource.isLabeled()) { // source isn't labeled yet, so check! boolean linkInside = false; boolean sourceInside = false; for (int i = 0; i < labeledSites.size(); i++) { String curSite = labeledSites.get(i); if (newResource.startsWith(curSite)) { // the link lies in a labeled site linkInside = true; } if (resource.getRootPath().startsWith(curSite)) { // the source lies in a labeled site sourceInside = true; } if (linkInside && sourceInside) { break; } } // return true when either source or link is in labeled site, otherwise false return (linkInside != sourceInside); } // resource is already labeled return false; } else { // CASE 2: the resource will be deleted or created (import) // check if at least one of the other siblings resides inside a "labeled site" // and if at least one of the other siblings resides outside a "labeled site" boolean isInside = false; boolean isOutside = false; // check if one of the other vfs links lies in a labeled site folder List siblings = getVfsDriver( dbc).readSiblings(dbc, dbc.currentProject().getUuid(), resource, false); updateContextDates(dbc, siblings); Iterator i = siblings.iterator(); while (i.hasNext() && (!isInside || !isOutside)) { CmsResource currentResource = i.next(); if (currentResource.equals(resource)) { // dont't check the resource itself! continue; } String curPath = currentResource.getRootPath(); boolean curInside = false; for (int k = 0; k < labeledSites.size(); k++) { if (curPath.startsWith(labeledSites.get(k))) { // the link is in the labeled site isInside = true; curInside = true; break; } } if (!curInside) { // the current link was not found in labeled site, so it is outside isOutside = true; } } // now check the new resource name if present if (newResource != null) { boolean curInside = false; for (int k = 0; k < labeledSites.size(); k++) { if (newResource.startsWith(labeledSites.get(k))) { // the new resource is in the labeled site isInside = true; curInside = true; break; } } if (!curInside) { // the new resource was not found in labeled site, so it is outside isOutside = true; } } return (isInside && isOutside); } } /** * Returns the user, who had locked the resource.

* * A user can lock a resource, so he is the only one who can write this * resource. This methods checks, if a resource was locked. * * @param dbc the current database context * @param resource the resource * * @return the user, who had locked the resource * * @throws CmsException will be thrown, if the user has not the rights for this resource */ public CmsUser lockedBy(CmsDbContext dbc, CmsResource resource) throws CmsException { return readUser(dbc, m_lockManager.getLock(dbc, resource).getEditionLock().getUserId()); } /** * Locks a resource.

* * The type parameter controls what kind of lock is used.
* Possible values for this parameter are:
*

    *
  • {@link org.opencms.lock.CmsLockType#EXCLUSIVE}
  • *
  • {@link org.opencms.lock.CmsLockType#TEMPORARY}
  • *
  • {@link org.opencms.lock.CmsLockType#PUBLISH}
  • *

* * @param dbc the current database context * @param resource the resource to lock * @param type type of the lock * * @throws CmsException if something goes wrong * * @see CmsObject#lockResource(String) * @see CmsObject#lockResourceTemporary(String) * @see org.opencms.file.types.I_CmsResourceType#lockResource(CmsObject, CmsSecurityManager, CmsResource, CmsLockType) */ public void lockResource(CmsDbContext dbc, CmsResource resource, CmsLockType type) throws CmsException { // update the resource cache m_monitor.clearResourceCache(); CmsProject project = dbc.currentProject(); // add the resource to the lock dispatcher m_lockManager.addResource(dbc, resource, dbc.currentUser(), project, type); boolean changedProjectLastModified = false; if (!resource.getState().isUnchanged() && !resource.getState().isKeep()) { // update the project flag of a modified resource as "last modified inside the current project" getVfsDriver(dbc).writeLastModifiedProjectId(dbc, project, project.getUuid(), resource); changedProjectLastModified = true; } // we must also clear the permission cache m_monitor.flushCache(CmsMemoryMonitor.CacheType.PERMISSION); // fire resource modification event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put( I_CmsEventListener.KEY_CHANGE, Integer.valueOf(changedProjectLastModified ? CHANGED_PROJECT : NOTHING_CHANGED)); data.put(I_CmsEventListener.KEY_SKIPINDEX, Boolean.TRUE); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Adds the given log entry to the current user's log.

* * This operation works only on memory, to get the log entries actually * written to DB you have to call the {@link #updateLog(CmsDbContext)} method.

* * @param dbc the current database context * @param logEntry the log entry to create * @param force forces the log entry to be counted, * if not only the first log entry in a transaction will be taken into account */ public void log(CmsDbContext dbc, CmsLogEntry logEntry, boolean force) { if (dbc == null) { return; } // check log level if (!logEntry.getType().isActive()) { // do not log inactive entries return; } // if not forcing if (!force) { // operation already logged boolean abort = (dbc.getAttribute(CmsLogEntry.ATTR_LOG_ENTRY) != null); // disabled logging from outside abort |= (dbc.getRequestContext().getAttribute(CmsLogEntry.ATTR_LOG_ENTRY) != null); if (abort) { return; } } // prevent several entries for the same operation dbc.setAttribute(CmsLogEntry.ATTR_LOG_ENTRY, Boolean.TRUE); // keep it for later m_log.add(logEntry); } /** * Attempts to authenticate a user into OpenCms with the given password. * *

The method can be used in multiple modes (see the CmsDriverManager.LoginUserMode enum): Standard mode is the mode for actually logging in a user, * while check mode merely checks the login details without firing the events normally fired during login, and without modifying the user. However, * in the case an incorrect password is given, the invalid login counter is still incremented. * * @param dbc the current database context * @param userName the name of the user to be logged in * @param password the password of the user * @param secondFactorInfo the second factor information for 2FA (may be null) * @param remoteAddress the ip address of the request * @param mode the mode to use (real login or check only) * * @return the logged in user * * @throws CmsAuthentificationException if the login was not successful * @throws CmsDataAccessException in case of errors accessing the database * @throws CmsPasswordEncryptionException in case of errors encrypting the users password */ public CmsUser loginUser( CmsDbContext dbc, String userName, String password, CmsSecondFactorInfo secondFactorInfo, String remoteAddress, LoginUserMode mode) throws CmsAuthentificationException, CmsDataAccessException, CmsPasswordEncryptionException { if (CmsStringUtil.isEmptyOrWhitespaceOnly(password)) { throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_USER_1, userName)); } CmsUser newUser; CmsUser userCopy; try { // read the user from the driver to avoid the cache newUser = getUserDriver(dbc).readUser(dbc, userName, password, remoteAddress); userCopy = newUser.clone(); userName = newUser.getName(); } catch (CmsDbEntryNotFoundException e) { // this indicates that the username / password combination does not exist // any other exception indicates database issues, these are not catched here // check if a user with this name exists at all CmsUser user = null; try { user = readUser(dbc, userName); userName = user.getName(); } catch (CmsDataAccessException e2) { // apparently this user does not exist in the database } if (user != null) { if (dbc.currentUser().isGuestUser()) { // add an invalid login attempt for this user to the storage OpenCms.getLoginManager().addInvalidLogin(userName, remoteAddress); } OpenCms.getLoginManager().checkInvalidLogins(userName, remoteAddress); throw new CmsAuthentificationException( org.opencms.security.Messages.get().container( org.opencms.security.Messages.ERR_LOGIN_FAILED_2, userName, remoteAddress), e); } else { String userOu = CmsOrganizationalUnit.getParentFqn(userName); if (userOu != null) { String parentOu = CmsOrganizationalUnit.getParentFqn(userOu); if (parentOu != null) { // try a higher level ou String uName = CmsOrganizationalUnit.getSimpleName(userName); return loginUser(dbc, parentOu + uName, password, secondFactorInfo, remoteAddress, mode); } } throw new CmsAuthentificationException( org.opencms.security.Messages.get().container( org.opencms.security.Messages.ERR_LOGIN_FAILED_NO_USER_2, userName, remoteAddress), e); } } // check if the "enabled" flag is set for the user if (!newUser.isEnabled()) { // user is disabled, throw a securiy exception throw new CmsAuthentificationException( org.opencms.security.Messages.get().container( org.opencms.security.Messages.ERR_LOGIN_FAILED_DISABLED_2, userName, remoteAddress)); } if (mode == LoginUserMode.standard) { CmsTwoFactorAuthenticationHandler handler = OpenCms.getTwoFactorAuthenticationHandler(); if (handler.needsTwoFactorAuthentication(newUser)) { // note that password check must already have been successful at this stage if (handler.hasSecondFactor(newUser)) { if (!handler.verifySecondFactor(newUser, secondFactorInfo)) { if (dbc.currentUser().isGuestUser()) { // add an invalid login attempt for this user to the storage OpenCms.getLoginManager().addInvalidLogin(userName, remoteAddress); } OpenCms.getLoginManager().checkInvalidLogins(userName, remoteAddress); throw new CmsAuthentificationException( org.opencms.security.Messages.get().container( org.opencms.security.Messages.ERR_VERIFICATION_FAILED_1, userName)); } } else { try { if (handler.setUpAndVerifySecondFactor(newUser, secondFactorInfo)) { LOG.info("Second factor setup successful for user " + newUser.getName()); } else { if (dbc.currentUser().isGuestUser()) { // add an invalid login attempt for this user to the storage OpenCms.getLoginManager().addInvalidLogin(userName, remoteAddress); } OpenCms.getLoginManager().checkInvalidLogins(userName, remoteAddress); throw new CmsAuthentificationException( org.opencms.security.Messages.get().container( org.opencms.security.Messages.ERR_VERIFICATION_FAILED_1, userName)); } } catch (CmsSecondFactorSetupException e) { throw new CmsAuthentificationException( org.opencms.security.Messages.get().container( org.opencms.security.Messages.ERR_VERIFICATION_FAILED_1, userName), e); } } } } if (dbc.currentUser().isGuestUser()) { // check if this account is temporarily disabled because of too many invalid login attempts // this will throw an exception if the test fails OpenCms.getLoginManager().checkInvalidLogins(userName, remoteAddress); if (mode == LoginUserMode.standard) { // test successful, remove all previous invalid login attempts for this user from the storage OpenCms.getLoginManager().removeInvalidLogins(userName, remoteAddress); } } if (!m_securityManager.hasRole( dbc, newUser, CmsRole.ADMINISTRATOR.forOrgUnit(dbc.getRequestContext().getOuFqn()))) { // new user is not Administrator, check if login is currently allowed OpenCms.getLoginManager().checkLoginAllowed(); } if (mode == LoginUserMode.standard) { newUser.setLastlogin(System.currentTimeMillis()); m_monitor.clearUserCache(newUser); // write the changed user object back to the user driver Map additionalInfosForRepositories = OpenCms.getRepositoryManager().getAdditionalInfoForLogin( newUser.getName(), password); boolean requiresAddInfoUpdate = false; // check for changes for (Entry entry : additionalInfosForRepositories.entrySet()) { Object value = entry.getValue(); Object current = newUser.getAdditionalInfo(entry.getKey()); if (((value == null) && (current != null)) || ((value != null) && !value.equals(current))) { requiresAddInfoUpdate = true; break; } } if (requiresAddInfoUpdate) { newUser.getAdditionalInfo().putAll(additionalInfosForRepositories); } String lastPasswordChange = (String)newUser.getAdditionalInfo( CmsUserSettings.ADDITIONAL_INFO_LAST_PASSWORD_CHANGE); if (lastPasswordChange == null) { requiresAddInfoUpdate = true; newUser.getAdditionalInfo().put( CmsUserSettings.ADDITIONAL_INFO_LAST_PASSWORD_CHANGE, "" + System.currentTimeMillis()); } if (!requiresAddInfoUpdate) { dbc.setAttribute(ATTRIBUTE_LOGIN, newUser.getName()); } if (mode == LoginUserMode.standard) { OpenCms.getTwoFactorAuthenticationHandler().trackUserChange(dbc.getRequestContext(), userCopy, newUser); getUserDriver(dbc).writeUser(dbc, newUser); } int changes = CmsUser.FLAG_LAST_LOGIN; // check if we need to update the password if (!OpenCms.getPasswordHandler().checkPassword(password, newUser.getPassword(), false) && OpenCms.getPasswordHandler().checkPassword(password, newUser.getPassword(), true)) { // the password does not check with the current hash algorithm but with the fall back, update the password getUserDriver(dbc).writePassword(dbc, userName, password, password); changes = changes | CmsUser.FLAG_CORE_DATA; } // update cache m_monitor.cacheUser(newUser); // invalidate all user dependent caches m_monitor.flushCache( CmsMemoryMonitor.CacheType.ACL, CmsMemoryMonitor.CacheType.GROUP, CmsMemoryMonitor.CacheType.ORG_UNIT, CmsMemoryMonitor.CacheType.USER_LIST, CmsMemoryMonitor.CacheType.PERMISSION, CmsMemoryMonitor.CacheType.RESOURCE_LIST); // fire user modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_USER_ID, newUser.getId().toString()); eventData.put(I_CmsEventListener.KEY_USER_NAME, newUser.getName()); eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_WRITE_USER); eventData.put(I_CmsEventListener.KEY_USER_CHANGES, Integer.valueOf(changes)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); } // return the user object read from the driver return newUser.clone(); } /** * Lookup and read the user or group with the given UUID.

* * @param dbc the current database context * @param principalId the UUID of the principal to lookup * * @return the principal (group or user) if found, otherwise null */ public I_CmsPrincipal lookupPrincipal(CmsDbContext dbc, CmsUUID principalId) { try { CmsGroup group = getUserDriver(dbc).readGroup(dbc, principalId); if (group != null) { return group; } } catch (Exception e) { // ignore this exception } try { CmsUser user = readUser(dbc, principalId); if (user != null) { return user; } } catch (Exception e) { // ignore this exception } return null; } /** * Lookup and read the user or group with the given name.

* * @param dbc the current database context * @param principalName the name of the principal to lookup * * @return the principal (group or user) if found, otherwise null */ public I_CmsPrincipal lookupPrincipal(CmsDbContext dbc, String principalName) { try { CmsGroup group = getUserDriver(dbc).readGroup(dbc, principalName); if (group != null) { return group; } } catch (Exception e) { // ignore this exception } try { CmsUser user = readUser(dbc, principalName); if (user != null) { return user; } } catch (Exception e) { // ignore this exception } return null; } /** * Mark the given resource as visited by the user.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param resource the resource to mark as visited * @param user the user that visited the resource * * @throws CmsException if something goes wrong */ public void markResourceAsVisitedBy(CmsDbContext dbc, String poolName, CmsResource resource, CmsUser user) throws CmsException { getSubscriptionDriver().markResourceAsVisitedBy(dbc, poolName, resource, user); } /** * Moves a resource.

* * You must ensure that the parent of the destination path is an absolute, valid and * existing VFS path. Relative paths from the source are not supported.

* * The moved resource will always be locked to the current user * after the move operation.

* * In case the target resource already exists, it will be overwritten with the * source resource if possible.

* * @param dbc the current database context * @param source the resource to move * @param destination the name of the move destination with complete path * @param internal if set nothing more than the path is modified * * @throws CmsException if something goes wrong * * @see CmsSecurityManager#moveResource(CmsRequestContext, CmsResource, String) */ public void moveResource(CmsDbContext dbc, CmsResource source, String destination, boolean internal) throws CmsException { CmsFolder destinationFolder = readFolder(dbc, CmsResource.getParentFolder(destination), CmsResourceFilter.ALL); m_securityManager.checkPermissions( dbc, destinationFolder, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL); if (source.isFolder()) { m_monitor.flushCache(CmsMemoryMonitor.CacheType.HAS_ROLE, CmsMemoryMonitor.CacheType.ROLE_LIST); } getVfsDriver(dbc).moveResource(dbc, dbc.getRequestContext().getCurrentProject().getUuid(), source, destination); if (!internal) { CmsResourceState newState = CmsResource.STATE_CHANGED; if (source.getState().isNew()) { newState = CmsResource.STATE_NEW; } else if (source.getState().isDeleted()) { newState = CmsResource.STATE_DELETED; } source.setState(newState); // safe since this operation always uses the ids instead of the resource path getVfsDriver(dbc).writeResourceState( dbc, dbc.currentProject(), source, CmsDriverManager.UPDATE_STRUCTURE_STATE, false); // log it log( dbc, new CmsLogEntry( dbc, source.getStructureId(), CmsLogEntryType.RESOURCE_MOVED, new String[] {source.getRootPath(), destination}), false); } CmsResource destRes = readResource(dbc, destination, CmsResourceFilter.ALL); // move lock m_lockManager.moveResource(source.getRootPath(), destRes.getRootPath()); // flush all relevant caches m_monitor.clearAccessControlListCache(); m_monitor.flushCache( CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST, CmsMemoryMonitor.CacheType.PROJECT_RESOURCES); List resources = new ArrayList(4); // source resources.add(source); try { resources.add(readFolder(dbc, CmsResource.getParentFolder(source.getRootPath()), CmsResourceFilter.ALL)); } catch (Exception e) { if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } // destination resources.add(destRes); resources.add(destinationFolder); Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_RESOURCES, resources); eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); // fire the events OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MOVED, eventData)); } /** * Moves a resource to the "lost and found" folder.

* * The method can also be used to check get the name of a resource * in the "lost and found" folder only without actually moving the * the resource. To do this, the returnNameOnly flag * must be set to true.

* * @param dbc the current database context * @param resource the resource to apply this operation to * @param returnNameOnly if true, only the name of the resource in the "lost and found" * folder is returned, the move operation is not really performed * * @return the name of the resource inside the "lost and found" folder * * @throws CmsException if something goes wrong * @throws CmsIllegalArgumentException if the resourcename argument is null or of length 0 * * @see CmsObject#moveToLostAndFound(String) * @see CmsObject#getLostAndFoundName(String) */ public String moveToLostAndFound(CmsDbContext dbc, CmsResource resource, boolean returnNameOnly) throws CmsException, CmsIllegalArgumentException { String resourcename = dbc.removeSiteRoot(resource.getRootPath()); String siteRoot = dbc.getRequestContext().getSiteRoot(); dbc.getRequestContext().setSiteRoot(""); String destination = CmsDriverManager.LOST_AND_FOUND_FOLDER + resourcename; // create the required folders if necessary try { // collect all folders... String folderPath = CmsResource.getParentFolder(destination); folderPath = folderPath.substring(1, folderPath.length() - 1); // cut out leading and trailing '/' Iterator folders = CmsStringUtil.splitAsList(folderPath, '/').iterator(); // ...now create them.... folderPath = "/"; while (folders.hasNext()) { folderPath += folders.next().toString() + "/"; try { readFolder(dbc, folderPath, CmsResourceFilter.IGNORE_EXPIRATION); } catch (Exception e1) { if (returnNameOnly) { // we can use the original name without risk, and we do not need to recreate the parent folders break; } // the folder is not existing, so create it createResource( dbc, folderPath, CmsResourceTypeFolder.RESOURCE_TYPE_ID, null, new ArrayList()); } } // check if this resource name does already exist // if so add a postfix to the name String des = destination; int postfix = 1; boolean found = true; while (found) { try { // try to read the file..... found = true; readResource(dbc, des, CmsResourceFilter.ALL); // ....it's there, so add a postfix and try again String path = destination.substring(0, destination.lastIndexOf('/') + 1); String filename = destination.substring(destination.lastIndexOf('/') + 1, destination.length()); des = path; if (filename.lastIndexOf('.') > 0) { des += filename.substring(0, filename.lastIndexOf('.')); } else { des += filename; } des += "_" + postfix; if (filename.lastIndexOf('.') > 0) { des += filename.substring(filename.lastIndexOf('.'), filename.length()); } postfix++; } catch (CmsException e3) { // the file does not exist, so we can use this filename found = false; } } destination = des; if (!returnNameOnly) { // do not use the move semantic here! to prevent links pointing to the lost & found folder copyResource(dbc, resource, destination, CmsResource.COPY_AS_SIBLING); deleteResource(dbc, resource, CmsResource.DELETE_PRESERVE_SIBLINGS); } } catch (CmsException e2) { throw e2; } finally { // set the site root to the old value again dbc.getRequestContext().setSiteRoot(siteRoot); } return destination; } /** * Gets a new driver instance.

* * @param dbc the database context * @param configurationManager the configuration manager * @param driverName the driver name * @param successiveDrivers the list of successive drivers * * @return the driver object * @throws CmsInitException if the selected driver could not be initialized */ public Object newDriverInstance( CmsDbContext dbc, CmsConfigurationManager configurationManager, String driverName, List successiveDrivers) throws CmsInitException { Class driverClass = null; I_CmsDriver driver = null; try { // try to get the class driverClass = Class.forName(driverName); if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_START_1, driverName)); } // try to create a instance driver = (I_CmsDriver)driverClass.newInstance(); if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_INITIALIZING_1, driverName)); } // invoke the init-method of this access class driver.init(dbc, configurationManager, successiveDrivers, this); if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_INIT_FINISHED_0)); } } catch (Throwable t) { CmsMessageContainer message = Messages.get().container( Messages.ERR_ERROR_INITIALIZING_DRIVER_1, driverName); if (LOG.isErrorEnabled()) { LOG.error(message.key(), t); } throw new CmsInitException(message, t); } return driver; } /** * Method to create a new instance of a driver.

* * @param configuration the configurations from the propertyfile * @param driverName the class name of the driver * @param driverPoolUrl the pool url for the driver * @return an initialized instance of the driver * @throws CmsException if something goes wrong */ public Object newDriverInstance(CmsParameterConfiguration configuration, String driverName, String driverPoolUrl) throws CmsException { Class[] initParamClasses = {CmsParameterConfiguration.class, String.class, CmsDriverManager.class}; Object[] initParams = {configuration, driverPoolUrl, this}; Class driverClass = null; Object driver = null; try { // try to get the class driverClass = Class.forName(driverName); if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_START_1, driverName)); } // try to create a instance driver = driverClass.newInstance(); if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_INITIALIZING_1, driverName)); } // invoke the init-method of this access class driver.getClass().getMethod("init", initParamClasses).invoke(driver, initParams); if (CmsLog.INIT.isInfoEnabled()) { CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_INIT_FINISHED_1, driverPoolUrl)); } } catch (Exception exc) { CmsMessageContainer message = Messages.get().container(Messages.ERR_INIT_DRIVER_MANAGER_1); if (LOG.isFatalEnabled()) { LOG.fatal(message.key(), exc); } throw new CmsDbException(message, exc); } return driver; } /** * Method to create a new instance of a pool.

* * @param configuration the configurations from the propertyfile * @param poolName the configuration name of the pool * * @throws CmsInitException if the pools could not be initialized */ public void newPoolInstance(CmsParameterConfiguration configuration, String poolName) throws CmsInitException { CmsDbPoolV11 pool; try { pool = new CmsDbPoolV11(configuration, poolName); } catch (Exception e) { CmsMessageContainer message = Messages.get().container(Messages.ERR_INIT_CONN_POOL_1, poolName); if (LOG.isErrorEnabled()) { LOG.error(message.key(), e); } throw new CmsInitException(message, e); } addPool(pool); } /** * Publishes the given publish job.

* * @param cms the cms context * @param dbc the db context * @param publishList the list of resources to publish * @param report the report to write to * * @throws CmsException if something goes wrong */ public void publishJob(CmsObject cms, CmsDbContext dbc, CmsPublishList publishList, I_CmsReport report) throws CmsException { try { // check state and lock List allResources = new ArrayList(publishList.getFolderList()); allResources.addAll(publishList.getDeletedFolderList()); allResources.addAll(publishList.getFileList()); Iterator itResources = allResources.iterator(); while (itResources.hasNext()) { CmsResource resource = itResources.next(); try { resource = readResource(dbc, resource.getStructureId(), CmsResourceFilter.ALL); } catch (CmsVfsResourceNotFoundException e) { continue; } if (resource.getState().isUnchanged()) { // remove files that were published by a concurrent job if (LOG.isDebugEnabled()) { LOG.debug( Messages.get().getBundle().key( Messages.RPT_PUBLISH_REMOVED_RESOURCE_1, dbc.removeSiteRoot(resource.getRootPath()))); } publishList.remove(resource); unlockResource(dbc, resource, true, true); continue; } CmsLock lock = m_lockManager.getLock(dbc, resource, false); if (!lock.getSystemLock().isPublish()) { // remove files that are not locked for publishing if (LOG.isDebugEnabled()) { LOG.debug( Messages.get().getBundle().key( Messages.RPT_PUBLISH_REMOVED_RESOURCE_1, dbc.removeSiteRoot(resource.getRootPath()))); } publishList.remove(resource); continue; } } CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); // clear the cache m_monitor.clearCacheForPublishing(); int publishTag = getNextPublishTag(dbc); getProjectDriver(dbc).publishProject(dbc, report, onlineProject, publishList, publishTag); // iterate the initialized module action instances Iterator i = OpenCms.getModuleManager().getModuleNames().iterator(); while (i.hasNext()) { CmsModule module = OpenCms.getModuleManager().getModule(i.next()); if ((module != null) && (module.getActionInstance() != null)) { module.getActionInstance().publishProject(cms, publishList, publishTag, report); } } boolean temporaryProject = (cms.getRequestContext().getCurrentProject().getType() == CmsProject.PROJECT_TYPE_TEMPORARY); // the project was stored in the history tables for history // it will be deleted if the project_flag is PROJECT_TYPE_TEMPORARY if ((temporaryProject) && (!publishList.isDirectPublish())) { try { getProjectDriver(dbc).deleteProject(dbc, dbc.currentProject()); } catch (CmsException e) { LOG.error( Messages.get().getBundle().key( Messages.LOG_DELETE_TEMP_PROJECT_FAILED_1, cms.getRequestContext().getCurrentProject().getName())); } // if project was temporary set context to online project cms.getRequestContext().setCurrentProject(onlineProject); } } finally { // clear the cache again m_monitor.clearCacheForPublishing(); } } /** * Publishes the resources of a specified publish list.

* * @param cms the current request context * @param dbc the current database context * @param publishList a publish list * @param report an instance of {@link I_CmsReport} to print messages * * @throws CmsException if something goes wrong * * @see #fillPublishList(CmsDbContext, CmsPublishList) */ public synchronized void publishProject( CmsObject cms, CmsDbContext dbc, CmsPublishList publishList, I_CmsReport report) throws CmsException { // check the parent folders checkParentFolders(dbc, publishList); ensureSubResourcesOfMovedFoldersPublished(cms, dbc, publishList); OpenCms.getPublishManager().getPublishListVerifier().checkPublishList(publishList); try { // fire an event that a project is to be published Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_REPORT, report); eventData.put(I_CmsEventListener.KEY_PUBLISHLIST, publishList); eventData.put(I_CmsEventListener.KEY_PROJECTID, dbc.currentProject().getUuid()); eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); CmsEvent beforePublishEvent = new CmsEvent(I_CmsEventListener.EVENT_BEFORE_PUBLISH_PROJECT, eventData); OpenCms.fireCmsEvent(beforePublishEvent); } catch (Throwable t) { if (report != null) { report.addError(t); report.println(t); } if (LOG.isErrorEnabled()) { LOG.error(t.getLocalizedMessage(), t); } } // lock all resources with the special publish lock Iterator itResources = new ArrayList(publishList.getAllResources()).iterator(); while (itResources.hasNext()) { CmsResource resource = itResources.next(); CmsLock lock = m_lockManager.getLock(dbc, resource, false); if (lock.getSystemLock().isUnlocked() && lock.isLockableBy(dbc.currentUser())) { if (getLock(dbc, resource).getEditionLock().isNullLock()) { lockResource(dbc, resource, CmsLockType.PUBLISH); } else { changeLock(dbc, resource, CmsLockType.PUBLISH); } } else if (lock.getSystemLock().isPublish()) { if (LOG.isWarnEnabled()) { LOG.warn( Messages.get().getBundle().key( Messages.RPT_PUBLISH_REMOVED_RESOURCE_1, dbc.removeSiteRoot(resource.getRootPath()))); } // remove files that are already waiting to be published publishList.remove(resource); continue; } else { // this is needed to fix TestPublishIsssues#testPublishScenarioE changeLock(dbc, resource, CmsLockType.PUBLISH); } // now re-check the lock state lock = m_lockManager.getLock(dbc, resource, false); if (!lock.getSystemLock().isPublish()) { if (report != null) { report.println( Messages.get().container( Messages.RPT_PUBLISH_REMOVED_RESOURCE_1, dbc.removeSiteRoot(resource.getRootPath())), I_CmsReport.FORMAT_WARNING); } if (LOG.isWarnEnabled()) { LOG.warn( Messages.get().getBundle().key( Messages.RPT_PUBLISH_REMOVED_RESOURCE_1, dbc.removeSiteRoot(resource.getRootPath()))); } // remove files that could not be locked publishList.remove(resource); } } // enqueue the publish job CmsException enqueueException = null; try { m_publishEngine.enqueuePublishJob(cms, publishList, report); } catch (CmsException exc) { enqueueException = exc; } // if an exception was raised, remove the publish locks // and throw the exception again if (enqueueException != null) { itResources = publishList.getAllResources().iterator(); while (itResources.hasNext()) { CmsResource resource = itResources.next(); CmsLock lock = m_lockManager.getLock(dbc, resource, false); if (lock.getSystemLock().isPublish() && lock.getSystemLock().isOwnedInProjectBy( cms.getRequestContext().getCurrentUser(), cms.getRequestContext().getCurrentProject())) { unlockResource(dbc, resource, true, true); } } throw enqueueException; } } /** * Transfers the new URL name mappings (if any) for a given resource to the online project.

* * @param dbc the current database context * @param res the resource whose new URL name mappings should be transferred to the online project * * @throws CmsDataAccessException if something goes wrong */ public void publishUrlNameMapping(CmsDbContext dbc, CmsResource res) throws CmsDataAccessException { I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); if (res.getState().isDeleted()) { // remove both offline and online mappings CmsUrlNameMappingFilter idFilter = CmsUrlNameMappingFilter.ALL.filterStructureId(res.getStructureId()); vfsDriver.deleteUrlNameMappingEntries(dbc, true, idFilter); vfsDriver.deleteUrlNameMappingEntries(dbc, false, idFilter); } else { // copy the new entries to the online table List entries = vfsDriver.readUrlNameMappingEntries( dbc, false, CmsUrlNameMappingFilter.ALL.filterStructureId(res.getStructureId()).filterStates( CmsUrlNameMappingEntry.MAPPING_STATUS_NEW, CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH)); boolean isReplaceOnPublish = false; for (CmsUrlNameMappingEntry entry : entries) { isReplaceOnPublish |= entry.getState() == CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH; } if (!entries.isEmpty()) { long now = System.currentTimeMillis(); if (isReplaceOnPublish) { vfsDriver.deleteUrlNameMappingEntries( dbc, true, CmsUrlNameMappingFilter.ALL.filterStructureId(res.getStructureId())); vfsDriver.deleteUrlNameMappingEntries( dbc, false, CmsUrlNameMappingFilter.ALL.filterStructureId(res.getStructureId())); } for (CmsUrlNameMappingEntry entry : entries) { CmsUrlNameMappingFilter nameFilter = CmsUrlNameMappingFilter.ALL.filterName(entry.getName()); if (!isReplaceOnPublish) { // we already handled the other case above vfsDriver.deleteUrlNameMappingEntries(dbc, true, nameFilter); vfsDriver.deleteUrlNameMappingEntries(dbc, false, nameFilter); } } for (CmsUrlNameMappingEntry entry : entries) { CmsUrlNameMappingEntry newEntry = new CmsUrlNameMappingEntry( entry.getName(), entry.getStructureId(), entry.getState() == CmsUrlNameMappingEntry.MAPPING_STATUS_NEW ? CmsUrlNameMappingEntry.MAPPING_STATUS_PUBLISHED : CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH_PUBLISHED, now, entry.getLocale()); vfsDriver.addUrlNameMappingEntry(dbc, true, newEntry); vfsDriver.addUrlNameMappingEntry(dbc, false, newEntry); } } } } /** * Reads an access control entry from the cms.

* * The access control entries of a resource are readable by everyone. * * @param dbc the current database context * @param resource the resource * @param principal the id of a group or a user any other entity * @return an access control entry that defines the permissions of the entity for the given resource * @throws CmsException if something goes wrong */ public CmsAccessControlEntry readAccessControlEntry(CmsDbContext dbc, CmsResource resource, CmsUUID principal) throws CmsException { return getUserDriver( dbc).readAccessControlEntry(dbc, dbc.currentProject(), resource.getResourceId(), principal); } /** * Finds the alias with a given path.

* * If no alias is found, null is returned.

* * @param dbc the current database context * @param project the current project * @param siteRoot the site root * @param path the path of the alias * * @return the alias with the given path * * @throws CmsException if something goes wrong */ public CmsAlias readAliasByPath(CmsDbContext dbc, CmsProject project, String siteRoot, String path) throws CmsException { List aliases = getVfsDriver(dbc).readAliases(dbc, project, new CmsAliasFilter(siteRoot, path, null)); if (aliases.isEmpty()) { return null; } else { return aliases.get(0); } } /** * Reads the aliases for a given site root.

* * @param dbc the current database context * @param currentProject the current project * @param siteRoot the site root * * @return the list of aliases for the given site root * * @throws CmsException if something goes wrong */ public List readAliasesBySite(CmsDbContext dbc, CmsProject currentProject, String siteRoot) throws CmsException { return getVfsDriver(dbc).readAliases(dbc, currentProject, new CmsAliasFilter(siteRoot, null, null)); } /** * Reads the aliases which point to a given structure id.

* * @param dbc the current database context * @param project the current project * @param structureId the structure id for which we want to read the aliases * * @return the list of aliases pointing to the structure id * @throws CmsException if something goes wrong */ public List readAliasesByStructureId(CmsDbContext dbc, CmsProject project, CmsUUID structureId) throws CmsException { return getVfsDriver(dbc).readAliases(dbc, project, new CmsAliasFilter(null, null, structureId)); } /** * Reads all versions of the given resource.
* * This method returns a list with the history of the given resource, i.e. * the historical resource entries, independent of the project they were attached to.
* * The reading excludes the file content.

* * @param dbc the current database context * @param resource the resource to read the history for * * @return a list of file headers, as {@link I_CmsHistoryResource} objects * * @throws CmsException if something goes wrong */ public List readAllAvailableVersions(CmsDbContext dbc, CmsResource resource) throws CmsException { // read the historical resources List versions = getHistoryDriver(dbc).readAllAvailableVersions( dbc, resource.getStructureId()); if ((versions.size() > OpenCms.getSystemInfo().getHistoryVersions()) && (OpenCms.getSystemInfo().getHistoryVersions() > -1)) { return versions.subList(0, OpenCms.getSystemInfo().getHistoryVersions()); } return versions; } /** * Reads all property definitions for the given mapping type.

* * @param dbc the current database context * * @return a list with the {@link CmsPropertyDefinition} objects (may be empty) * * @throws CmsException if something goes wrong */ public List readAllPropertyDefinitions(CmsDbContext dbc) throws CmsException { List result = getVfsDriver(dbc).readPropertyDefinitions( dbc, dbc.currentProject().getUuid()); Collections.sort(result); return result; } /** * Returns all resources subscribed by the given user or group.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param principal the principal to read the subscribed resources * * @return all resources subscribed by the given user or group * * @throws CmsException if something goes wrong */ public List readAllSubscribedResources(CmsDbContext dbc, String poolName, CmsPrincipal principal) throws CmsException { List result = getSubscriptionDriver().readAllSubscribedResources(dbc, poolName, principal); result = filterPermissions(dbc, result, CmsResourceFilter.DEFAULT); return result; } /** * Selects the best url name for a given resource and locale.

* * @param dbc the database context * @param id the resource's structure id * @param locale the requested locale * @param defaultLocales the default locales to use if the locale isn't available * * @return the URL name which was found * * @throws CmsDataAccessException if the database operation failed */ public String readBestUrlName(CmsDbContext dbc, CmsUUID id, Locale locale, List defaultLocales) throws CmsDataAccessException { List entries = getVfsDriver(dbc).readUrlNameMappingEntries( dbc, dbc.currentProject().isOnlineProject(), CmsUrlNameMappingFilter.ALL.filterStructureId(id)); if (entries.isEmpty()) { return null; } ArrayListMultimap entriesByLocale = ArrayListMultimap.create(); for (CmsUrlNameMappingEntry entry : entries) { entriesByLocale.put(entry.getLocale(), entry); } List lastEntries = new ArrayList(); Comparator dateChangedComparator = new UrlNameMappingComparator(); for (String localeKey : entriesByLocale.keySet()) { // for each locale select the latest mapping entry CmsUrlNameMappingEntry latestEntryForLocale = Collections.max( entriesByLocale.get(localeKey), dateChangedComparator); lastEntries.add(latestEntryForLocale); } CmsLocaleManager localeManager = OpenCms.getLocaleManager(); List availableLocales = new ArrayList(); for (CmsUrlNameMappingEntry entry : lastEntries) { availableLocales.add(CmsLocaleManager.getLocale(entry.getLocale())); } Locale bestLocale = localeManager.getBestMatchingLocale(locale, defaultLocales, availableLocales); String bestLocaleStr = bestLocale.toString(); for (CmsUrlNameMappingEntry entry : lastEntries) { if (entry.getLocale().equals(bestLocaleStr)) { return entry.getName(); } } return null; } /** * Returns the child resources of a resource, that is the resources * contained in a folder.

* * With the parameters getFolders and getFiles * you can control what type of resources you want in the result list: * files, folders, or both.

* * This method is mainly used by the workplace explorer.

* * @param dbc the current database context * @param resource the resource to return the child resources for * @param filter the resource filter to use * @param getFolders if true the child folders are included in the result * @param getFiles if true the child files are included in the result * @param checkPermissions if the resources should be filtered with the current user permissions * * @return a list of all child resources * * @throws CmsException if something goes wrong */ public List readChildResources( CmsDbContext dbc, CmsResource resource, CmsResourceFilter filter, boolean getFolders, boolean getFiles, boolean checkPermissions) throws CmsException { String cacheKey = null; List resourceList = null; if (m_monitor.isEnabled(CmsMemoryMonitor.CacheType.RESOURCE_LIST)) { // check this here to skip the complex cache key generation String time = ""; if (checkPermissions) { // ensure correct caching if site time offset is set if ((dbc.getRequestContext() != null) && (OpenCms.getSiteManager().getSiteForSiteRoot(dbc.getRequestContext().getSiteRoot()) != null)) { time += OpenCms.getSiteManager().getSiteForSiteRoot( dbc.getRequestContext().getSiteRoot()).getSiteMatcher().getTimeOffset(); } } // try to get the sub resources from the cache cacheKey = getCacheKey( new String[] { dbc.currentUser().getName(), getFolders ? (getFiles ? CmsCacheKey.CACHE_KEY_SUBALL : CmsCacheKey.CACHE_KEY_SUBFOLDERS) : CmsCacheKey.CACHE_KEY_SUBFILES, checkPermissions ? "+" + time : "-", filter.getCacheId(), resource.getRootPath()}, dbc); resourceList = m_monitor.getCachedResourceList(cacheKey); } if ((resourceList == null) || !dbc.getProjectId().isNullUUID()) { // read the result form the database resourceList = getVfsDriver( dbc).readChildResources(dbc, dbc.currentProject(), resource, getFolders, getFiles); if (checkPermissions) { // apply the permission filter resourceList = filterPermissions(dbc, resourceList, filter); } // cache the sub resources if (dbc.getProjectId().isNullUUID()) { m_monitor.cacheResourceList(cacheKey, resourceList); } } // we must always apply the result filter and update the context dates return updateContextDates(dbc, resourceList, filter); } /** * Returns the default file for the given folder.

* * If the given resource is a file, then this file is returned.

* * Otherwise, in case of a folder:
*

    *
  1. the {@link CmsPropertyDefinition#PROPERTY_DEFAULT_FILE} is checked, and *
  2. if still no file could be found, the configured default files in the * opencms-vfs.xml configuration are iterated until a match is * found, and *
  3. if still no file could be found, null is retuned *
* * @param dbc the database context * @param resource the folder to get the default file for * @param resourceFilter the resource filter * * @return the default file for the given folder */ public CmsResource readDefaultFile(CmsDbContext dbc, CmsResource resource, CmsResourceFilter resourceFilter) { // resource exists, lets check if we have a file or a folder if (resource.isFolder()) { // the resource is a folder, check if PROPERTY_DEFAULT_FILE is set on folder try { String defaultFileName = readPropertyObject( dbc, resource, CmsPropertyDefinition.PROPERTY_DEFAULT_FILE, false).getValue(); // check if the default file property does not match the navigation level folder marker value if ((defaultFileName != null) && !CmsJspNavBuilder.NAVIGATION_LEVEL_FOLDER.equals(defaultFileName)) { // property was set, so look up this file first String folderName = CmsResource.getFolderPath(resource.getRootPath()); resource = readResource(dbc, folderName + defaultFileName, resourceFilter.addRequireFile()); } } catch (CmsException e) { // ignore all other exceptions and continue the lookup process if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } if (resource.isFolder()) { String folderName = CmsResource.getFolderPath(resource.getRootPath()); // resource is (still) a folder, check default files specified in configuration Iterator it = OpenCms.getDefaultFiles().iterator(); while (it.hasNext()) { String tmpResourceName = folderName + it.next(); try { resource = readResource(dbc, tmpResourceName, resourceFilter.addRequireFile()); // no exception? So we have found the default file // stop looking for default files break; } catch (CmsException e) { // ignore all other exceptions and continue the lookup process if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } } } } if (resource.isFolder()) { // we only want files as a result for further processing resource = null; } return resource; } /** * Reads all deleted (historical) resources below the given path, * including the full tree below the path, if required.

* * @param dbc the current db context * @param resource the parent resource to read the resources from * @param readTree true to read all subresources * @param isVfsManager true if the current user has the vfs manager role * * @return a list of {@link I_CmsHistoryResource} objects * * @throws CmsException if something goes wrong * * @see CmsObject#readResource(CmsUUID, int) * @see CmsObject#readResources(String, CmsResourceFilter, boolean) * @see CmsObject#readDeletedResources(String, boolean) */ public List readDeletedResources( CmsDbContext dbc, CmsResource resource, boolean readTree, boolean isVfsManager) throws CmsException { Set result = new HashSet(); List deletedResources; dbc.getRequestContext().setAttribute("ATTR_RESOURCE_NAME", resource.getRootPath()); try { deletedResources = getHistoryDriver(dbc).readDeletedResources( dbc, resource.getStructureId(), isVfsManager ? null : dbc.currentUser().getId()); } finally { dbc.getRequestContext().removeAttribute("ATTR_RESOURCE_NAME"); } result.addAll(deletedResources); Set newResult = new HashSet(result.size()); I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); Iterator it = result.iterator(); while (it.hasNext()) { I_CmsHistoryResource histRes = it.next(); // adjust the paths try { if (vfsDriver.validateStructureIdExists( dbc, dbc.currentProject().getUuid(), histRes.getStructureId())) { newResult.add(histRes); continue; } // adjust the path in case of deleted files String resourcePath = histRes.getRootPath(); String resName = CmsResource.getName(resourcePath); String path = CmsResource.getParentFolder(resourcePath); CmsUUID parentId = histRes.getParentId(); try { // first look for the path through the parent id path = readResource(dbc, parentId, CmsResourceFilter.IGNORE_EXPIRATION).getRootPath(); } catch (CmsDataAccessException e) { // if the resource with the parent id is not found, try to get a new parent id with the path try { parentId = readResource(dbc, path, CmsResourceFilter.IGNORE_EXPIRATION).getStructureId(); } catch (CmsDataAccessException e1) { // ignore, the parent folder has been completely deleted } } resourcePath = path + resName; boolean isFolder = resourcePath.endsWith("/"); if (isFolder) { newResult.add( new CmsHistoryFolder( histRes.getPublishTag(), histRes.getStructureId(), histRes.getResourceId(), resourcePath, histRes.getTypeId(), histRes.getFlags(), histRes.getProjectLastModified(), histRes.getState(), histRes.getDateCreated(), histRes.getUserCreated(), histRes.getDateLastModified(), histRes.getUserLastModified(), histRes.getDateReleased(), histRes.getDateExpired(), histRes.getVersion(), parentId, histRes.getResourceVersion(), histRes.getStructureVersion())); } else { newResult.add( new CmsHistoryFile( histRes.getPublishTag(), histRes.getStructureId(), histRes.getResourceId(), resourcePath, histRes.getTypeId(), histRes.getFlags(), histRes.getProjectLastModified(), histRes.getState(), histRes.getDateCreated(), histRes.getUserCreated(), histRes.getDateLastModified(), histRes.getUserLastModified(), histRes.getDateReleased(), histRes.getDateExpired(), histRes.getLength(), histRes.getDateContent(), histRes.getVersion(), parentId, null, histRes.getResourceVersion(), histRes.getStructureVersion())); } } catch (CmsDataAccessException e) { // should never happen if (LOG.isErrorEnabled()) { LOG.error(e.getLocalizedMessage(), e); } } } if (readTree) { Iterator itDeleted = deletedResources.iterator(); while (itDeleted.hasNext()) { I_CmsHistoryResource delResource = itDeleted.next(); if (delResource.isFolder()) { newResult.addAll(readDeletedResources(dbc, (CmsFolder)delResource, readTree, isVfsManager)); } } try { readResource(dbc, resource.getStructureId(), CmsResourceFilter.ALL); // resource exists, so recurse Iterator itResources = readResources( dbc, resource, CmsResourceFilter.ALL.addRequireFolder(), readTree).iterator(); while (itResources.hasNext()) { CmsResource subResource = itResources.next(); if (subResource.isFolder()) { newResult.addAll(readDeletedResources(dbc, subResource, readTree, isVfsManager)); } } } catch (Exception e) { // resource does not exists if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } } List finalRes = new ArrayList(newResult); Collections.sort(finalRes, I_CmsResource.COMPARE_ROOT_PATH); return finalRes; } /** * Reads a file resource (including it's binary content) from the VFS, * using the specified resource filter.

* * In case you do not need the file content, * use {@link #readResource(CmsDbContext, String, CmsResourceFilter)} instead.

* * The specified filter controls what kind of resources should be "found" * during the read operation. This will depend on the application. For example, * using {@link CmsResourceFilter#DEFAULT} will only return currently * "valid" resources, while using {@link CmsResourceFilter#IGNORE_EXPIRATION} * will ignore the date release / date expired information of the resource.

* * @param dbc the current database context * @param resource the base file resource (without content) * @return the file read from the VFS * @throws CmsException if operation was not successful */ public CmsFile readFile(CmsDbContext dbc, CmsResource resource) throws CmsException { if (resource.isFolder()) { throw new CmsVfsResourceNotFoundException( Messages.get().container( Messages.ERR_ACCESS_FOLDER_AS_FILE_1, dbc.removeSiteRoot(resource.getRootPath()))); } CmsUUID projectId = dbc.currentProject().getUuid(); CmsFile file = null; if (resource instanceof I_CmsHistoryResource) { file = new CmsHistoryFile((I_CmsHistoryResource)resource); file.setContents( getHistoryDriver(dbc).readContent( dbc, resource.getResourceId(), ((I_CmsHistoryResource)resource).getPublishTag())); } else { file = new CmsFile(resource); file.setContents(getVfsDriver(dbc).readContent(dbc, projectId, resource.getResourceId())); } return file; } /** * Reads a folder from the VFS, * using the specified resource filter.

* * @param dbc the current database context * @param resourcename the name of the folder to read (full path) * @param filter the resource filter to use while reading * * @return the folder that was read * * @throws CmsDataAccessException if something goes wrong * * @see #readResource(CmsDbContext, String, CmsResourceFilter) * @see CmsObject#readFolder(String) * @see CmsObject#readFolder(String, CmsResourceFilter) */ public CmsFolder readFolder(CmsDbContext dbc, String resourcename, CmsResourceFilter filter) throws CmsDataAccessException { CmsResource resource = readResource(dbc, resourcename, filter); return convertResourceToFolder(resource); } /** * Reads the group of a project.

* * @param dbc the current database context * @param project the project to read from * * @return the group of a resource */ public CmsGroup readGroup(CmsDbContext dbc, CmsProject project) { try { return readGroup(dbc, project.getGroupId()); } catch (CmsException exc) { return new CmsGroup( CmsUUID.getNullUUID(), CmsUUID.getNullUUID(), project.getGroupId() + "", "deleted group", 0); } } /** * Reads a group based on its id.

* * @param dbc the current database context * @param groupId the id of the group that is to be read * * @return the requested group * * @throws CmsException if operation was not successful */ public CmsGroup readGroup(CmsDbContext dbc, CmsUUID groupId) throws CmsException { CmsGroup group = null; // try to read group from cache group = m_monitor.getCachedGroup(groupId.toString()); if (group == null) { group = getUserDriver(dbc).readGroup(dbc, groupId); m_monitor.cacheGroup(group); } return group; } /** * Reads a group based on its name.

* * @param dbc the current database context * @param groupname the name of the group that is to be read * * @return the requested group * * @throws CmsDataAccessException if operation was not successful */ public CmsGroup readGroup(CmsDbContext dbc, String groupname) throws CmsDataAccessException { CmsGroup group = null; // try to read group from cache group = m_monitor.getCachedGroup(groupname); if (group == null) { group = getUserDriver(dbc).readGroup(dbc, groupname); m_monitor.cacheGroup(group); } return group; } /** * Reads a principal (an user or group) from the historical archive based on its ID.

* * @param dbc the current database context * @param principalId the id of the principal to read * * @return the historical principal entry with the given id * * @throws CmsException if something goes wrong, ie. {@link CmsDbEntryNotFoundException} * * @see CmsObject#readUser(CmsUUID) * @see CmsObject#readGroup(CmsUUID) * @see CmsObject#readHistoryPrincipal(CmsUUID) */ public CmsHistoryPrincipal readHistoricalPrincipal(CmsDbContext dbc, CmsUUID principalId) throws CmsException { return getHistoryDriver(dbc).readPrincipal(dbc, principalId); } /** * Returns the latest historical project entry with the given id.

* * @param dbc the current database context * @param projectId the project id * * @return the requested historical project entry * * @throws CmsException if something goes wrong */ public CmsHistoryProject readHistoryProject(CmsDbContext dbc, CmsUUID projectId) throws CmsException { return getHistoryDriver(dbc).readProject(dbc, projectId); } /** * Returns a historical project entry.

* * @param dbc the current database context * @param publishTag the publish tag of the project * * @return the requested historical project entry * * @throws CmsException if something goes wrong */ public CmsHistoryProject readHistoryProject(CmsDbContext dbc, int publishTag) throws CmsException { return getHistoryDriver(dbc).readProject(dbc, publishTag); } /** * Reads the list of all {@link CmsProperty} objects that belongs to the given historical resource.

* * @param dbc the current database context * @param historyResource the historical resource to read the properties for * * @return the list of {@link CmsProperty} objects * * @throws CmsException if something goes wrong */ public List readHistoryPropertyObjects(CmsDbContext dbc, I_CmsHistoryResource historyResource) throws CmsException { return getHistoryDriver(dbc).readProperties(dbc, historyResource); } /** * Reads the structure id which is mapped to a given URL name.

* * @param dbc the current database context * @param name the name for which the mapped structure id should be looked up * * @return the structure id which is mapped to the given name, or null if there is no such id * * @throws CmsDataAccessException if something goes wrong */ public CmsUUID readIdForUrlName(CmsDbContext dbc, String name) throws CmsDataAccessException { List entries = getVfsDriver(dbc).readUrlNameMappingEntries( dbc, dbc.currentProject().isOnlineProject(), CmsUrlNameMappingFilter.ALL.filterName(name)); if (entries.isEmpty()) { return null; } return entries.get(0).getStructureId(); } /** * Reads the locks that were saved to the database in the previous run of OpenCms.

* * @param dbc the current database context * * @throws CmsException if something goes wrong */ public void readLocks(CmsDbContext dbc) throws CmsException { m_lockManager.readLocks(dbc); } /** * Reads the manager group of a project.

* * @param dbc the current database context * @param project the project to read from * * @return the group of a resource */ public CmsGroup readManagerGroup(CmsDbContext dbc, CmsProject project) { try { return readGroup(dbc, project.getManagerGroupId()); } catch (CmsException exc) { // the group does not exist any more - return a dummy-group return new CmsGroup( CmsUUID.getNullUUID(), CmsUUID.getNullUUID(), project.getManagerGroupId() + "", "deleted group", 0); } } /** * Reads the URL name which has been most recently mapped to the given structure id, or null * if no URL name is mapped to the id.

* * @param dbc the current database context * @param id a structure id * @return the name which has been most recently mapped to the given structure id * * @throws CmsDataAccessException if something goes wrong */ public String readNewestUrlNameForId(CmsDbContext dbc, CmsUUID id) throws CmsDataAccessException { List entries = getVfsDriver(dbc).readUrlNameMappingEntries( dbc, dbc.currentProject().isOnlineProject(), CmsUrlNameMappingFilter.ALL.filterStructureId(id)); if (entries.isEmpty()) { return null; } Collections.sort(entries, new UrlNameMappingComparator()); CmsUrlNameMappingEntry lastEntry = entries.get(entries.size() - 1); return lastEntry.getName(); } /** * Reads an organizational Unit based on its fully qualified name.

* * @param dbc the current db context * @param ouFqn the fully qualified name of the organizational Unit to be read * * @return the organizational Unit that with the provided fully qualified name * * @throws CmsException if something goes wrong */ public CmsOrganizationalUnit readOrganizationalUnit(CmsDbContext dbc, String ouFqn) throws CmsException { CmsOrganizationalUnit organizationalUnit = null; // try to read organizational unit from cache organizationalUnit = m_monitor.getCachedOrgUnit(ouFqn); if (organizationalUnit == null) { organizationalUnit = getUserDriver(dbc).readOrganizationalUnit(dbc, ouFqn); m_monitor.cacheOrgUnit(organizationalUnit); } return organizationalUnit; } /** * Reads the owner of a project.

* * @param dbc the current database context * @param project the project to get the owner from * * @return the owner of a resource * @throws CmsException if something goes wrong */ public CmsUser readOwner(CmsDbContext dbc, CmsProject project) throws CmsException { return readUser(dbc, project.getOwnerId()); } /** * Reads the parent folder to a given structure id.

* * @param dbc the current database context * @param structureId the structure id of the child * * @return the parent folder resource * * @throws CmsDataAccessException if something goes wrong */ public CmsResource readParentFolder(CmsDbContext dbc, CmsUUID structureId) throws CmsDataAccessException { return getVfsDriver(dbc).readParentFolder(dbc, dbc.currentProject().getUuid(), structureId); } /** * Builds a list of resources for a given path.

* * @param dbc the current database context * @param path the requested path * @param filter a filter object (only "includeDeleted" information is used!) * * @return list of {@link CmsResource}s * * @throws CmsException if something goes wrong */ public List readPath(CmsDbContext dbc, String path, CmsResourceFilter filter) throws CmsException { // splits the path into folder and filename tokens List tokens = CmsStringUtil.splitAsList(path, '/'); // the root folder is no token in the path but a resource which has to be added to the path int count = tokens.size() + 1; // holds the CmsResource instances in the path List pathList = new ArrayList(count); // true if the path doesn't end with a folder boolean lastResourceIsFile = false; // number of folders in the path int folderCount = count; if (!path.endsWith("/")) { folderCount--; lastResourceIsFile = true; } // read the root folder, because it's ID is required to read any sub-resources String currentResourceName = "/"; StringBuffer currentPath = new StringBuffer(64); currentPath.append('/'); String cp = currentPath.toString(); CmsUUID projectId = getProjectIdForContext(dbc); // key to cache the resources String cacheKey = getCacheKey(null, false, projectId, cp); // the current resource CmsResource currentResource = m_monitor.getCachedResource(cacheKey); if ((currentResource == null) || !dbc.getProjectId().isNullUUID()) { currentResource = getVfsDriver(dbc).readFolder(dbc, projectId, cp); if (dbc.getProjectId().isNullUUID()) { m_monitor.cacheResource(cacheKey, currentResource); } } pathList.add(0, currentResource); if (count == 1) { // the root folder was requested- no further operations required return pathList; } Iterator it = tokens.iterator(); currentResourceName = it.next(); // read the folder resources in the path /a/b/c/ int i = 0; for (i = 1; i < folderCount; i++) { currentPath.append(currentResourceName); currentPath.append('/'); // read the folder cp = currentPath.toString(); cacheKey = getCacheKey(null, false, projectId, cp); currentResource = m_monitor.getCachedResource(cacheKey); if ((currentResource == null) || !dbc.getProjectId().isNullUUID()) { currentResource = getVfsDriver(dbc).readFolder(dbc, projectId, cp); if (dbc.getProjectId().isNullUUID()) { m_monitor.cacheResource(cacheKey, currentResource); } } pathList.add(i, currentResource); if (i < (folderCount - 1)) { currentResourceName = it.next(); } } // read the (optional) last file resource in the path /x.html if (lastResourceIsFile) { if (it.hasNext()) { // this will only be false if a resource in the // top level root folder (e.g. "/index.html") was requested currentResourceName = it.next(); } currentPath.append(currentResourceName); // read the file cp = currentPath.toString(); cacheKey = getCacheKey(null, false, projectId, cp); currentResource = m_monitor.getCachedResource(cacheKey); if ((currentResource == null) || !dbc.getProjectId().isNullUUID()) { currentResource = getVfsDriver(dbc).readResource(dbc, projectId, cp, filter.includeDeleted()); if (dbc.getProjectId().isNullUUID()) { m_monitor.cacheResource(cacheKey, currentResource); } } pathList.add(i, currentResource); } return pathList; } /** * Reads a project given the projects id.

* * @param dbc the current database context * @param id the id of the project * * @return the project read * * @throws CmsDataAccessException if something goes wrong */ public CmsProject readProject(CmsDbContext dbc, CmsUUID id) throws CmsDataAccessException { CmsProject project = null; project = m_monitor.getCachedProject(id.toString()); if (project == null) { project = getProjectDriver(dbc).readProject(dbc, id); m_monitor.cacheProject(project); } return project; } /** * Reads a project.

* * Important: Since a project name can be used multiple times, this is NOT the most efficient * way to read the project. This is only a convenience for front end developing. * Reading a project by name will return the first project with that name. * All core classes must use the id version {@link #readProject(CmsDbContext, CmsUUID)} to ensure the right project is read.

* * @param dbc the current database context * @param name the name of the project * * @return the project read * * @throws CmsException if something goes wrong */ public CmsProject readProject(CmsDbContext dbc, String name) throws CmsException { CmsProject project = null; project = m_monitor.getCachedProject(name); if (project == null) { project = getProjectDriver(dbc).readProject(dbc, name); m_monitor.cacheProject(project); } return project; } /** * Returns the list of all resource names that define the "view" of the given project.

* * @param dbc the current database context * @param project the project to get the project resources for * * @return the list of all resources, as {@link String} objects * that define the "view" of the given project. * * @throws CmsException if something goes wrong */ public List readProjectResources(CmsDbContext dbc, CmsProject project) throws CmsException { return getProjectDriver(dbc).readProjectResources(dbc, project); } /** * Reads all resources of a project that match a given state from the VFS.

* * Possible values for the state parameter are:
*

    *
  • {@link CmsResource#STATE_CHANGED}: Read all "changed" resources in the project
  • *
  • {@link CmsResource#STATE_NEW}: Read all "new" resources in the project
  • *
  • {@link CmsResource#STATE_DELETED}: Read all "deleted" resources in the project
  • *
  • {@link CmsResource#STATE_KEEP}: Read all resources either "changed", "new" or "deleted" in the project
  • *

* * @param dbc the current database context * @param projectId the id of the project to read the file resources for * @param state the resource state to match * * @return a list of {@link CmsResource} objects matching the filter criteria * * @throws CmsException if something goes wrong * * @see CmsObject#readProjectView(CmsUUID, CmsResourceState) */ public List readProjectView(CmsDbContext dbc, CmsUUID projectId, CmsResourceState state) throws CmsException { List resources; if (state.isNew() || state.isChanged() || state.isDeleted()) { // get all resources form the database that match the selected state resources = getVfsDriver(dbc).readResources(dbc, projectId, state, CmsDriverManager.READMODE_MATCHSTATE); } else { // get all resources form the database that are somehow changed (i.e. not unchanged) resources = getVfsDriver( dbc).readResources(dbc, projectId, CmsResource.STATE_UNCHANGED, CmsDriverManager.READMODE_UNMATCHSTATE); } // filter the permissions List result = filterPermissions(dbc, resources, CmsResourceFilter.ALL); // sort the result Collections.sort(result); // set the full resource names return updateContextDates(dbc, result); } /** * Reads a property definition.

* * If no property definition with the given name is found, * null is returned.

* * @param dbc the current database context * @param name the name of the property definition to read * * @return the property definition that was read * * @throws CmsException a CmsDbEntryNotFoundException is thrown if the property definition does not exist */ public CmsPropertyDefinition readPropertyDefinition(CmsDbContext dbc, String name) throws CmsException { return getVfsDriver(dbc).readPropertyDefinition(dbc, name, dbc.currentProject().getUuid()); } /** * Reads a property object from a resource specified by a property name.

* * Returns {@link CmsProperty#getNullProperty()} if the property is not found.

* * @param dbc the current database context * @param resource the resource where the property is read from * @param key the property key name * @param search if true, the property is searched on all parent folders of the resource. * if it's not found attached directly to the resource. * * @return the required property, or {@link CmsProperty#getNullProperty()} if the property was not found * * @throws CmsException if something goes wrong */ public CmsProperty readPropertyObject(CmsDbContext dbc, CmsResource resource, String key, boolean search) throws CmsException { // NOTE: Do not call readPropertyObject(dbc, resource, key, search, null) for performance reasons // use the list reading method to obtain all properties for the resource List properties = readPropertyObjects(dbc, resource, search); int i = properties.indexOf(new CmsProperty(key, null, null)); if (i >= 0) { // property has been found in the map CmsProperty result = properties.get(i); // ensure the result value is not frozen return result.cloneAsProperty(); } return CmsProperty.getNullProperty(); } /** * Reads a property object from a resource specified by a property name.

* * Returns {@link CmsProperty#getNullProperty()} if the property is not found.

* * @param dbc the current database context * @param resource the resource where the property is read from * @param key the property key name * @param search if true, the property is searched on all parent folders of the resource. * if it's not found attached directly to the resource. * @param locale the locale for which the property should be read. * * @return the required property, or {@link CmsProperty#getNullProperty()} if the property was not found * * @throws CmsException if something goes wrong */ public CmsProperty readPropertyObject( CmsDbContext dbc, CmsResource resource, String key, boolean search, Locale locale) throws CmsException { // use the list reading method to obtain all properties for the resource List properties = readPropertyObjects(dbc, resource, search); // create a lookup property object and look this up in the result map CmsProperty result = null; // handle the case without locale separately to improve performance for (String localizedKey : CmsLocaleManager.getLocaleVariants(key, locale, true, false)) { int i = properties.indexOf(new CmsProperty(localizedKey, null, null)); if (i >= 0) { // property has been found in the map result = properties.get(i); // ensure the result value is not frozen return result.cloneAsProperty(); } } return CmsProperty.getNullProperty(); } /** * Reads all property objects mapped to a specified resource from the database.

* * All properties in the result List will be in frozen (read only) state, so you can't change the values.

* * Returns an empty list if no properties are found at all.

* * @param dbc the current database context * @param resource the resource where the properties are read from * @param search true, if the properties should be searched on all parent folders if not found on the resource * * @return a list of CmsProperty objects containing the structure and/or resource value * * @throws CmsException if something goes wrong * * @see CmsObject#readPropertyObjects(String, boolean) */ public List readPropertyObjects(CmsDbContext dbc, CmsResource resource, boolean search) throws CmsException { // check if we have the result already cached CmsUUID projectId = getProjectIdForContext(dbc); String cacheKey = getCacheKey(CACHE_ALL_PROPERTIES, search, projectId, resource.getRootPath()); List properties = m_monitor.getCachedPropertyList(cacheKey); if ((properties == null) || !dbc.getProjectId().isNullUUID()) { // result not cached, let's look it up in the DB if (search) { boolean cont; properties = new ArrayList(); List parentProperties = null; do { try { parentProperties = readPropertyObjects(dbc, resource, false); // make sure properties from lower folders "overwrite" properties from upper folders parentProperties.removeAll(properties); parentProperties.addAll(properties); properties.clear(); properties.addAll(parentProperties); cont = resource.getRootPath().length() > 1; } catch (CmsSecurityException se) { // a security exception (probably no read permission) we return the current result cont = false; } if (cont) { // no permission check on parent folder is required since we must have "read" // permissions to read the child resource anyway resource = readResource( dbc, CmsResource.getParentFolder(resource.getRootPath()), CmsResourceFilter.ALL); } } while (cont); } else { properties = getVfsDriver(dbc).readPropertyObjects(dbc, dbc.currentProject(), resource); // for (CmsProperty prop : properties) { // prop.setOrigin(resource.getRootPath()); // } } // set all properties in the result list as frozen CmsProperty.setFrozen(properties); if (dbc.getProjectId().isNullUUID()) { // store the result in the cache if needed m_monitor.cachePropertyList(cacheKey, properties); } } return new ArrayList(properties); } /** * Reads the resources that were published in a publish task for a given publish history ID.

* * @param dbc the current database context * @param publishHistoryId unique int ID to identify each publish task in the publish history * * @return a list of {@link org.opencms.db.CmsPublishedResource} objects * * @throws CmsException if something goes wrong */ public List readPublishedResources(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { String cacheKey = publishHistoryId.toString(); List resourceList = m_monitor.getCachedPublishedResources(cacheKey); if ((resourceList == null) || !dbc.getProjectId().isNullUUID()) { resourceList = getProjectDriver(dbc).readPublishedResources(dbc, publishHistoryId); // store the result in the cache if (dbc.getProjectId().isNullUUID()) { m_monitor.cachePublishedResources(cacheKey, resourceList); } } return resourceList; } /** * Reads a single publish job identified by its publish history id.

* * @param dbc the current database context * @param publishHistoryId unique id to identify the publish job in the publish history * @return an object of type {@link CmsPublishJobInfoBean} * * @throws CmsException if something goes wrong */ public CmsPublishJobInfoBean readPublishJob(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { return getProjectDriver(dbc).readPublishJob(dbc, publishHistoryId); } /** * Reads all available publish jobs.

* * @param dbc the current database context * @param startTime the start of the time range for finish time * @param endTime the end of the time range for finish time * @return a list of objects of type {@link CmsPublishJobInfoBean} * * @throws CmsException if something goes wrong */ public List readPublishJobs(CmsDbContext dbc, long startTime, long endTime) throws CmsException { return getProjectDriver(dbc).readPublishJobs(dbc, startTime, endTime); } /** * Reads the publish list assigned to a publish job.

* * @param dbc the current database context * @param publishHistoryId the history id identifying the publish job * @return the assigned publish list * @throws CmsException if something goes wrong */ public CmsPublishList readPublishList(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { return getProjectDriver(dbc).readPublishList(dbc, publishHistoryId); } /** * Reads the publish report assigned to a publish job.

* * @param dbc the current database context * @param publishHistoryId the history id identifying the publish job * @return the content of the assigned publish report * @throws CmsException if something goes wrong */ public byte[] readPublishReportContents(CmsDbContext dbc, CmsUUID publishHistoryId) throws CmsException { return getProjectDriver(dbc).readPublishReportContents(dbc, publishHistoryId); } /** * Reads an historical resource entry for the given resource and with the given version number.

* * @param dbc the current db context * @param resource the resource to be read * @param version the version number to retrieve * * @return the resource that was read * * @throws CmsException if the resource could not be read for any reason * * @see CmsObject#restoreResourceVersion(CmsUUID, int) * @see CmsObject#readResource(CmsUUID, int) */ public I_CmsHistoryResource readResource(CmsDbContext dbc, CmsResource resource, int version) throws CmsException { Iterator itVersions = getHistoryDriver(dbc).readAllAvailableVersions( dbc, resource.getStructureId()).iterator(); while (itVersions.hasNext()) { I_CmsHistoryResource histRes = itVersions.next(); if (histRes.getVersion() == version) { return histRes; } } throw new CmsVfsResourceNotFoundException( org.opencms.db.generic.Messages.get().container( org.opencms.db.generic.Messages.ERR_HISTORY_FILE_NOT_FOUND_1, resource.getStructureId())); } /** * Reads a resource from the VFS, using the specified resource filter.

* * @param dbc the current database context * @param structureID the structure id of the resource to read * @param filter the resource filter to use while reading * * @return the resource that was read * * @throws CmsDataAccessException if something goes wrong * * @see CmsObject#readResource(CmsUUID, CmsResourceFilter) * @see CmsObject#readResource(CmsUUID) */ public CmsResource readResource(CmsDbContext dbc, CmsUUID structureID, CmsResourceFilter filter) throws CmsDataAccessException { CmsUUID projectId = getProjectIdForContext(dbc); // please note: the filter will be applied in the security manager later CmsResource resource = getVfsDriver(dbc).readResource(dbc, projectId, structureID, filter.includeDeleted()); // context dates need to be updated updateContextDates(dbc, resource); // return the resource return resource; } /** * Reads a resource from the VFS, using the specified resource filter.

* * @param dbc the current database context * @param resourcePath the name of the resource to read (full path) * @param filter the resource filter to use while reading * * @return the resource that was read * * @throws CmsDataAccessException if something goes wrong * * @see CmsObject#readResource(String, CmsResourceFilter) * @see CmsObject#readResource(String) * @see CmsObject#readFile(CmsResource) */ public CmsResource readResource(CmsDbContext dbc, String resourcePath, CmsResourceFilter filter) throws CmsDataAccessException { CmsUUID projectId = getProjectIdForContext(dbc); // please note: the filter will be applied in the security manager later CmsResource resource = getVfsDriver(dbc).readResource(dbc, projectId, resourcePath, filter.includeDeleted()); // context dates need to be updated updateContextDates(dbc, resource); // return the resource return resource; } /** * Reads all resources below the given path matching the filter criteria, * including the full tree below the path only in case the readTree * parameter is true.

* * @param dbc the current database context * @param parent the parent path to read the resources from * @param filter the filter * @param readTree true to read all subresources * * @return a list of {@link CmsResource} objects matching the filter criteria * * @throws CmsDataAccessException if the bare reading of the resources fails * @throws CmsException if security and permission checks for the resources read fail */ public List readResources( CmsDbContext dbc, CmsResource parent, CmsResourceFilter filter, boolean readTree) throws CmsException, CmsDataAccessException { // try to get the sub resources from the cache String cacheKey = getCacheKey( new String[] {dbc.currentUser().getName(), filter.getCacheId(), readTree ? "+" : "-", parent.getRootPath()}, dbc); List resourceList = m_monitor.getCachedResourceList(cacheKey); if ((resourceList == null) || !dbc.getProjectId().isNullUUID()) { // read the result from the database resourceList = getVfsDriver(dbc).readResourceTree( dbc, dbc.currentProject().getUuid(), (readTree ? parent.getRootPath() : parent.getStructureId().toString()), filter.getType(), filter.getState(), filter.getModifiedAfter(), filter.getModifiedBefore(), filter.getReleaseAfter(), filter.getReleaseBefore(), filter.getExpireAfter(), filter.getExpireBefore(), (readTree ? CmsDriverManager.READMODE_INCLUDE_TREE : CmsDriverManager.READMODE_EXCLUDE_TREE) | (filter.excludeType() ? CmsDriverManager.READMODE_EXCLUDE_TYPE : 0) | (filter.excludeState() ? CmsDriverManager.READMODE_EXCLUDE_STATE : 0) | ((filter.getOnlyFolders() != null) ? (filter.getOnlyFolders().booleanValue() ? CmsDriverManager.READMODE_ONLY_FOLDERS : CmsDriverManager.READMODE_ONLY_FILES) : 0)); // HACK: do not take care of permissions if reading organizational units if (!parent.getRootPath().startsWith("/system/orgunits/")) { // apply permission filter resourceList = filterPermissions(dbc, resourceList, filter); } // store the result in the resourceList cache if (dbc.getProjectId().isNullUUID()) { m_monitor.cacheResourceList(cacheKey, resourceList); } } // we must always apply the result filter and update the context dates return updateContextDates(dbc, resourceList, filter); } /** * Returns the resources that were visited by a user set in the filter.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param filter the filter that is used to get the visited resources * * @return the resources that were visited by a user set in the filter * * @throws CmsException if something goes wrong */ public List readResourcesVisitedBy(CmsDbContext dbc, String poolName, CmsVisitedByFilter filter) throws CmsException { List result = getSubscriptionDriver().readResourcesVisitedBy(dbc, poolName, filter); result = filterPermissions(dbc, result, CmsResourceFilter.DEFAULT); return result; } /** * Reads all resources that have a value (containing the given value string) set * for the specified property (definition) in the given path.

* * Both individual and shared properties of a resource are checked.

* * If the value parameter is null, all resources having the * given property set are returned.

* * @param dbc the current database context * @param folder the folder to get the resources with the property from * @param propertyDefinition the name of the property (definition) to check for * @param value the string to search in the value of the property * @param filter the resource filter to apply to the result set * * @return a list of all {@link CmsResource} objects * that have a value set for the specified property. * * @throws CmsException if something goes wrong */ public List readResourcesWithProperty( CmsDbContext dbc, CmsResource folder, String propertyDefinition, String value, CmsResourceFilter filter) throws CmsException { String cacheKey; if (value == null) { cacheKey = getCacheKey( new String[] { dbc.currentUser().getName(), folder.getRootPath(), propertyDefinition, filter.getCacheId()}, dbc); } else { cacheKey = getCacheKey( new String[] { dbc.currentUser().getName(), folder.getRootPath(), propertyDefinition, value, filter.getCacheId()}, dbc); } List resourceList = m_monitor.getCachedResourceList(cacheKey); if ((resourceList == null) || !dbc.getProjectId().isNullUUID()) { CmsPropertyDefinition propDef = null; try { // first read the property definition propDef = readPropertyDefinition(dbc, propertyDefinition); } catch (CmsDbEntryNotFoundException e) { LOG.debug(e.getLocalizedMessage(), e); } if (propDef != null) { // now read the list of resources that have a value set for the property definition resourceList = getVfsDriver(dbc).readResourcesWithProperty( dbc, dbc.currentProject().getUuid(), propDef.getId(), folder.getRootPath(), value); // apply permission filter resourceList = filterPermissions(dbc, resourceList, filter); } else { resourceList = new ArrayList<>(); } // store the result in the resourceList cache if (dbc.getProjectId().isNullUUID()) { m_monitor.cacheResourceList(cacheKey, resourceList); } } // we must always apply the result filter and update the context dates return updateContextDates(dbc, resourceList, filter); } /** * Returns the set of users that are responsible for a specific resource.

* * @param dbc the current database context * @param resource the resource to get the responsible users from * * @return the set of users that are responsible for a specific resource * * @throws CmsException if something goes wrong */ public Set readResponsiblePrincipals(CmsDbContext dbc, CmsResource resource) throws CmsException { Set result = new HashSet(); Iterator aces = getAccessControlEntries(dbc, resource, true).iterator(); while (aces.hasNext()) { CmsAccessControlEntry ace = aces.next(); if (ace.isResponsible()) { I_CmsPrincipal p = lookupPrincipal(dbc, ace.getPrincipal()); if (p != null) { result.add(p); } } } return result; } /** * Returns the set of users that are responsible for a specific resource.

* * @param dbc the current database context * @param resource the resource to get the responsible users from * * @return the set of users that are responsible for a specific resource * * @throws CmsException if something goes wrong */ public Set readResponsibleUsers(CmsDbContext dbc, CmsResource resource) throws CmsException { Set result = new HashSet(); Iterator principals = readResponsiblePrincipals(dbc, resource).iterator(); while (principals.hasNext()) { I_CmsPrincipal principal = principals.next(); if (principal.isGroup()) { try { result.addAll(getUsersOfGroup(dbc, principal.getName(), true, false, false)); } catch (CmsException e) { if (LOG.isInfoEnabled()) { LOG.info(e.getLocalizedMessage(), e); } } } else { result.add((CmsUser)principal); } } return result; } /** * Returns a List of all siblings of the specified resource, * the specified resource being always part of the result set.

* * The result is a list of {@link CmsResource} objects.

* * @param dbc the current database context * @param resource the resource to read the siblings for * @param filter a filter object * * @return a list of {@link CmsResource} Objects that * are siblings to the specified resource, * including the specified resource itself * * @throws CmsException if something goes wrong */ public List readSiblings(CmsDbContext dbc, CmsResource resource, CmsResourceFilter filter) throws CmsException { List siblings = getVfsDriver( dbc).readSiblings(dbc, dbc.currentProject().getUuid(), resource, filter.includeDeleted()); // important: there is no permission check done on the returned list of siblings // this is because of possible issues with the "publish all siblings" option, // moreover the user has read permission for the content through // the selected sibling anyway return updateContextDates(dbc, siblings, filter); } /** * Returns the parameters of a resource in the table of all published template resources.

* * @param dbc the current database context * @param rfsName the rfs name of the resource * * @return the parameter string of the requested resource * * @throws CmsException if something goes wrong */ public String readStaticExportPublishedResourceParameters(CmsDbContext dbc, String rfsName) throws CmsException { return getProjectDriver(dbc).readStaticExportPublishedResourceParameters(dbc, rfsName); } /** * Returns a list of all template resources which must be processed during a static export.

* * @param dbc the current database context * @param parameterResources flag for reading resources with parameters (1) or without (0) * @param timestamp for reading the data from the db * * @return a list of template resources as {@link String} objects * * @throws CmsException if something goes wrong */ public List readStaticExportResources(CmsDbContext dbc, int parameterResources, long timestamp) throws CmsException { return getProjectDriver(dbc).readStaticExportResources(dbc, parameterResources, timestamp); } /** * Returns the subscribed history resources that were deleted.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param user the user that subscribed to the resource * @param groups the groups to check subscribed resources for * @param parent the parent resource (folder) of the deleted resources, if null all deleted resources will be returned * @param includeSubFolders indicates if the sub folders of the specified folder path should be considered, too * @param deletedFrom the time stamp from which the resources should have been deleted * * @return the subscribed history resources that were deleted * * @throws CmsException if something goes wrong */ public List readSubscribedDeletedResources( CmsDbContext dbc, String poolName, CmsUser user, List groups, CmsResource parent, boolean includeSubFolders, long deletedFrom) throws CmsException { List result = getSubscriptionDriver().readSubscribedDeletedResources( dbc, poolName, user, groups, parent, includeSubFolders, deletedFrom); return result; } /** * Returns the resources that were subscribed by a user or group set in the filter.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param filter the filter that is used to get the subscribed resources * * @return the resources that were subscribed by a user or group set in the filter * * @throws CmsException if something goes wrong */ public List readSubscribedResources(CmsDbContext dbc, String poolName, CmsSubscriptionFilter filter) throws CmsException { List result = getSubscriptionDriver().readSubscribedResources(dbc, poolName, filter); result = filterPermissions(dbc, result, CmsResourceFilter.DEFAULT); return result; } /** * Reads URL name mapping entries which match the given filter.

* * @param dbc the database context * @param online if true, read online URL name mappings, else offline ones * @param filter the filter for matching the URL name entries * * @return the list of URL name mapping entries which match the given filter * * @throws CmsDataAccessException if something goes wrong */ public List readUrlNameMappingEntries( CmsDbContext dbc, boolean online, CmsUrlNameMappingFilter filter) throws CmsDataAccessException { I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); return vfsDriver.readUrlNameMappingEntries(dbc, online, filter); } /** * Reads the URL name mappings matching the given filter.

* * @param dbc the DB context to use * @param filter the filter used to select the mapping entries * @return the entries matching the given filter * * @throws CmsDataAccessException if something goes wrong */ public List readUrlNameMappings(CmsDbContext dbc, CmsUrlNameMappingFilter filter) throws CmsDataAccessException { List entries = getVfsDriver(dbc).readUrlNameMappingEntries( dbc, dbc.currentProject().isOnlineProject(), filter); return entries; } /** * Reads the newest URL names of a resource for all locales.

* * @param dbc the database context * @param id the resource's structure id * * @return the url names for the locales * * @throws CmsDataAccessException if the database operation failed */ public List readUrlNamesForAllLocales(CmsDbContext dbc, CmsUUID id) throws CmsDataAccessException { List result = new ArrayList(); List entries = getVfsDriver(dbc).readUrlNameMappingEntries( dbc, dbc.currentProject().isOnlineProject(), CmsUrlNameMappingFilter.ALL.filterStructureId(id)); ArrayListMultimap entriesByLocale = ArrayListMultimap.create(); for (CmsUrlNameMappingEntry entry : entries) { String localeKey = entry.getLocale(); entriesByLocale.put(localeKey, entry); } for (String localeKey : entriesByLocale.keySet()) { List entrs = entriesByLocale.get(localeKey); CmsUrlNameMappingEntry maxEntryForLocale = Collections.max(entrs, new UrlNameMappingComparator()); result.add(maxEntryForLocale.getName()); } return result; } /** * Returns a user object based on the id of a user.

* * @param dbc the current database context * @param id the id of the user to read * * @return the user read * * @throws CmsException if something goes wrong */ public CmsUser readUser(CmsDbContext dbc, CmsUUID id) throws CmsException { CmsUser user = m_monitor.getCachedUser(id.toString()); if (user == null) { user = getUserDriver(dbc).readUser(dbc, id); m_monitor.cacheUser(user); } // important: do not return the cached user object, but a clone to avoid unwanted changes on cached objects return user.clone(); } /** * Returns a user object.

* * @param dbc the current database context * @param username the name of the user that is to be read * * @return user read * * @throws CmsDataAccessException if operation was not successful */ public CmsUser readUser(CmsDbContext dbc, String username) throws CmsDataAccessException { CmsUser user = m_monitor.getCachedUser(username); if (user == null) { user = getUserDriver(dbc).readUser(dbc, username); m_monitor.cacheUser(user); } // important: do not return the cached user object, but a clone to avoid unwanted changes on cached objects return user.clone(); } /** * Returns a user object if the password for the user is correct.

* * If the user/pwd pair is not valid a {@link CmsException} is thrown.

* * @param dbc the current database context * @param username the username of the user that is to be read * @param password the password of the user that is to be read * * @return user read * * @throws CmsException if operation was not successful */ public CmsUser readUser(CmsDbContext dbc, String username, String password) throws CmsException { // don't read user from cache here because password may have changed CmsUser user = getUserDriver(dbc).readUser(dbc, username, password, null); m_monitor.cacheUser(user); return user; } /** * Removes an access control entry for a given resource and principal.

* * @param dbc the current database context * @param resource the resource * @param principal the id of the principal to remove the the access control entry for * * @throws CmsException if something goes wrong */ public void removeAccessControlEntry(CmsDbContext dbc, CmsResource resource, CmsUUID principal) throws CmsException { // remove the ace getUserDriver(dbc).removeAccessControlEntry(dbc, dbc.currentProject(), resource.getResourceId(), principal); // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_PERMISSIONS, new String[] {resource.getRootPath()}), false); // update the "last modified" information setDateLastModified(dbc, resource, resource.getDateLastModified()); // clear the cache m_monitor.clearAccessControlListCache(); // fire a resource modification event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_ACCESSCONTROL)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Removes a resource from the given organizational unit.

* * @param dbc the current db context * @param orgUnit the organizational unit to remove the resource from * @param resource the resource that is to be removed from the organizational unit * * @throws CmsException if something goes wrong * * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String) * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String) */ public void removeResourceFromOrgUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, CmsResource resource) throws CmsException { m_monitor.flushCache(CmsMemoryMonitor.CacheType.HAS_ROLE, CmsMemoryMonitor.CacheType.ROLE_LIST); getUserDriver(dbc).removeResourceFromOrganizationalUnit(dbc, orgUnit, resource); } /** * Removes a resource from the current project of the user.

* * @param dbc the current database context * @param resource the resource to apply this operation to * * @throws CmsException if something goes wrong * * @see CmsObject#copyResourceToProject(String) * @see I_CmsResourceType#copyResourceToProject(CmsObject, CmsSecurityManager, CmsResource) */ public void removeResourceFromProject(CmsDbContext dbc, CmsResource resource) throws CmsException { // remove the resource to the project only if the resource is already in the project if (isInsideCurrentProject(dbc, resource.getRootPath())) { // check if there are already any subfolders of this resource I_CmsProjectDriver projectDriver = getProjectDriver(dbc); if (resource.isFolder()) { List projectResources = projectDriver.readProjectResources(dbc, dbc.currentProject()); for (int i = 0; i < projectResources.size(); i++) { String resname = projectResources.get(i); if (resname.startsWith(resource.getRootPath())) { // delete the existing project resource first projectDriver.deleteProjectResource(dbc, dbc.currentProject().getUuid(), resname); } } } try { projectDriver.deleteProjectResource(dbc, dbc.currentProject().getUuid(), resource.getRootPath()); } catch (CmsException exc) { // if the subfolder exists already - all is ok } finally { m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROJECT_RESOURCES); OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_PROJECT_MODIFIED, Collections. singletonMap("project", dbc.currentProject()))); } } } /** * Removes the given resource to the given user's publish list.

* * @param dbc the database context * @param userId the user's id * @param structureIds the collection of structure IDs to remove * * @throws CmsDataAccessException if something goes wrong */ public void removeResourceFromUsersPubList(CmsDbContext dbc, CmsUUID userId, Collection structureIds) throws CmsDataAccessException { for (CmsUUID structureId : structureIds) { CmsLogEntry entry = new CmsLogEntry( userId, System.currentTimeMillis(), structureId, CmsLogEntryType.RESOURCE_HIDDEN, new String[] {readResource(dbc, structureId, CmsResourceFilter.ALL).getRootPath()}); log(dbc, entry, true); } } /** * Removes a user from a group.

* * @param dbc the current database context * @param username the name of the user that is to be removed from the group * @param groupname the name of the group * @param readRoles if to read roles or groups * * @throws CmsException if operation was not successful * @throws CmsIllegalArgumentException if the given user was not member in the given group * @throws CmsDbEntryNotFoundException if the given group was not found * @throws CmsSecurityException if the given user was read as 'null' from the database * * @see #addUserToGroup(CmsDbContext, String, String, boolean) */ public void removeUserFromGroup(CmsDbContext dbc, String username, String groupname, boolean readRoles) throws CmsException, CmsIllegalArgumentException, CmsDbEntryNotFoundException, CmsSecurityException { CmsGroup group = readGroup(dbc, groupname); //check if group exists if (group == null) { // the group does not exists throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, groupname)); } if (group.isVirtual() && !readRoles) { // if removing a user from a virtual role treat it as removing the user from the role removeUserFromGroup(dbc, username, CmsRole.valueOf(group).getGroupName(), true); return; } if (group.isVirtual()) { // this is an hack so to prevent a unlimited recursive calls readRoles = false; } if ((readRoles && !group.isRole()) || (!readRoles && group.isRole())) { // we want a role but we got a group, or the other way throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, groupname)); } boolean skipRemove = false; // test if this user is existing in the group if (!userInGroup(dbc, username, groupname, readRoles)) { if (readRoles) { // Sometimes users can end up with the default groups corresponding to roles (Administrators, Users) without the actual roles. // When trying to remove the user from such a group, we end up here in a recursive call of this method with readRoles = true. We do not // want to throw an exception then, because it would prevent the code that actually removes the user from the group from running. LOG.warn( "Trying to remove user from role that they are not a member of (user: " + username + ", group: " + groupname + ")"); skipRemove = true; } else { // user is not in the group, throw exception throw new CmsIllegalArgumentException( Messages.get().container(Messages.ERR_USER_NOT_IN_GROUP_2, username, groupname)); } } CmsUser user = readUser(dbc, username); //check if the user exists if (user == null) { // the user does not exists throw new CmsIllegalArgumentException( Messages.get().container(Messages.ERR_USER_NOT_IN_GROUP_2, username, groupname)); } if (readRoles) { CmsRole role = CmsRole.valueOf(group); // update virtual groups Iterator it = getVirtualGroupsForRole(dbc, role).iterator(); while (it.hasNext()) { CmsGroup virtualGroup = it.next(); if (userInGroup(dbc, username, virtualGroup.getName(), false)) { // here we say readroles = true, to prevent an unlimited recursive calls removeUserFromGroup(dbc, username, virtualGroup.getName(), true); } } } if (!skipRemove) { getUserDriver(dbc).deleteUserInGroup(dbc, user.getId(), group.getId()); } // flush relevant caches if (readRoles) { m_monitor.flushCache(CmsMemoryMonitor.CacheType.HAS_ROLE, CmsMemoryMonitor.CacheType.ROLE_LIST); } m_monitor.flushUserGroups(user.getId()); m_monitor.flushCache(CmsMemoryMonitor.CacheType.USER_LIST); if (!dbc.getProjectId().isNullUUID()) { // user modified event is not needed return; } // fire user modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); eventData.put(I_CmsEventListener.KEY_USER_NAME, user.getName()); eventData.put(I_CmsEventListener.KEY_GROUP_ID, group.getId().toString()); eventData.put(I_CmsEventListener.KEY_GROUP_NAME, group.getName()); eventData.put( I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_REMOVE_USER_FROM_GROUP); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); } /** * Repairs broken categories.

* * @param dbc the database context * @param projectId the project id * @param resource the resource to repair the categories for * * @throws CmsException if something goes wrong */ public void repairCategories(CmsDbContext dbc, CmsUUID projectId, CmsResource resource) throws CmsException { CmsObject cms = OpenCms.initCmsObject(new CmsObject(getSecurityManager(), dbc.getRequestContext())); cms.getRequestContext().setSiteRoot(""); cms.getRequestContext().setCurrentProject(readProject(dbc, projectId)); CmsCategoryService.getInstance().repairRelations(cms, resource); } /** * Replaces the content, type and properties of a resource.

* * @param dbc the current database context * @param resource the name of the resource to apply this operation to * @param type the new type of the resource * @param content the new content of the resource * @param properties the new properties of the resource * * @throws CmsException if something goes wrong * * @see CmsObject#replaceResource(String, int, byte[], List) * @see I_CmsResourceType#replaceResource(CmsObject, CmsSecurityManager, CmsResource, int, byte[], List) */ @SuppressWarnings("javadoc") public void replaceResource( CmsDbContext dbc, CmsResource resource, int type, byte[] content, List properties) throws CmsException { // replace the existing with the new file content getVfsDriver(dbc).replaceResource(dbc, resource, content, type); if ((properties != null) && !properties.isEmpty()) { // write the properties getVfsDriver(dbc).writePropertyObjects(dbc, dbc.currentProject(), resource, properties); m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); } // update the resource state if (resource.getState().isUnchanged()) { resource.setState(CmsResource.STATE_CHANGED); } resource.setUserLastModified(dbc.currentUser().getId()); // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_CONTENT_MODIFIED, new String[] {resource.getRootPath()}), false); setDateLastModified(dbc, resource, System.currentTimeMillis()); getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_RESOURCE, false); deleteRelationsWithSiblings(dbc, resource); // clear the cache m_monitor.clearResourceCache(); if ((properties != null) && !properties.isEmpty()) { // resource and properties were modified OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCE, resource))); } else { // only the resource was modified Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_RESOURCE | CHANGED_CONTENT)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } } /** * Resets the password for a specified user.

* * @param dbc the current database context * @param username the name of the user * @param oldPassword the old password * @param secondFactor the second factor data used for 2FA * @param newPassword the new password * * @throws CmsException if the user data could not be read from the database * @throws CmsSecurityException if the specified username and old password could not be verified */ public void resetPassword( CmsDbContext dbc, String username, String oldPassword, CmsSecondFactorInfo secondFactor, String newPassword) throws CmsException, CmsSecurityException { if ((oldPassword != null) && (newPassword != null)) { CmsUser user = null; if (dbc.getRequestContext().getAttribute(CmsUserDriver.REQ_ATTR_DONT_DIGEST_PASSWORD) == null) { validatePassword(newPassword); } // read the user as a system user to verify that the specified old password is correct try { user = getUserDriver(dbc).readUser(dbc, username, oldPassword, null); } catch (CmsDbEntryNotFoundException e) { throw new CmsDataAccessException(Messages.get().container(Messages.ERR_RESET_PASSWORD_1, username), e); } if ((user == null) || user.isManaged()) { throw new CmsDataAccessException(Messages.get().container(Messages.ERR_RESET_PASSWORD_1, username)); } CmsTwoFactorAuthenticationHandler twoFactorHandler = OpenCms.getTwoFactorAuthenticationHandler(); if (twoFactorHandler.needsTwoFactorAuthentication(user) && twoFactorHandler.hasSecondFactor(user)) { if (!twoFactorHandler.verifySecondFactor(user, secondFactor)) { throw new CmsDataAccessException( Messages.get().container(Messages.ERR_RESET_PASSWORD_1, username), new RuntimeException("Verification code mismatch")); } } getUserDriver(dbc).writePassword(dbc, username, oldPassword, newPassword); user.getAdditionalInfo().put( CmsUserSettings.ADDITIONAL_INFO_LAST_PASSWORD_CHANGE, "" + System.currentTimeMillis()); user.deleteAdditionalInfo(CmsUserSettings.ADDITIONAL_INFO_PASSWORD_RESET); getUserDriver(dbc).writeUser(dbc, user); if (!dbc.getProjectId().isNullUUID()) { // user modified event is not needed return; } // fire user modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); eventData.put( I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_RESET_PASSWORD); eventData.put( I_CmsEventListener.KEY_USER_CHANGES, Integer.valueOf(CmsUser.FLAG_CORE_DATA | CmsUser.FLAG_CORE_DATA)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); } else if (CmsStringUtil.isEmpty(oldPassword)) { throw new CmsDataAccessException(Messages.get().container(Messages.ERR_PWD_OLD_MISSING_0)); } else if (CmsStringUtil.isEmpty(newPassword)) { throw new CmsDataAccessException(Messages.get().container(Messages.ERR_PWD_NEW_MISSING_0)); } } /** * Restores a deleted resource identified by its structure id from the historical archive.

* * @param dbc the current database context * @param structureId the structure id of the resource to restore * * @throws CmsException if something goes wrong * * @see CmsObject#restoreDeletedResource(CmsUUID) */ public void restoreDeletedResource(CmsDbContext dbc, CmsUUID structureId) throws CmsException { // get the last version, which should be the deleted one int version = getHistoryDriver(dbc).readLastVersion(dbc, structureId); // get that version I_CmsHistoryResource histRes = getHistoryDriver(dbc).readResource(dbc, structureId, version); // check the parent path CmsResource parent; try { // try to read the parent resource by id parent = getVfsDriver(dbc).readResource(dbc, dbc.currentProject().getUuid(), histRes.getParentId(), true); } catch (CmsVfsResourceNotFoundException e) { // if not found try to read the parent resource by name try { // try to read the parent resource by id parent = getVfsDriver(dbc).readResource( dbc, dbc.currentProject().getUuid(), CmsResource.getParentFolder(histRes.getRootPath()), true); } catch (CmsVfsResourceNotFoundException e1) { // if not found try to restore the parent resource restoreDeletedResource(dbc, histRes.getParentId()); parent = readResource(dbc, histRes.getParentId(), CmsResourceFilter.IGNORE_EXPIRATION); } } // check write permissions m_securityManager.checkPermissions( dbc, parent, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.IGNORE_EXPIRATION); // check the name String path = parent.getRootPath(); String resName = CmsResource.getName(histRes.getRootPath()); // name String ext = ""; if (resName.charAt(resName.length() - 1) == '/') { resName = resName.substring(0, resName.length() - 1); } else { ext = CmsFileUtil.getExtension(resName); // extension } String nameWOExt = resName.substring(0, resName.length() - ext.length()); // name without extension for (int i = 1; true; i++) { try { readResource(dbc, path + resName, CmsResourceFilter.ALL); resName = nameWOExt + "_" + i + ext; // try the next resource name with following schema: path/name_{i}.ext } catch (CmsVfsResourceNotFoundException e) { // ok, we found a not used resource name break; } } // check structure id CmsUUID id = structureId; if (getVfsDriver(dbc).validateStructureIdExists(dbc, dbc.currentProject().getUuid(), structureId)) { // should never happen, but if already exists create a new one id = new CmsUUID(); } byte[] contents = null; boolean isFolder = true; // do we need the contents? if (histRes instanceof CmsFile) { contents = ((CmsFile)histRes).getContents(); if ((contents == null) || (contents.length == 0)) { contents = getHistoryDriver(dbc).readContent(dbc, histRes.getResourceId(), histRes.getPublishTag()); } isFolder = false; } // now read the historical properties List properties = getHistoryDriver(dbc).readProperties(dbc, histRes); // create the object to create CmsResource newResource = new CmsResource( id, histRes.getResourceId(), path + resName, histRes.getTypeId(), isFolder, histRes.getFlags(), dbc.currentProject().getUuid(), CmsResource.STATE_NEW, histRes.getDateCreated(), histRes.getUserCreated(), histRes.getDateLastModified(), dbc.currentUser().getId(), histRes.getDateReleased(), histRes.getDateExpired(), histRes.getSiblingCount(), histRes.getLength(), histRes.getDateContent(), histRes.getVersion()); // log it log( dbc, new CmsLogEntry( dbc, newResource.getStructureId(), CmsLogEntryType.RESOURCE_RESTORE_DELETED, new String[] {newResource.getRootPath()}), false); // prevent the date last modified is set to the current time newResource.setDateLastModified(newResource.getDateLastModified()); // restore the resource! CmsResource resource = createResource(dbc, path + resName, newResource, contents, properties, true); // set resource state to changed newResource.setState(CmsResource.STATE_CHANGED); getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), newResource, UPDATE_RESOURCE_STATE, false); newResource.setState(CmsResource.STATE_NEW); // fire the event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_RESOURCE | CHANGED_CONTENT)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Restores a resource in the current project with a version from the historical archive.

* * @param dbc the current database context * @param resource the resource to restore from the archive * @param version the version number to restore from the archive * * @throws CmsException if something goes wrong * * @see CmsObject#restoreResourceVersion(CmsUUID, int) * @see I_CmsResourceType#restoreResource(CmsObject, CmsSecurityManager, CmsResource, int) */ public void restoreResource(CmsDbContext dbc, CmsResource resource, int version) throws CmsException { I_CmsHistoryResource historyResource = readResource(dbc, resource, version); CmsResourceState state = CmsResource.STATE_CHANGED; if (resource.getState().isNew()) { state = CmsResource.STATE_NEW; } int newVersion = resource.getVersion(); if (resource.getState().isUnchanged()) { newVersion++; } CmsResource newResource = null; // is the resource a file? if (historyResource instanceof CmsFile) { // get the historical up flags int flags = historyResource.getFlags(); if (resource.isLabeled()) { // set the flag for labeled links on the restored file flags |= CmsResource.FLAG_LABELED; } CmsFile newFile = new CmsFile( resource.getStructureId(), resource.getResourceId(), resource.getRootPath(), historyResource.getTypeId(), flags, dbc.currentProject().getUuid(), state, resource.getDateCreated(), historyResource.getUserCreated(), resource.getDateLastModified(), dbc.currentUser().getId(), historyResource.getDateReleased(), historyResource.getDateExpired(), resource.getSiblingCount(), historyResource.getLength(), historyResource.getDateContent(), newVersion, readFile(dbc, (CmsHistoryFile)historyResource).getContents()); // log it log( dbc, new CmsLogEntry( dbc, newFile.getStructureId(), CmsLogEntryType.RESOURCE_HISTORY, new String[] {newFile.getRootPath()}), false); newResource = writeFile(dbc, newFile); } else { // it is a folder! newResource = new CmsFolder( resource.getStructureId(), resource.getResourceId(), resource.getRootPath(), historyResource.getTypeId(), historyResource.getFlags(), dbc.currentProject().getUuid(), state, resource.getDateCreated(), historyResource.getUserCreated(), resource.getDateLastModified(), dbc.currentUser().getId(), historyResource.getDateReleased(), historyResource.getDateExpired(), newVersion); // log it log( dbc, new CmsLogEntry( dbc, newResource.getStructureId(), CmsLogEntryType.RESOURCE_HISTORY, new String[] {newResource.getRootPath()}), false); writeResource(dbc, newResource); } if (newResource != null) { // now read the historical properties List historyProperties = getHistoryDriver(dbc).readProperties(dbc, historyResource); // remove all properties deleteAllProperties(dbc, newResource.getRootPath()); // write them to the restored resource writePropertyObjects(dbc, newResource, historyProperties, false); m_monitor.clearResourceCache(); } Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_RESOURCE | CHANGED_CONTENT)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Saves a list of aliases for the same structure id, replacing any aliases for the same structure id.

* * @param dbc the current database context * @param project the current project * @param structureId the structure id for which the aliases should be saved * @param aliases the list of aliases to save * * @throws CmsException if something goes wrong */ public void saveAliases(CmsDbContext dbc, CmsProject project, CmsUUID structureId, List aliases) throws CmsException { for (CmsAlias alias : aliases) { if (!structureId.equals(alias.getStructureId())) { throw new IllegalArgumentException("Aliases to replace must have the same structure id!"); } } I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); vfsDriver.deleteAliases(dbc, project, new CmsAliasFilter(null, null, structureId)); for (CmsAlias alias : aliases) { String aliasPath = alias.getAliasPath(); if (CmsAlias.ALIAS_PATTERN.matcher(aliasPath).matches()) { vfsDriver.insertAlias(dbc, project, alias); } else { LOG.error("Invalid alias path: " + aliasPath); } } } /** * Replaces the complete list of rewrite aliases for a given site root.

* * @param dbc the current database context * @param siteRoot the site root for which the rewrite aliases should be replaced * @param newAliases the new aliases for the given site root * @throws CmsException if something goes wrong */ public void saveRewriteAliases(CmsDbContext dbc, String siteRoot, List newAliases) throws CmsException { CmsRewriteAliasFilter filter = new CmsRewriteAliasFilter().setSiteRoot(siteRoot); getVfsDriver(dbc).deleteRewriteAliases(dbc, filter); getVfsDriver(dbc).insertRewriteAliases(dbc, newAliases); } /** * Searches for users which fit the given criteria.

* * @param dbc the database context * @param searchParams the search criteria * * @return the users which fit the search criteria * * @throws CmsDataAccessException if something goes wrong */ public List searchUsers(CmsDbContext dbc, CmsUserSearchParameters searchParams ) throws CmsDataAccessException { return getUserDriver(dbc).searchUsers(dbc, searchParams); } /** * Changes the "expire" date of a resource.

* * @param dbc the current database context * @param resource the resource to touch * @param dateExpired the new expire date of the resource * * @throws CmsDataAccessException if something goes wrong * * @see CmsObject#setDateExpired(String, long, boolean) * @see I_CmsResourceType#setDateExpired(CmsObject, CmsSecurityManager, CmsResource, long, boolean) */ public void setDateExpired(CmsDbContext dbc, CmsResource resource, long dateExpired) throws CmsDataAccessException { resource.setDateExpired(dateExpired); if (resource.getState().isUnchanged()) { resource.setState(CmsResource.STATE_CHANGED); } getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_STRUCTURE, false); // modify the last modified project reference getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_RESOURCE_PROJECT, false); // log log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_DATE_EXPIRED, new String[] {resource.getRootPath()}), false); // clear the cache m_monitor.clearResourceCache(); // fire the event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_TIMEFRAME)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Changes the "last modified" timestamp of a resource.

* * @param dbc the current database context * @param resource the resource to touch * @param dateLastModified the new last modified date of the resource * * @throws CmsDataAccessException if something goes wrong * * @see CmsObject#setDateLastModified(String, long, boolean) * @see I_CmsResourceType#setDateLastModified(CmsObject, CmsSecurityManager, CmsResource, long, boolean) */ public void setDateLastModified(CmsDbContext dbc, CmsResource resource, long dateLastModified) throws CmsDataAccessException { // modify the last modification date resource.setDateLastModified(dateLastModified); if (resource.getState().isUnchanged()) { resource.setState(CmsResource.STATE_CHANGED); } else if (resource.getState().isNew() && (resource.getSiblingCount() > 1)) { // in case of new resources with siblings make sure the state is correct resource.setState(CmsResource.STATE_CHANGED); } resource.setUserLastModified(dbc.currentUser().getId()); getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_RESOURCE, false); log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_TOUCHED, new String[] {resource.getRootPath()}), false); // clear the cache m_monitor.clearResourceCache(); // fire the event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_LASTMODIFIED)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Changes the "release" date of a resource.

* * @param dbc the current database context * @param resource the resource to touch * @param dateReleased the new release date of the resource * * @throws CmsDataAccessException if something goes wrong * * @see CmsObject#setDateReleased(String, long, boolean) * @see I_CmsResourceType#setDateReleased(CmsObject, CmsSecurityManager, CmsResource, long, boolean) */ public void setDateReleased(CmsDbContext dbc, CmsResource resource, long dateReleased) throws CmsDataAccessException { // modify the last modification date resource.setDateReleased(dateReleased); if (resource.getState().isUnchanged()) { resource.setState(CmsResource.STATE_CHANGED); } getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_STRUCTURE, false); // modify the last modified project reference getVfsDriver(dbc).writeResourceState(dbc, dbc.currentProject(), resource, UPDATE_RESOURCE_PROJECT, false); // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_DATE_RELEASED, new String[] {resource.getRootPath()}), false); // clear the cache m_monitor.clearResourceCache(); // fire the event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_TIMEFRAME)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Sets a new parent group for an already existing group.

* * @param dbc the current database context * @param groupName the name of the group that should be written * @param parentGroupName the name of the parent group to set, * or null if the parent * group should be deleted. * * @throws CmsException if operation was not successful * @throws CmsDataAccessException if the group with groupName could not be read from VFS */ public void setParentGroup(CmsDbContext dbc, String groupName, String parentGroupName) throws CmsException, CmsDataAccessException { CmsGroup group = readGroup(dbc, groupName); CmsUUID parentGroupId = CmsUUID.getNullUUID(); // if the group exists, use its id, else set to unknown. if (parentGroupName != null) { parentGroupId = readGroup(dbc, parentGroupName).getId(); } group.setParentId(parentGroupId); // write the changes to the cms writeGroup(dbc, group); } /** * Sets the password for a user.

* * @param dbc the current database context * @param username the name of the user * @param newPassword the new password * * @throws CmsException if operation was not successful * @throws CmsIllegalArgumentException if the user with the username was not found */ public void setPassword(CmsDbContext dbc, String username, String newPassword) throws CmsException, CmsIllegalArgumentException { if (dbc.getRequestContext().getAttribute(CmsUserDriver.REQ_ATTR_DONT_DIGEST_PASSWORD) == null) { validatePassword(newPassword); } // read the user as a system user to verify that the specified old password is correct CmsUser user = getUserDriver(dbc).readUser(dbc, username); // only continue if not found and read user from web might succeed getUserDriver(dbc).writePassword(dbc, username, null, newPassword); user.getAdditionalInfo().put( CmsUserSettings.ADDITIONAL_INFO_LAST_PASSWORD_CHANGE, "" + System.currentTimeMillis()); getUserDriver(dbc).writeUser(dbc, user); // fire user modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_RESET_PASSWORD); eventData.put( I_CmsEventListener.KEY_USER_CHANGES, Integer.valueOf(CmsUser.FLAG_CORE_DATA | CmsUser.FLAG_CORE_DATA)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); } /** * Marks a subscribed resource as deleted.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param resource the subscribed resource to mark as deleted * * @throws CmsException if something goes wrong */ public void setSubscribedResourceAsDeleted(CmsDbContext dbc, String poolName, CmsResource resource) throws CmsException { getSubscriptionDriver().setSubscribedResourceAsDeleted(dbc, poolName, resource); } /** * Moves an user to the given organizational unit.

* * @param dbc the current db context * @param orgUnit the organizational unit to add the resource to * @param user the user that is to be moved to the organizational unit * * @throws CmsException if something goes wrong * * @see org.opencms.security.CmsOrgUnitManager#setUsersOrganizationalUnit(CmsObject, String, String) */ public void setUsersOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, CmsUser user) throws CmsException { if (!getGroupsOfUser(dbc, user.getName(), false).isEmpty()) { throw new CmsDbConsistencyException( Messages.get().container(Messages.ERR_ORGUNIT_MOVE_USER_2, orgUnit.getName(), user.getName())); } // move the principal getUserDriver(dbc).setUsersOrganizationalUnit(dbc, orgUnit, user); // remove the principal from cache m_monitor.clearUserCache(user); if (!dbc.getProjectId().isNullUUID()) { // user modified event is not needed return; } // fire user modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); eventData.put(I_CmsEventListener.KEY_OU_NAME, user.getOuFqn()); eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_SET_OU); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); } /** * Subscribes the user or group to the resource.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param principal the principal that subscribes to the resource * @param resource the resource to subscribe to * * @throws CmsException if something goes wrong */ public void subscribeResourceFor(CmsDbContext dbc, String poolName, CmsPrincipal principal, CmsResource resource) throws CmsException { getSubscriptionDriver().subscribeResourceFor(dbc, poolName, principal, resource); } /** * Undelete the resource.

* * @param dbc the current database context * @param resource the name of the resource to apply this operation to * * @throws CmsException if something goes wrong * * @see CmsObject#undeleteResource(String, boolean) * @see I_CmsResourceType#undelete(CmsObject, CmsSecurityManager, CmsResource, boolean) */ public void undelete(CmsDbContext dbc, CmsResource resource) throws CmsException { if (!resource.getState().isDeleted()) { throw new CmsVfsException( Messages.get().container( Messages.ERR_UNDELETE_FOR_RESOURCE_DELETED_1, dbc.removeSiteRoot(resource.getRootPath()))); } // set the state to changed resource.setState(CmsResourceState.STATE_CHANGED); // perform the changes updateState(dbc, resource, false); // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_UNDELETED, new String[] {resource.getRootPath()}), false); // clear the cache m_monitor.clearResourceCache(); // fire change event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_RESOURCE)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Undos all changes in the resource by restoring the version from the * online project to the current offline project.

* * @param dbc the current database context * @param resource the name of the resource to apply this operation to * @param mode the undo mode, one of the {@link org.opencms.file.CmsResource.CmsResourceUndoMode}#UNDO_XXX constants * please note that the recursive flag is ignored at this level * * @throws CmsException if something goes wrong * * @see CmsObject#undoChanges(String, CmsResource.CmsResourceUndoMode) * @see I_CmsResourceType#undoChanges(CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceUndoMode) */ public void undoChanges(CmsDbContext dbc, CmsResource resource, CmsResource.CmsResourceUndoMode mode) throws CmsException { if (resource.getState().isNew()) { // undo changes is impossible on a new resource throw new CmsVfsException(Messages.get().container(Messages.ERR_UNDO_CHANGES_FOR_RESOURCE_NEW_0)); } // we need this for later use CmsProject onlineProject = readProject(dbc, CmsProject.ONLINE_PROJECT_ID); // read the resource from the online project CmsResource onlineResource = getVfsDriver( dbc).readResource(dbc, CmsProject.ONLINE_PROJECT_ID, resource.getStructureId(), true); CmsResource onlineResourceByPath = null; try { // this is needed to figure out if a moved resource overwrote a deleted one onlineResourceByPath = getVfsDriver( dbc).readResource(dbc, CmsProject.ONLINE_PROJECT_ID, resource.getRootPath(), true); // force undo move operation if needed if (!mode.isUndoMove() && !onlineResourceByPath.getRootPath().equals(onlineResource.getRootPath())) { mode = mode.includeMove(); } } catch (Exception e) { // ok } boolean moved = !onlineResource.getRootPath().equals(resource.getRootPath()); // undo move operation if required if (moved && mode.isUndoMove()) { moveResource(dbc, resource, onlineResource.getRootPath(), true); if ((onlineResourceByPath != null) && !onlineResourceByPath.getRootPath().equals(onlineResource.getRootPath())) { // was moved over deleted, so the deleted file has to be undone undoContentChanges(dbc, onlineProject, null, onlineResourceByPath, CmsResource.STATE_UNCHANGED, true); } } // undo content changes CmsResourceState newState = CmsResource.STATE_UNCHANGED; if (moved && !mode.isUndoMove()) { newState = CmsResource.STATE_CHANGED; } undoContentChanges(dbc, onlineProject, resource, onlineResource, newState, moved && mode.isUndoMove()); // because undoContentChanges deletes the offline resource internally, we have // to write an entry to the log table to prevent the resource from appearing in the // user's publish list. log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_CHANGES_UNDONE, new String[] {resource.getRootPath()}), true); } /** * Unlocks all resources in the given project.

* * @param project the project to unlock the resources in */ public void unlockProject(CmsProject project) { // unlock all resources in the project m_lockManager.removeResourcesInProject(project.getUuid(), false); m_monitor.clearResourceCache(); m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROJECT, CmsMemoryMonitor.CacheType.PERMISSION); } /** * Unlocks a resource.

* * @param dbc the current database context * @param resource the resource to unlock * @param force true, if a resource is forced to get unlocked, no matter by which user and in which project the resource is currently locked * @param removeSystemLock true, if you also want to remove system locks * * @throws CmsException if something goes wrong * * @see CmsObject#unlockResource(String) * @see I_CmsResourceType#unlockResource(CmsObject, CmsSecurityManager, CmsResource) */ public void unlockResource(CmsDbContext dbc, CmsResource resource, boolean force, boolean removeSystemLock) throws CmsException { // update the resource cache m_monitor.clearResourceCache(); // now update lock status m_lockManager.removeResource(dbc, resource, force, removeSystemLock); // we must also clear the permission cache m_monitor.flushCache(CmsMemoryMonitor.CacheType.PERMISSION); // fire resource modification event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(NOTHING_CHANGED)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Unsubscribes all deleted resources that were deleted before the specified time stamp.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param deletedTo the time stamp to which the resources have been deleted * * @throws CmsException if something goes wrong */ public void unsubscribeAllDeletedResources(CmsDbContext dbc, String poolName, long deletedTo) throws CmsException { getSubscriptionDriver().unsubscribeAllDeletedResources(dbc, poolName, deletedTo); } /** * Unsubscribes the principal from all resources.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param principal the principal that unsubscribes from all resources * * @throws CmsException if something goes wrong */ public void unsubscribeAllResourcesFor(CmsDbContext dbc, String poolName, CmsPrincipal principal) throws CmsException { getSubscriptionDriver().unsubscribeAllResourcesFor(dbc, poolName, principal); } /** * Unsubscribes the principal from the resource.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param principal the principal that unsubscribes from the resource * @param resource the resource to unsubscribe from * * @throws CmsException if something goes wrong */ public void unsubscribeResourceFor(CmsDbContext dbc, String poolName, CmsPrincipal principal, CmsResource resource) throws CmsException { getSubscriptionDriver().unsubscribeResourceFor(dbc, poolName, principal, resource); } /** * Unsubscribes all groups and users from the resource.

* * @param dbc the database context * @param poolName the name of the database pool to use * @param resource the resource to unsubscribe all groups and users from * * @throws CmsException if something goes wrong */ public void unsubscribeResourceForAll(CmsDbContext dbc, String poolName, CmsResource resource) throws CmsException { getSubscriptionDriver().unsubscribeResourceForAll(dbc, poolName, resource); } /** * Update the export points.

* * All files and folders "inside" an export point are written.

* * @param dbc the current database context */ public void updateExportPoints(CmsDbContext dbc) { try { // read the export points and return immediately if there are no export points at all Set exportPoints = new HashSet(); exportPoints.addAll(OpenCms.getExportPoints()); exportPoints.addAll(OpenCms.getModuleManager().getExportPoints()); if (exportPoints.size() == 0) { if (LOG.isWarnEnabled()) { LOG.warn(Messages.get().getBundle().key(Messages.LOG_NO_EXPORT_POINTS_CONFIGURED_0)); } return; } // create the driver to write the export points I_CmsExportPointDriver exportPointDriver = OpenCms.getImportExportManager().createExportPointDriver( exportPoints); // the export point hash table contains RFS export paths keyed by their internal VFS paths Iterator i = exportPointDriver.getExportPointPaths().iterator(); I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); while (i.hasNext()) { String currentExportPoint = i.next(); // print some report messages if (LOG.isInfoEnabled()) { LOG.info(Messages.get().getBundle().key(Messages.LOG_WRITE_EXPORT_POINT_1, currentExportPoint)); } try { CmsResourceFilter filter = CmsResourceFilter.DEFAULT; List resources = vfsDriver.readResourceTree( dbc, CmsProject.ONLINE_PROJECT_ID, currentExportPoint, filter.getType(), filter.getState(), filter.getModifiedAfter(), filter.getModifiedBefore(), filter.getReleaseAfter(), filter.getReleaseBefore(), filter.getExpireAfter(), filter.getExpireBefore(), CmsDriverManager.READMODE_INCLUDE_TREE | (filter.excludeType() ? CmsDriverManager.READMODE_EXCLUDE_TYPE : 0) | (filter.excludeState() ? CmsDriverManager.READMODE_EXCLUDE_STATE : 0)); Iterator j = resources.iterator(); while (j.hasNext()) { CmsResource currentResource = j.next(); if (currentResource.isFolder()) { // export the folder exportPointDriver.createFolder(currentResource.getRootPath(), currentExportPoint); } else { // try to create the exportpoint folder exportPointDriver.createFolder(currentExportPoint, currentExportPoint); byte[] onlineContent = vfsDriver.readContent( dbc, CmsProject.ONLINE_PROJECT_ID, currentResource.getResourceId()); // export the file content online exportPointDriver.writeFile( currentResource.getRootPath(), currentExportPoint, onlineContent); } } } catch (CmsException e) { // there might exist export points without corresponding resources in the VFS // -> ignore exceptions which are not "resource not found" exception quiet here if (e instanceof CmsVfsResourceNotFoundException) { if (LOG.isErrorEnabled()) { LOG.error(Messages.get().getBundle().key(Messages.LOG_UPDATE_EXORT_POINTS_ERROR_0), e); } } } } } catch (Exception e) { if (LOG.isErrorEnabled()) { LOG.error(Messages.get().getBundle().key(Messages.LOG_UPDATE_EXORT_POINTS_ERROR_0), e); } } } /** * Updates the last login date on the given user to the current time.

* * @param dbc the current database context * @param user the user to be updated * * @throws CmsException if operation was not successful */ public void updateLastLoginDate(CmsDbContext dbc, CmsUser user) throws CmsException { m_monitor.clearUserCache(user); // set the last login time to the current time user.setLastlogin(System.currentTimeMillis()); dbc.setAttribute(ATTRIBUTE_LOGIN, user.getName()); getUserDriver(dbc).writeUser(dbc, user); // update cache m_monitor.cacheUser(user); // invalidate all user dependent caches m_monitor.flushCache( CmsMemoryMonitor.CacheType.ACL, CmsMemoryMonitor.CacheType.GROUP, CmsMemoryMonitor.CacheType.ORG_UNIT, CmsMemoryMonitor.CacheType.USER_LIST, CmsMemoryMonitor.CacheType.PERMISSION, CmsMemoryMonitor.CacheType.RESOURCE_LIST); // fire user modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); eventData.put(I_CmsEventListener.KEY_USER_NAME, user.getName()); eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_WRITE_USER); eventData.put(I_CmsEventListener.KEY_USER_CHANGES, Integer.valueOf(CmsUser.FLAG_LAST_LOGIN)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); } /** * Logs everything that has not been written to DB jet.

* * @param dbc the current db context * * @throws CmsDataAccessException if something goes wrong */ public void updateLog(CmsDbContext dbc) throws CmsDataAccessException { synchronized (m_publishListUpdateLock) { if (m_log.isEmpty()) { return; } List log = new ArrayList(m_log); m_log.clear(); String logTableEnabledStr = (String)OpenCms.getRuntimeProperty(PARAM_LOG_TABLE_ENABLED); if (Boolean.parseBoolean(logTableEnabledStr)) { // defaults to 'false' if value not set m_projectDriver.log(dbc, log); } A_CmsLogPublishListConverter converter = null; switch (OpenCms.getPublishManager().getPublishListRemoveMode()) { case currentUser: converter = new CmsLogPublishListConverterCurrentUser(); break; case allUsers: default: converter = new CmsLogPublishListConverterAllUsers(); break; } for (CmsLogEntry entry : log) { converter.add(entry); } converter.writeChangesToDatabase(dbc, m_projectDriver); } } /** * Updates/Creates the given relations for the given resource.

* * @param dbc the db context * @param resource the resource to update the relations for * @param links the links to consider for updating * @param updateSiblingState if true, sets the state of siblings whose relations have changed to 'changed' (unless they are new or deleted) * * @throws CmsException if something goes wrong * * @see CmsSecurityManager#updateRelationsForResource(CmsRequestContext, CmsResource, List) */ public void updateRelationsForResource( CmsDbContext dbc, CmsResource resource, List links, boolean updateSiblingState) throws CmsException { if (links == null) { links = new ArrayList<>(); } // create new relation information I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); Iterator itLinks = links.iterator(); Set relationsForOriginalResource = new HashSet<>(); while (itLinks.hasNext()) { CmsLink link = itLinks.next(); if (link.isInternal()) { // only update internal links if (CmsStringUtil.isEmptyOrWhitespaceOnly(link.getTarget())) { // only an anchor continue; } CmsUUID targetId = link.getStructureId(); String destPath = link.getTarget(); if (targetId != null) { // the link target may not be a VFS path even if the link id is a structure id, // so if possible, we read the resource for the id and set the relation target to its // real root path. try { CmsResource destRes = readResource(dbc, targetId, CmsResourceFilter.ALL); destPath = destRes.getRootPath(); } catch (CmsVfsResourceNotFoundException e) { // ignore } } CmsRelation originalRelation = new CmsRelation( resource.getStructureId(), resource.getRootPath(), link.getStructureId(), destPath, link.getType()); relationsForOriginalResource.add(originalRelation); } } List siblings = resource.getSiblingCount() == 1 ? Arrays.asList(resource) : readSiblings(dbc, resource, CmsResourceFilter.ALL); for (CmsResource sibling : siblings) { // For each sibling, we determine which 'defined in content' relations it SHOULD have, // and only update the relations if that set differs from the ones it actually has. // If the updateSiblingState flag is set, then for siblings, we update the structure // state to changed (unless the state was 'deleted' or 'new'). // This is so that even if the user later publishes only one sibling, the other sibling will still // show up as changed in the GUI, so the user can publish it separately (with its updated relations). Set relationsForSibling = relationsForOriginalResource.stream().map( relation -> new CmsRelation( sibling.getStructureId(), sibling.getRootPath(), relation.getTargetId(), relation.getTargetPath(), relation.getType())).collect(Collectors.toSet()); Set existingRelations = new HashSet<>( vfsDriver.readRelations( dbc, dbc.currentProject().getUuid(), sibling, CmsRelationFilter.TARGETS.filterDefinedInContent())); if (!existingRelations.equals(relationsForSibling)) { vfsDriver.deleteRelations( dbc, dbc.currentProject().getUuid(), sibling, CmsRelationFilter.TARGETS.filterDefinedInContent()); for (CmsRelation relation : relationsForSibling) { vfsDriver.createRelation(dbc, dbc.currentProject().getUuid(), relation); } if (!sibling.getState().isDeleted() && !sibling.getState().isNew() && (siblings.size() > 1) && updateSiblingState) { sibling.setState(CmsResource.STATE_CHANGED); vfsDriver.writeResourceState( dbc, dbc.currentProject(), sibling, CmsDriverManager.UPDATE_STRUCTURE_STATE, false); } } } } /** * Returns true if a user is member of the given group.

* * @param dbc the current database context * @param username the name of the user to check * @param groupname the name of the group to check * @param readRoles if to read roles or groups * * @return true, if the user is in the group, false otherwise * * @throws CmsException if something goes wrong */ public boolean userInGroup(CmsDbContext dbc, String username, String groupname, boolean readRoles) throws CmsException { List groups = getGroupsOfUser(dbc, username, readRoles); for (int i = 0; i < groups.size(); i++) { CmsGroup group = groups.get(i); if (groupname.equals(group.getName()) || groupname.substring(1).equals(group.getName())) { return true; } } return false; } /** * This method checks if a new password follows the rules for * new passwords, which are defined by a Class implementing the * {@link org.opencms.security.I_CmsPasswordHandler} * interface and configured in the opencms.properties file.

* * If this method throws no exception the password is valid.

* * @param password the new password that has to be checked * * @throws CmsSecurityException if the password is not valid */ public void validatePassword(String password) throws CmsSecurityException { OpenCms.getPasswordHandler().validatePassword(password); } /** * Validates the relations for the given resources.

* * @param dbc the database context * @param publishList the resources to validate during publishing * @param report a report to write the messages to * * @return a map with lists of invalid links * ({@link org.opencms.relations.CmsRelation}} objects) * keyed by root paths * * @throws Exception if something goes wrong */ public Map> validateRelations( CmsDbContext dbc, CmsPublishList publishList, I_CmsReport report) throws Exception { return m_htmlLinkValidator.validateResources(dbc, publishList, report); } /** * Writes an access control entries to a given resource.

* * @param dbc the current database context * @param resource the resource * @param ace the entry to write * * @throws CmsException if something goes wrong */ public void writeAccessControlEntry(CmsDbContext dbc, CmsResource resource, CmsAccessControlEntry ace) throws CmsException { // write the new ace getUserDriver(dbc).writeAccessControlEntry(dbc, dbc.currentProject(), ace); // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_PERMISSIONS, new String[] {resource.getRootPath()}), false); // update the "last modified" information setDateLastModified(dbc, resource, resource.getDateLastModified()); // clear the cache m_monitor.clearAccessControlListCache(); // fire a resource modification event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_ACCESSCONTROL)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Writes all export points into the file system for the publish task * specified by trhe given publish history ID.

* * @param dbc the current database context * @param report an I_CmsReport instance to print output message, or null to write messages to the log file * @param publishHistoryId ID to identify the publish task in the publish history */ public void writeExportPoints(CmsDbContext dbc, I_CmsReport report, CmsUUID publishHistoryId) { boolean printReportHeaders = false; List publishedResources = null; try { // read the "published resources" for the specified publish history ID publishedResources = getProjectDriver(dbc).readPublishedResources(dbc, publishHistoryId); } catch (CmsException e) { if (LOG.isErrorEnabled()) { LOG.error( Messages.get().getBundle().key(Messages.ERR_READ_PUBLISHED_RESOURCES_FOR_ID_1, publishHistoryId), e); } } if ((publishedResources == null) || publishedResources.isEmpty()) { if (LOG.isWarnEnabled()) { LOG.warn(Messages.get().getBundle().key(Messages.LOG_EMPTY_PUBLISH_HISTORY_1, publishHistoryId)); } return; } // read the export points and return immediately if there are no export points at all Set exportPoints = new HashSet(); exportPoints.addAll(OpenCms.getExportPoints()); exportPoints.addAll(OpenCms.getModuleManager().getExportPoints()); if (exportPoints.size() == 0) { if (LOG.isWarnEnabled()) { LOG.warn(Messages.get().getBundle().key(Messages.LOG_NO_EXPORT_POINTS_CONFIGURED_0)); } return; } // create the driver to write the export points I_CmsExportPointDriver exportPointDriver = OpenCms.getImportExportManager().createExportPointDriver( exportPoints); // the report may be null if the export point write was started by an event if (report == null) { if (dbc.getRequestContext() != null) { report = new CmsLogReport(dbc.getRequestContext().getLocale(), getClass()); } else { report = new CmsLogReport(CmsLocaleManager.getDefaultLocale(), getClass()); } } // iterate over all published resources to export them I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); Iterator i = publishedResources.iterator(); while (i.hasNext()) { CmsPublishedResource currentPublishedResource = i.next(); String currentExportPoint = exportPointDriver.getExportPoint(currentPublishedResource.getRootPath()); if (currentExportPoint != null) { if (!printReportHeaders) { report.println( Messages.get().container(Messages.RPT_EXPORT_POINTS_WRITE_BEGIN_0), I_CmsReport.FORMAT_HEADLINE); printReportHeaders = true; } // print report message if (currentPublishedResource.getState().isDeleted()) { report.print( Messages.get().container(Messages.RPT_EXPORT_POINTS_DELETE_0), I_CmsReport.FORMAT_NOTE); } else { report.print(Messages.get().container(Messages.RPT_EXPORT_POINTS_WRITE_0), I_CmsReport.FORMAT_NOTE); } report.print( org.opencms.report.Messages.get().container( org.opencms.report.Messages.RPT_ARGUMENT_1, currentPublishedResource.getRootPath())); report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); if (currentPublishedResource.isFolder()) { // export the folder if (currentPublishedResource.getState().isDeleted()) { exportPointDriver.deleteResource(currentPublishedResource.getRootPath(), currentExportPoint); } else { exportPointDriver.createFolder(currentPublishedResource.getRootPath(), currentExportPoint); } report.println( org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), I_CmsReport.FORMAT_OK); } else { // export the file try { if (currentPublishedResource.getState().isDeleted()) { exportPointDriver.deleteResource( currentPublishedResource.getRootPath(), currentExportPoint); } else { // read the file content online byte[] onlineContent = vfsDriver.readContent( dbc, CmsProject.ONLINE_PROJECT_ID, currentPublishedResource.getResourceId()); exportPointDriver.writeFile( currentPublishedResource.getRootPath(), currentExportPoint, onlineContent); } report.println( org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), I_CmsReport.FORMAT_OK); } catch (CmsException e) { if (LOG.isErrorEnabled()) { LOG.error( Messages.get().getBundle().key( Messages.LOG_WRITE_EXPORT_POINT_ERROR_1, currentPublishedResource.getRootPath()), e); } report.println( org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_FAILED_0), I_CmsReport.FORMAT_ERROR); } } } } if (printReportHeaders) { report.println( Messages.get().container(Messages.RPT_EXPORT_POINTS_WRITE_END_0), I_CmsReport.FORMAT_HEADLINE); } } /** * Writes a resource to the OpenCms VFS, including it's content.

* * Applies only to resources of type {@link CmsFile} * i.e. resources that have a binary content attached.

* * Certain resource types might apply content validation or transformation rules * before the resource is actually written to the VFS. The returned result * might therefore be a modified version from the provided original.

* * @param dbc the current database context * @param resource the resource to apply this operation to * * @return the written resource (may have been modified) * * @throws CmsException if something goes wrong * * @see CmsObject#writeFile(CmsFile) * @see I_CmsResourceType#writeFile(CmsObject, CmsSecurityManager, CmsFile) */ public CmsFile writeFile(CmsDbContext dbc, CmsFile resource) throws CmsException { resource.setUserLastModified(dbc.currentUser().getId()); resource.setContents(resource.getContents()); // to be sure the content date is updated getVfsDriver(dbc).writeResource(dbc, dbc.currentProject().getUuid(), resource, UPDATE_RESOURCE_STATE); byte[] contents = resource.getContents(); getVfsDriver(dbc).writeContent(dbc, resource.getResourceId(), contents); // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_CONTENT_MODIFIED, new String[] {resource.getRootPath()}), false); // read the file back from db resource = new CmsFile(readResource(dbc, resource.getStructureId(), CmsResourceFilter.ALL)); resource.setContents(contents); deleteRelationsWithSiblings(dbc, resource); // update the cache m_monitor.clearResourceCache(); Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_CONTENT)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); return resource; } /** * Writes an already existing group.

* * The group id has to be a valid OpenCms group id.
* * The group with the given id will be completely overridden * by the given data.

* * @param dbc the current database context * @param group the group that should be written * * @throws CmsException if operation was not successful */ public void writeGroup(CmsDbContext dbc, CmsGroup group) throws CmsException { CmsGroup oldGroup = readGroup(dbc, group.getName()); m_monitor.uncacheGroup(oldGroup); getUserDriver(dbc).writeGroup(dbc, group); m_monitor.cacheGroup(group); if (!dbc.getProjectId().isNullUUID()) { // group modified event is not needed return; } // fire group modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_GROUP_ID, group.getId().toString()); eventData.put(I_CmsEventListener.KEY_GROUP_NAME, oldGroup.getName()); eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_GROUP_MODIFIED_ACTION_WRITE); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_GROUP_MODIFIED, eventData)); } /** * Creates an historical entry of the current project.

* * @param dbc the current database context * @param publishTag the version * @param publishDate the date of publishing * * @throws CmsDataAccessException if operation was not successful */ public void writeHistoryProject(CmsDbContext dbc, int publishTag, long publishDate) throws CmsDataAccessException { getHistoryDriver(dbc).writeProject(dbc, publishTag, publishDate); } /** * Writes the locks that are currently stored in-memory to the database to allow restoring them * in future server startups.

* * This overwrites the locks previously stored in the underlying database table.

* * @param dbc the current database context * * @throws CmsException if something goes wrong */ public void writeLocks(CmsDbContext dbc) throws CmsException { m_lockManager.writeLocks(dbc); } /** * Writes an already existing organizational unit.

* * The organizational unit id has to be a valid OpenCms organizational unit id.
* * The organizational unit with the given id will be completely overridden * by the given data.

* * @param dbc the current db context * @param organizationalUnit the organizational unit that should be written * * @throws CmsException if operation was not successful * * @see org.opencms.security.CmsOrgUnitManager#writeOrganizationalUnit(CmsObject, CmsOrganizationalUnit) */ public void writeOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit organizationalUnit) throws CmsException { m_monitor.uncacheOrgUnit(organizationalUnit); getUserDriver(dbc).writeOrganizationalUnit(dbc, organizationalUnit); // create a publish list for the 'virtual' publish event CmsResource ouRes = readResource(dbc, organizationalUnit.getId(), CmsResourceFilter.DEFAULT); CmsPublishList pl = new CmsPublishList(ouRes, false); pl.add(ouRes, false); getProjectDriver(dbc).writePublishHistory( dbc, pl.getPublishHistoryId(), new CmsPublishedResource(ouRes, -1, CmsResourceState.STATE_NEW)); // fire the 'virtual' publish event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_PUBLISHID, pl.getPublishHistoryId().toString()); eventData.put(I_CmsEventListener.KEY_PROJECTID, dbc.currentProject().getUuid()); eventData.put(I_CmsEventListener.KEY_DBCONTEXT, dbc); CmsEvent afterPublishEvent = new CmsEvent(I_CmsEventListener.EVENT_PUBLISH_PROJECT, eventData); OpenCms.fireCmsEvent(afterPublishEvent); m_monitor.cacheOrgUnit(organizationalUnit); } /** * Writes an already existing project.

* * The project id has to be a valid OpenCms project id.
* * The project with the given id will be completely overridden * by the given data.

* * @param dbc the current database context * @param project the project that should be written * * @throws CmsException if operation was not successful */ public void writeProject(CmsDbContext dbc, CmsProject project) throws CmsException { m_monitor.uncacheProject(project); getProjectDriver(dbc).writeProject(dbc, project); m_monitor.cacheProject(project); } /** * Writes a new project into the PROJECT_LASTMODIFIED field of a resource record.

* * @param dbc the current database context * @param resource the resource which should be modified * @param projectId the project id to write * * @throws CmsDataAccessException if the database access fails */ public void writeProjectLastModified(CmsDbContext dbc, CmsResource resource, CmsUUID projectId) throws CmsDataAccessException { I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); vfsDriver.writeLastModifiedProjectId(dbc, dbc.currentProject(), projectId, resource); } /** * Writes a property for a specified resource.

* * @param dbc the current database context * @param resource the resource to write the property for * @param property the property to write * * @throws CmsException if something goes wrong * * @see CmsObject#writePropertyObject(String, CmsProperty) * @see I_CmsResourceType#writePropertyObject(CmsObject, CmsSecurityManager, CmsResource, CmsProperty) */ public void writePropertyObject(CmsDbContext dbc, CmsResource resource, CmsProperty property) throws CmsException { try { if (property == CmsProperty.getNullProperty()) { // skip empty or null properties return; } // test if and what state should be updated // 0: none, 1: structure, 2: resource int updateState = getUpdateState(dbc, resource, Collections.singletonList(property)); // write the property getVfsDriver(dbc).writePropertyObject(dbc, dbc.currentProject(), resource, property); if (updateState > 0) { updateState(dbc, resource, updateState == 2); } // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_PROPERTIES, new String[] {resource.getRootPath()}), false); } finally { // update the driver manager cache m_monitor.clearResourceCache(); m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); // fire an event that a property of a resource has been modified Map data = new HashMap(); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put("property", property); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_PROPERTY_MODIFIED, data)); } } /** * Writes a list of properties for a specified resource.

* * Code calling this method has to ensure that the no properties * a, b are contained in the specified list so that a.equals(b), * otherwise an exception is thrown.

* * @param dbc the current database context * @param resource the resource to write the properties for * @param properties the list of properties to write * @param updateState if true the state of the resource will be updated * * @throws CmsException if something goes wrong * * @see CmsObject#writePropertyObjects(String, List) * @see I_CmsResourceType#writePropertyObjects(CmsObject, CmsSecurityManager, CmsResource, List) */ public void writePropertyObjects( CmsDbContext dbc, CmsResource resource, List properties, boolean updateState) throws CmsException { if ((properties == null) || (properties.size() == 0)) { // skip empty or null lists return; } try { // the specified list must not contain two or more equal property objects for (int i = 0, n = properties.size(); i < n; i++) { Set keyValidationSet = new HashSet(); CmsProperty property = properties.get(i); if (!keyValidationSet.contains(property.getName())) { keyValidationSet.add(property.getName()); } else { throw new CmsVfsException( Messages.get().container(Messages.ERR_VFS_INVALID_PROPERTY_LIST_1, property.getName())); } } // test if and what state should be updated // 0: none, 1: structure, 2: resource int updateStateValue = 0; if (updateState) { updateStateValue = getUpdateState(dbc, resource, properties); } I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); for (int i = 0; i < properties.size(); i++) { // write the property CmsProperty property = properties.get(i); vfsDriver.writePropertyObject(dbc, dbc.currentProject(), resource, property); } if (updateStateValue > 0) { // update state updateState(dbc, resource, (updateStateValue == 2)); } if (updateState) { // log it log( dbc, new CmsLogEntry( dbc, resource.getStructureId(), CmsLogEntryType.RESOURCE_PROPERTIES, new String[] {resource.getRootPath()}), false); } } finally { // update the driver manager cache m_monitor.clearResourceCache(); m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); // fire an event that the properties of a resource have been modified OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCE, resource))); } } /** * Updates a publish job.

* * @param dbc the current database context * @param publishJob the publish job to update * * @throws CmsException if something goes wrong */ public void writePublishJob(CmsDbContext dbc, CmsPublishJobInfoBean publishJob) throws CmsException { getProjectDriver(dbc).writePublishJob(dbc, publishJob); } /** * Writes the publish report for a publish job.

* * @param dbc the current database context * @param publishJob the publish job * @throws CmsException if something goes wrong */ public void writePublishReport(CmsDbContext dbc, CmsPublishJobInfoBean publishJob) throws CmsException { CmsPublishReport report = (CmsPublishReport)publishJob.removePublishReport(); if (report != null) { getProjectDriver(dbc).writePublishReport(dbc, publishJob.getPublishHistoryId(), report.getContents()); } } /** * Writes a resource to the OpenCms VFS.

* * @param dbc the current database context * @param resource the resource to write * * @throws CmsException if something goes wrong */ public void writeResource(CmsDbContext dbc, CmsResource resource) throws CmsException { // access was granted - write the resource resource.setUserLastModified(dbc.currentUser().getId()); CmsUUID projectId = ((dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) ? dbc.currentProject().getUuid() : dbc.getProjectId(); getVfsDriver(dbc).writeResource(dbc, projectId, resource, UPDATE_RESOURCE_STATE); // make sure the written resource has the state correctly set if (resource.getState().isUnchanged()) { resource.setState(CmsResource.STATE_CHANGED); } // delete in content relations if the new type is not parseable if (!(OpenCms.getResourceManager().getResourceType(resource.getTypeId()) instanceof I_CmsLinkParseable)) { deleteRelationsWithSiblings(dbc, resource); } // update the cache m_monitor.clearResourceCache(); Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CHANGED_RESOURCE)); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } /** * Inserts an entry in the published resource table.

* * This is done during static export.

* * @param dbc the current database context * @param resourceName The name of the resource to be added to the static export * @param linkType the type of resource exported (0= non-parameter, 1=parameter) * @param linkParameter the parameters added to the resource * @param timestamp a time stamp for writing the data into the db * * @throws CmsException if something goes wrong */ public void writeStaticExportPublishedResource( CmsDbContext dbc, String resourceName, int linkType, String linkParameter, long timestamp) throws CmsException { getProjectDriver(dbc).writeStaticExportPublishedResource(dbc, resourceName, linkType, linkParameter, timestamp); } /** * Adds a new url name mapping for a structure id.

* * Instead of taking the name directly, this method takes an iterator of strings * which generates candidate URL names on-the-fly. The first generated name which is * not already mapped to another structure id will be chosen for the new URL name mapping. * * @param dbc the current database context * @param nameSeq the sequence of URL name candidates * @param structureId the structure id to which the url name should be mapped * @param locale the locale for which the mapping should be written * @param replaceOnPublish name mappings for which this is set will replace all other mappings for the same resource on publishing * * @return the actual name which was mapped to the structure id * * @throws CmsDataAccessException if something goes wrong */ public String writeUrlNameMapping( CmsDbContext dbc, Iterator nameSeq, CmsUUID structureId, String locale, boolean replaceOnPublish) throws CmsDataAccessException { String bestName = findBestNameForUrlNameMapping(dbc, nameSeq, structureId, locale); addOrReplaceUrlNameMapping(dbc, bestName, structureId, locale, replaceOnPublish); return bestName; } /** * Updates the user information.

* * The user id has to be a valid OpenCms user id.
* * The user with the given id will be completely overridden * by the given data.

* * @param dbc the current database context * @param user the user to be updated * * @throws CmsException if operation was not successful */ public void writeUser(CmsDbContext dbc, CmsUser user) throws CmsException { CmsUser oldUser = readUser(dbc, user.getId()); m_monitor.clearUserCache(oldUser); getUserDriver(dbc).writeUser(dbc, user); m_monitor.flushCache(CmsMemoryMonitor.CacheType.USER_LIST); if (!dbc.getProjectId().isNullUUID()) { // user modified event is not needed return; } // fire user modified event Map eventData = new HashMap(); eventData.put(I_CmsEventListener.KEY_USER_ID, user.getId().toString()); eventData.put(I_CmsEventListener.KEY_USER_NAME, oldUser.getName()); eventData.put(I_CmsEventListener.KEY_USER_ACTION, I_CmsEventListener.VALUE_USER_MODIFIED_ACTION_WRITE_USER); eventData.put(I_CmsEventListener.KEY_USER_CHANGES, Integer.valueOf(user.getChanges(oldUser))); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_USER_MODIFIED, eventData)); OpenCms.getTwoFactorAuthenticationHandler().trackUserChange(dbc.getRequestContext(), oldUser, user); } /** * Adds or replaces a new url name mapping in the offline project.

* * @param dbc the current database context * @param name the URL name of the mapping * @param structureId the structure id of the mapping * @param locale the locale of the mapping * @param replaceOnPublish if the mapping shoudl replace previous URL name mappings when published * * @throws CmsDataAccessException if something goes wrong */ protected void addOrReplaceUrlNameMapping( CmsDbContext dbc, String name, CmsUUID structureId, String locale, boolean replaceOnPublish) throws CmsDataAccessException { getVfsDriver(dbc).deleteUrlNameMappingEntries( dbc, false, CmsUrlNameMappingFilter.ALL.filterStructureId(structureId).filterLocale(locale).filterStates( CmsUrlNameMappingEntry.MAPPING_STATUS_NEW, CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH)); CmsUrlNameMappingEntry newEntry = new CmsUrlNameMappingEntry( name, structureId, replaceOnPublish ? CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH : CmsUrlNameMappingEntry.MAPPING_STATUS_NEW, System.currentTimeMillis(), locale); getVfsDriver(dbc).addUrlNameMappingEntry(dbc, false, newEntry); } /** * Converts a resource to a folder (if possible).

* * @param resource the resource to convert * @return the converted resource * * @throws CmsVfsResourceNotFoundException if the resource is not a folder */ protected CmsFolder convertResourceToFolder(CmsResource resource) throws CmsVfsResourceNotFoundException { if (resource.isFolder()) { return new CmsFolder(resource); } throw new CmsVfsResourceNotFoundException( Messages.get().container(Messages.ERR_ACCESS_FILE_AS_FOLDER_1, resource.getRootPath())); } /** * Helper method for creating a driver from configuration data.

* * @param dbc the db context * @param configManager the configuration manager * @param config the configuration * @param driverChainKey the configuration key under which the driver chain is stored * @param suffix the suffix to append to a driver chain entry to get the key for the driver class * * @return the newly created driver */ protected Object createDriver( CmsDbContext dbc, CmsConfigurationManager configManager, CmsParameterConfiguration config, String driverChainKey, String suffix) { // read the vfs driver class properties and initialize a new instance List drivers = config.getList(driverChainKey); String driverKey = drivers.get(0) + suffix; String driverName = config.get(driverKey); drivers = (drivers.size() > 1) ? drivers.subList(1, drivers.size()) : null; if (driverName == null) { CmsLog.INIT.error(Messages.get().getBundle().key(Messages.INIT_DRIVER_FAILED_1, driverKey)); } Object result = newDriverInstance(dbc, configManager, driverName, drivers); if ("true".equalsIgnoreCase(System.getProperty("opencms.profile.drivers"))) { result = wrapDriverInProfilingProxy(result); } return result; } /** * Deletes all relations for the given resource and all its siblings.

* * @param dbc the current database context * @param resource the resource to delete the resource for * * @throws CmsException if something goes wrong */ protected void deleteRelationsWithSiblings(CmsDbContext dbc, CmsResource resource) throws CmsException { // get all siblings List siblings; if (resource.getSiblingCount() > 1) { siblings = readSiblings(dbc, resource, CmsResourceFilter.ALL); } else { siblings = new ArrayList(); siblings.add(resource); } // clean the relations in content for all siblings I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); Iterator it = siblings.iterator(); while (it.hasNext()) { CmsResource sibling = it.next(); // clean the relation information for this sibling vfsDriver.deleteRelations( dbc, dbc.currentProject().getUuid(), sibling, CmsRelationFilter.TARGETS.filterDefinedInContent()); } } /** * Tries to add sub-resources of moved folders to the publish list and throws an exception if the publish list still does * not contain some sub-resources of the moved folders.

* * @param cms the current CMS context * @param dbc the current database context * @param pubList the publish list * @throws CmsException if something goes wrong */ protected void ensureSubResourcesOfMovedFoldersPublished(CmsObject cms, CmsDbContext dbc, CmsPublishList pubList) throws CmsException { List topMovedFolders = pubList.getTopMovedFolders(cms); Iterator folderIt = topMovedFolders.iterator(); while (folderIt.hasNext()) { CmsResource folder = folderIt.next(); addSubResources(dbc, pubList, folder, resource -> !resource.getState().isNew()); } List missingSubResources = pubList.getMissingSubResources(cms, topMovedFolders); if (missingSubResources.isEmpty()) { return; } StringBuffer pathBuffer = new StringBuffer(); for (CmsResource missing : missingSubResources) { pathBuffer.append(missing.getRootPath()); pathBuffer.append(" "); } throw new CmsVfsException( Messages.get().container(Messages.RPT_CHILDREN_OF_MOVED_FOLDER_NOT_PUBLISHED_1, pathBuffer.toString())); } /** * Tries to find the best name for an URL name mapping for the given structure id.

* * @param dbc the database context * @param nameSeq the sequence of name candidates * @param structureId the structure id to which an URL name should be mapped * @param locale the locale for which the URL name should be mapped * * @return the selected URL name candidate * * @throws CmsDataAccessException if something goes wrong */ protected String findBestNameForUrlNameMapping( CmsDbContext dbc, Iterator nameSeq, CmsUUID structureId, String locale) throws CmsDataAccessException { String newName; boolean alreadyInUse; do { newName = nameSeq.next(); alreadyInUse = false; CmsUrlNameMappingFilter filter = CmsUrlNameMappingFilter.ALL.filterName(newName); List entriesWithSameName = getVfsDriver(dbc).readUrlNameMappingEntries( dbc, false, filter); for (CmsUrlNameMappingEntry entry : entriesWithSameName) { boolean sameId = entry.getStructureId().equals(structureId); if (!sameId) { // name already used for other resource, or for different locale of the same resource alreadyInUse = true; break; } } } while (alreadyInUse); return newName; } /** * Helper method for finding the 'best' URL name to use for a new URL name mapping.

* * Since the name given as a parameter may be already used, this method will try to append numeric suffixes * to the name to find a mapping name which is not used.

* * @param dbc the current database context * @param name the name of the mapping * @param structureId the structure id to which the name is mapped * * @return the best name which was found for the new mapping * * @throws CmsDataAccessException if something goes wrong */ protected String findBestNameForUrlNameMapping(CmsDbContext dbc, String name, CmsUUID structureId) throws CmsDataAccessException { List entriesStartingWithName = getVfsDriver(dbc).readUrlNameMappingEntries( dbc, false, CmsUrlNameMappingFilter.ALL.filterNamePattern(name + "%").filterRejectStructureId(structureId)); Set usedNames = new HashSet(); for (CmsUrlNameMappingEntry entry : entriesStartingWithName) { usedNames.add(entry.getName()); } int counter = 0; String numberedName; do { numberedName = getNumberedName(name, counter); counter += 1; } while (usedNames.contains(numberedName)); return numberedName; } /** * Returns the lock manager instance.

* * @return the lock manager instance */ protected CmsLockManager getLockManager() { return m_lockManager; } /** * Adds a numeric suffix to the end of a string, unless the number passed as a parameter is 0.

* * @param name the base name * @param number the number from which to form the suffix * * @return the concatenation of the base name and possibly the numeric suffix */ protected String getNumberedName(String name, int number) { if (number == 0) { return name; } PrintfFormat fmt = new PrintfFormat("%0.6d"); return name + "_" + fmt.sprintf(number); } /** * Resets the resources in a project to their online state.

* * @param dbc the database context * @param projectId the project id * @param modifiedFiles the modified files * @param modifiedFolders the modified folders * @throws CmsException if something goes wrong * @throws CmsSecurityException if we don't have the permissions * @throws CmsDataAccessException if something goes wrong with the database */ protected void resetResourcesInProject( CmsDbContext dbc, CmsUUID projectId, List modifiedFiles, List modifiedFolders) throws CmsException, CmsSecurityException, CmsDataAccessException { // all resources inside the project have to be be reset to their online state. // 1. step: delete all new files for (int i = 0; i < modifiedFiles.size(); i++) { CmsResource currentFile = modifiedFiles.get(i); if (currentFile.getState().isNew()) { CmsLock lock = getLock(dbc, currentFile); if (lock.isNullLock()) { // lock the resource lockResource(dbc, currentFile, CmsLockType.EXCLUSIVE); } else if (!lock.isOwnedBy(dbc.currentUser()) || !lock.isInProject(dbc.currentProject())) { changeLock(dbc, currentFile, CmsLockType.EXCLUSIVE); } // delete the properties getVfsDriver(dbc).deletePropertyObjects( dbc, projectId, currentFile, CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES); // delete the file getVfsDriver(dbc).removeFile(dbc, dbc.currentProject().getUuid(), currentFile); // remove the access control entries getUserDriver(dbc).removeAccessControlEntries(dbc, dbc.currentProject(), currentFile.getResourceId()); // fire the corresponding event OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCE, currentFile))); } } // 2. step: delete all new folders for (int i = 0; i < modifiedFolders.size(); i++) { CmsResource currentFolder = modifiedFolders.get(i); if (currentFolder.getState().isNew()) { // delete the properties getVfsDriver(dbc).deletePropertyObjects( dbc, projectId, currentFolder, CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES); // delete the folder getVfsDriver(dbc).removeFolder(dbc, dbc.currentProject(), currentFolder); // remove the access control entries getUserDriver(dbc).removeAccessControlEntries(dbc, dbc.currentProject(), currentFolder.getResourceId()); // fire the corresponding event OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCE, currentFolder))); } } // 3. step: undo changes on all changed or deleted folders for (int i = 0; i < modifiedFolders.size(); i++) { CmsResource currentFolder = modifiedFolders.get(i); if ((currentFolder.getState().isChanged()) || (currentFolder.getState().isDeleted())) { CmsLock lock = getLock(dbc, currentFolder); if (lock.isNullLock()) { // lock the resource lockResource(dbc, currentFolder, CmsLockType.EXCLUSIVE); } else if (!lock.isOwnedBy(dbc.currentUser()) || !lock.isInProject(dbc.currentProject())) { changeLock(dbc, currentFolder, CmsLockType.EXCLUSIVE); } // undo all changes in the folder undoChanges(dbc, currentFolder, CmsResource.UNDO_CONTENT); // fire the corresponding event OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCE, currentFolder))); } } // 4. step: undo changes on all changed or deleted files for (int i = 0; i < modifiedFiles.size(); i++) { CmsResource currentFile = modifiedFiles.get(i); if (currentFile.getState().isChanged() || currentFile.getState().isDeleted()) { CmsLock lock = getLock(dbc, currentFile); if (lock.isNullLock()) { // lock the resource lockResource(dbc, currentFile, CmsLockType.EXCLUSIVE); } else if (!lock.isOwnedInProjectBy(dbc.currentUser(), dbc.currentProject())) { if (lock.isLockableBy(dbc.currentUser())) { changeLock(dbc, currentFile, CmsLockType.EXCLUSIVE); } } // undo all changes in the file undoChanges(dbc, currentFile, CmsResource.UNDO_CONTENT); // fire the corresponding event OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCE, currentFile))); } } } /** * Counts the total number of users which fit the given criteria.

* * @param dbc the database context * @param searchParams the user search criteria * * @return the total number of users matching the criteria * * @throws CmsDataAccessException if something goes wrong */ long countUsers(CmsDbContext dbc, CmsUserSearchParameters searchParams) throws CmsDataAccessException { return getUserDriver(dbc).countUsers(dbc, searchParams); } /** * Adds a pool to the static pool map.

* * @param pool the pool to add */ private void addPool(CmsDbPoolV11 pool) { m_pools.put(pool.getPoolUrl(), pool); } /** * Adds all sub-resources of the given resource to the publish list.

* * @param dbc the database context * @param publishList the publish list * @param directPublishResource the resource to get the sub-resources for * @param additionalFilter an additional test for resources to pass before they are added to the publish list * * @throws CmsDataAccessException if something goes wrong accessing the database */ private void addSubResources( CmsDbContext dbc, CmsPublishList publishList, CmsResource directPublishResource, Predicate additionalFilter) throws CmsDataAccessException { int flags = CmsDriverManager.READMODE_INCLUDE_TREE | CmsDriverManager.READMODE_EXCLUDE_STATE; if (!directPublishResource.getState().isDeleted()) { // fix for org.opencms.file.TestPublishIssues#testPublishFolderWithDeletedFileFromOtherProject flags = flags | CmsDriverManager.READMODE_INCLUDE_PROJECT; } // add all sub resources of the folder List folderList = getVfsDriver(dbc).readResourceTree( dbc, dbc.currentProject().getUuid(), directPublishResource.getRootPath(), CmsDriverManager.READ_IGNORE_TYPE, CmsResource.STATE_UNCHANGED, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, flags | CmsDriverManager.READMODE_ONLY_FOLDERS); publishList.addAll( filterResources(dbc, publishList, folderList).stream().filter(additionalFilter).collect( Collectors.toList()), true); List fileList = getVfsDriver(dbc).readResourceTree( dbc, dbc.currentProject().getUuid(), directPublishResource.getRootPath(), CmsDriverManager.READ_IGNORE_TYPE, CmsResource.STATE_UNCHANGED, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, CmsDriverManager.READ_IGNORE_TIME, flags | CmsDriverManager.READMODE_ONLY_FILES); publishList.addAll( filterResources(dbc, publishList, fileList).stream().filter(additionalFilter).collect(Collectors.toList()), true); } /** * Helper method to check whether we should bother with reading the group for a given role in a given OU.

* * 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. * * @param ou the OU * @param role the role * @return true if we should read the role in the OU */ private boolean canReadRoleInOu(CmsOrganizationalUnit ou, CmsRole role) { if (ou.hasFlagWebuser() && !role.getRoleName().equals(CmsRole.ACCOUNT_MANAGER.getRoleName())) { return false; } return true; } /** * Checks the parent of a resource during publishing.

* * @param dbc the current database context * @param deletedFolders a list of deleted folders * @param res a resource to check the parent for * * @return true if the parent resource will be deleted during publishing */ private boolean checkDeletedParentFolder(CmsDbContext dbc, List deletedFolders, CmsResource res) { String parentPath = CmsResource.getParentFolder(res.getRootPath()); if (parentPath == null) { // resource has no parent return false; } CmsResource parent; try { parent = readResource(dbc, parentPath, CmsResourceFilter.ALL); } catch (Exception e) { // failure: if we cannot read the parent, we should not publish the resource return false; } if (!parent.getState().isDeleted()) { // parent is not deleted return false; } for (int j = 0; j < deletedFolders.size(); j++) { if ((deletedFolders.get(j)).getStructureId().equals(parent.getStructureId())) { // parent is deleted, and it will get published return true; } } // parent is new, but it will not get published return false; } /** * Checks that no one of the resources to be published has a 'new' parent (that has not been published yet).

* * @param dbc the db context * @param publishList the publish list to check * * @throws CmsVfsException if there is a resource to be published with a 'new' parent */ private void checkParentFolders(CmsDbContext dbc, CmsPublishList publishList) throws CmsVfsException { boolean directPublish = publishList.isDirectPublish(); // if we direct publish a file, check if all parent folders are already published if (directPublish) { // first get the names of all parent folders Iterator it = publishList.getDirectPublishResources().iterator(); List parentFolderNames = new ArrayList(); while (it.hasNext()) { CmsResource res = it.next(); String parentFolderName = CmsResource.getParentFolder(res.getRootPath()); if (parentFolderName != null) { parentFolderNames.add(parentFolderName); } } // remove duplicate parent folder names parentFolderNames = CmsFileUtil.removeRedundancies(parentFolderNames); String parentFolderName = null; try { I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); // now check all folders if they exist in the online project Iterator parentIt = parentFolderNames.iterator(); while (parentIt.hasNext()) { parentFolderName = parentIt.next(); vfsDriver.readFolder(dbc, CmsProject.ONLINE_PROJECT_ID, parentFolderName); } } catch (CmsException e) { throw new CmsVfsException( Messages.get().container(Messages.RPT_PARENT_FOLDER_NOT_PUBLISHED_1, parentFolderName)); } } } /** * Checks the parent of a resource during publishing.

* * @param dbc the current database context * @param folderList a list of folders * @param res a resource to check the parent for * * @return true if the resource should be published */ private boolean checkParentResource(CmsDbContext dbc, List folderList, CmsResource res) { String parentPath = CmsResource.getParentFolder(res.getRootPath()); if (parentPath == null) { // resource has no parent return true; } CmsResource parent; try { parent = readResource(dbc, parentPath, CmsResourceFilter.ALL); } catch (Exception e) { // failure: if we cannot read the parent, we should not publish the resource return false; } if (!parent.getState().isNew()) { // parent is already published return true; } for (int j = 0; j < folderList.size(); j++) { if (folderList.get(j).getStructureId().equals(parent.getStructureId())) { // parent is new, but it will get published return true; } } // parent is new, but it will not get published return false; } /** * Copies all relations from the source resource to the target resource.

* * @param dbc the database context * @param source the source * @param target the target * * @throws CmsException if something goes wrong */ private void copyRelations(CmsDbContext dbc, CmsResource source, CmsResource target) throws CmsException { // copy relations all relations CmsObject cms = new CmsObject(getSecurityManager(), dbc.getRequestContext()); Iterator itRelations = getRelationsForResource( dbc, source, CmsRelationFilter.TARGETS.filterNotDefinedInContent()).iterator(); while (itRelations.hasNext()) { CmsRelation relation = itRelations.next(); if (relation.getType().getCopyBehavior() == CopyBehavior.copy) { try { CmsResource relTarget = relation.getTarget(cms, CmsResourceFilter.ALL); addRelationToResource(dbc, target, relTarget, relation.getType(), true); } catch (CmsVfsResourceNotFoundException e) { // ignore this broken relation if (LOG.isWarnEnabled()) { LOG.warn(e.getLocalizedMessage(), e); } } } } // repair categories repairCategories(dbc, getProjectIdForContext(dbc), target); } /** * Filters the given list of resources, removes all resources where the current user * does not have READ permissions, plus the filter is applied.

* * @param dbc the current database context * @param resourceList a list of CmsResources * @param filter the resource filter to use * * @return the filtered list of resources * * @throws CmsException in case errors testing the permissions */ private List filterPermissions( CmsDbContext dbc, List resourceList, CmsResourceFilter filter) throws CmsException { if (filter.requireTimerange()) { // never check time range here - this must be done later in #updateContextDates(...) filter = filter.addExcludeTimerange(); } ResourceListWithCacheability result = new ResourceListWithCacheability(); boolean nocacheWasSet = false; if (null == dbc.getAttribute(ATTR_PERMISSION_NOCACHE)) { // The attribute will be used by the permission handler to tell us that lists containing the resource // should not be cached. dbc.setAttribute(ATTR_PERMISSION_NOCACHE, new boolean[] {false}); // insurance against potential indirect recursive calls introduced by future code changes: // make sure we only remove the attribute later if we were the one who set it nocacheWasSet = true; } try { for (int i = 0; i < resourceList.size(); i++) { // check the permission of all resources CmsResource currentResource = resourceList.get(i); if (m_securityManager.hasPermissions( dbc, currentResource, CmsPermissionSet.ACCESS_READ, LockCheck.yes, filter).isAllowed()) { // only return resources where permission was granted result.add(currentResource); } } } finally { if (nocacheWasSet) { boolean[] nocache = (boolean[])dbc.getAttribute(ATTR_PERMISSION_NOCACHE); if (nocache != null) { dbc.removeAttribute(ATTR_PERMISSION_NOCACHE); if (nocache[0]) { result.setCacheable(false); } } } } // return the result return result; } /** * Returns a filtered list of resources for publishing.

* Contains all resources, which are not locked * and which have a parent folder that is already published or will be published, too.

* * @param dbc the current database context * @param publishList the filling publish list * @param resourceList the list of resources to filter * * @return a filtered list of resources */ private List filterResources( CmsDbContext dbc, CmsPublishList publishList, List resourceList) { List result = new ArrayList(); // local folder list for adding new publishing subfolders // this solves the {@link org.opencms.file.TestPublishIssues#testPublishScenarioD} problem. List newFolderList = new ArrayList( publishList == null ? resourceList : publishList.getFolderList()); for (int i = 0; i < resourceList.size(); i++) { CmsResource res = resourceList.get(i); try { CmsLock lock = getLock(dbc, res); if (lock.isPublish()) { // if already enqueued continue; } if (!lock.isLockableBy(dbc.currentUser())) { // checks if there is a shared lock and if the resource is deleted // this solves the {@link org.opencms.file.TestPublishIssues#testPublishScenarioE} problem. if (lock.isShared() && (publishList != null)) { if (!res.getState().isDeleted() || !checkDeletedParentFolder(dbc, publishList.getDeletedFolderList(), res)) { continue; } } else { // don't add locked resources continue; } } if (!"/".equals(res.getRootPath()) && !checkParentResource(dbc, newFolderList, res)) { continue; } // check permissions try { m_securityManager.checkPermissions( dbc, res, CmsPermissionSet.ACCESS_DIRECT_PUBLISH, false, CmsResourceFilter.ALL); } catch (CmsException e) { // skip if not enough permissions continue; } if (res.isFolder()) { newFolderList.add(res); } result.add(res); } catch (Exception e) { // should never happen LOG.error(e.getLocalizedMessage(), e); } } return result; } /** * Returns a filtered list of sibling resources for publishing.

* * Contains all siblings of the given resources, which are not locked * and which have a parent folder that is already published or will be published, too.

* * @param dbc the current database context * @param publishList the unfinished publish list * @param resourceList the list of siblings to filter * * @return a filtered list of sibling resources for publishing */ private List filterSiblings( CmsDbContext dbc, CmsPublishList publishList, Collection resourceList) { List result = new ArrayList(); // removed internal extendible folder list, since iterated (sibling) resources are files in any case, never folders for (CmsResource res : resourceList) { try { CmsLock lock = getLock(dbc, res); if (lock.isPublish()) { // if already enqueued continue; } if (!lock.isLockableBy(dbc.currentUser())) { // checks if there is a shared lock and if the resource is deleted // this solves the {@link org.opencms.file.TestPublishIssues#testPublishScenarioE} problem. if (lock.isShared() && (publishList != null)) { if (!res.getState().isDeleted() || !checkDeletedParentFolder(dbc, publishList.getDeletedFolderList(), res)) { continue; } } else { // don't add locked resources continue; } } if (!"/".equals(res.getRootPath()) && !checkParentResource(dbc, publishList.getFolderList(), res)) { // don't add resources that have no parent in the online project continue; } // check permissions try { m_securityManager.checkPermissions( dbc, res, CmsPermissionSet.ACCESS_DIRECT_PUBLISH, false, CmsResourceFilter.ALL); } catch (CmsException e) { // skip if not enough permissions continue; } result.add(res); } catch (Exception e) { // should never happen LOG.error(e.getLocalizedMessage(), e); } } return result; } /** * Returns the access control list of a given resource.

* * @param dbc the current database context * @param resource the resource * @param forFolder should be true if resource is a folder * @param depth the depth to include non-inherited access entries, also * @param inheritedOnly flag indicates to collect inherited permissions only * * @return the access control list of the resource * * @throws CmsException if something goes wrong */ private CmsAccessControlList getAccessControlList( CmsDbContext dbc, CmsResource resource, boolean inheritedOnly, boolean forFolder, int depth) throws CmsException { String cacheKey = getCacheKey( new String[] { inheritedOnly ? "+" : "-", forFolder ? "+" : "-", Integer.toString(depth), resource.getStructureId().toString()}, dbc); CmsAccessControlList acl = m_monitor.getCachedACL(cacheKey); // return the cached acl if already available if ((acl != null) && dbc.getProjectId().isNullUUID()) { return acl; } List aces = getUserDriver(dbc).readAccessControlEntries( dbc, dbc.currentProject(), resource.getResourceId(), (depth > 1) || ((depth > 0) && forFolder)); // sort the list of aces boolean overwriteAll = sortAceList(aces); // if no 'overwrite all' ace was found if (!overwriteAll) { // get the acl of the parent CmsResource parentResource = null; try { // try to recurse over the id parentResource = getVfsDriver(dbc).readParentFolder( dbc, dbc.currentProject().getUuid(), resource.getStructureId()); } catch (CmsVfsResourceNotFoundException e) { // should never happen, but try with the path String parentPath = CmsResource.getParentFolder(resource.getRootPath()); if (parentPath != null) { parentResource = getVfsDriver(dbc).readFolder(dbc, dbc.currentProject().getUuid(), parentPath); } } if (parentResource != null) { acl = (CmsAccessControlList)getAccessControlList( dbc, parentResource, inheritedOnly, forFolder, depth + 1).clone(); } } if (acl == null) { acl = new CmsAccessControlList(); } Set exclusiveAccessPrincipals = new HashSet<>(); if (!((depth == 0) && inheritedOnly)) { Iterator itAces = aces.iterator(); while (itAces.hasNext()) { CmsAccessControlEntry acEntry = itAces.next(); if (depth > 0) { acEntry.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_INHERITED); } if ((depth == 0) && resource.isFile() && (0 != (acEntry.getFlags() & CmsAccessControlEntry.ACCESS_FLAGS_RESPONSIBLE))) { // 'responsible' flag is only interpreted as exclusive access if it's not inherited and set directly on a file exclusiveAccessPrincipals.add(acEntry.getPrincipal()); } acl.add(acEntry); // if the overwrite flag is set, reset the allowed permissions to the permissions of this entry // denied permissions are kept or extended if ((acEntry.getFlags() & CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE) > 0) { acl.setAllowedPermissions(acEntry); } } } if (exclusiveAccessPrincipals.size() > 0) { acl.setExclusiveAccessPrincipals(exclusiveAccessPrincipals); } if (dbc.getProjectId().isNullUUID()) { m_monitor.cacheACL(cacheKey, acl); } return acl; } /** * Return a cache key build from the provided information.

* * @param prefix a prefix for the key * @param flag a boolean flag for the key (only used if prefix is not null) * @param projectId the project for which to generate the key * @param resource the resource for which to generate the key * * @return String a cache key build from the provided information */ private String getCacheKey(String prefix, boolean flag, CmsUUID projectId, String resource) { StringBuffer b = new StringBuffer(64); if (prefix != null) { b.append(prefix); b.append(flag ? '+' : '-'); } b.append(CmsProject.isOnlineProject(projectId) ? '+' : '-'); return b.append(resource).toString(); } /** * Return a cache key build from the provided information.

* * @param keys an array of keys to generate the cache key from * @param dbc the database context for which to generate the key * * @return String a cache key build from the provided information */ private String getCacheKey(String[] keys, CmsDbContext dbc) { if (!dbc.getProjectId().isNullUUID()) { return ""; } StringBuffer b = new StringBuffer(64); int len = keys.length; if (len > 0) { for (int i = 0; i < len; i++) { b.append(keys[i]); b.append('_'); } } if (dbc.currentProject().isOnlineProject()) { b.append("+"); } else { b.append("-"); } return b.toString(); } /** * Gets the correct driver interface to use for proxying a specific driver instance.

* * @param obj the driver instance * @return the interface to use for proxying */ private Class getDriverInterfaceForProxy(Object obj) { for (Class interfaceClass : new Class[] { I_CmsUserDriver.class, I_CmsVfsDriver.class, I_CmsProjectDriver.class, I_CmsHistoryDriver.class, I_CmsSubscriptionDriver.class}) { if (interfaceClass.isAssignableFrom(obj.getClass())) { return interfaceClass; } } return null; } /** * Returns the correct project id.

* * @param dbc the database context * * @return the correct project id */ private CmsUUID getProjectIdForContext(CmsDbContext dbc) { CmsUUID projectId = dbc.getProjectId(); if (projectId.isNullUUID()) { projectId = dbc.currentProject().getUuid(); } return projectId; } /** * Returns if and what state needs to be updated.

* * @param dbc the db context * @param resource the resource * @param properties the properties to check * * @return 0: none, 1: structure, 2: resource * * @throws CmsDataAccessException if something goes wrong */ private int getUpdateState(CmsDbContext dbc, CmsResource resource, List properties) throws CmsDataAccessException { int updateState = 0; I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); Iterator it = properties.iterator(); while (it.hasNext() && (updateState < 2)) { CmsProperty property = it.next(); // read existing property CmsProperty existingProperty = vfsDriver.readPropertyObject( dbc, property.getName(), dbc.currentProject(), resource); // check the shared property if (property.getResourceValue() != null) { if (property.isDeleteResourceValue()) { if (existingProperty.getResourceValue() != null) { updateState = 2; // deleted } } else { if (existingProperty.getResourceValue() == null) { updateState = 2; // created } else { if (!property.getResourceValue().equals(existingProperty.getResourceValue())) { updateState = 2; // updated } } } } if (updateState == 0) { // check the individual property only if needed if (property.getStructureValue() != null) { if (property.isDeleteStructureValue()) { if (existingProperty.getStructureValue() != null) { updateState = 1; // deleted } } else { if (existingProperty.getStructureValue() == null) { updateState = 1; // created } else { if (!property.getStructureValue().equals(existingProperty.getStructureValue())) { updateState = 1; // updated } } } } } } return updateState; } /** * Returns all groups that are virtualizing the given role in the given ou.

* * @param dbc the database context * @param role the role * * @return all groups that are virtualizing the given role (or a child of it) * * @throws CmsException if something goes wrong */ private List getVirtualGroupsForRole(CmsDbContext dbc, CmsRole role) throws CmsException { Set roleFlags = new HashSet(); // add role flag Integer flags = Integer.valueOf(role.getVirtualGroupFlags()); roleFlags.add(flags); // collect all child role flags Iterator itChildRoles = role.getChildren(true).iterator(); while (itChildRoles.hasNext()) { CmsRole child = itChildRoles.next(); flags = Integer.valueOf(child.getVirtualGroupFlags()); roleFlags.add(flags); } // iterate all groups matching the flags List groups = new ArrayList(); Iterator it = getGroups(dbc, readOrganizationalUnit(dbc, role.getOuFqn()), false, false).iterator(); while (it.hasNext()) { CmsGroup group = it.next(); if (group.isVirtual()) { CmsRole r = CmsRole.valueOf(group); if (roleFlags.contains(Integer.valueOf(r.getVirtualGroupFlags()))) { groups.add(group); } } } return groups; } /** * Returns a list of users in a group.

* * @param dbc the current database context * @param ouFqn the organizational unit to get the users from * @param groupname the name of the group to list users from * @param includeOtherOuUsers include users of other organizational units * @param directUsersOnly if set only the direct assigned users will be returned, * if not also indirect users, ie. members of parent roles, * this parameter only works with roles * @param readRoles if to read roles or groups * * @return all {@link CmsUser} objects in the group * * @throws CmsException if operation was not successful */ private List internalUsersOfGroup( CmsDbContext dbc, String ouFqn, String groupname, boolean includeOtherOuUsers, boolean directUsersOnly, boolean readRoles) throws CmsException { CmsGroup group = readGroup(dbc, groupname); // check that the group really exists if ((group == null) || (!((!readRoles && !group.isRole()) || (readRoles && group.isRole())))) { throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_UNKNOWN_GROUP_1, groupname)); } String prefix = "_" + includeOtherOuUsers + "_" + directUsersOnly + "_" + ouFqn; String cacheKey = m_keyGenerator.getCacheKeyForGroupUsers(prefix, dbc, group); List allUsers = m_monitor.getCachedUserList(cacheKey); if (allUsers == null) { Set users = new HashSet( getUserDriver(dbc).readUsersOfGroup(dbc, groupname, includeOtherOuUsers)); if (readRoles && !directUsersOnly) { CmsRole role = CmsRole.valueOf(group); if (role.getParentRole() != null) { try { String parentGroup = role.getParentRole().getGroupName(); readGroup(dbc, parentGroup); // iterate the parent roles users.addAll( internalUsersOfGroup( dbc, ouFqn, parentGroup, includeOtherOuUsers, directUsersOnly, readRoles)); } catch (CmsDbEntryNotFoundException e) { // ignore, this may happen while deleting an orgunit if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } } String parentOu = CmsOrganizationalUnit.getParentFqn(group.getOuFqn()); if (parentOu != null) { // iterate the parent ou's users.addAll( internalUsersOfGroup( dbc, ouFqn, parentOu + group.getSimpleName(), includeOtherOuUsers, directUsersOnly, readRoles)); } } else if (!readRoles && !directUsersOnly) { List groups = getChildren(dbc, group, false); for (CmsGroup parentGroup : groups) { try { // iterate the parent groups users.addAll( internalUsersOfGroup( dbc, ouFqn, parentGroup.getName(), includeOtherOuUsers, directUsersOnly, readRoles)); } catch (CmsDbEntryNotFoundException e) { // ignore, this may happen while deleting an orgunit if (LOG.isDebugEnabled()) { LOG.debug(e.getLocalizedMessage(), e); } } } } // filter users from other ous if (!includeOtherOuUsers) { Iterator itUsers = users.iterator(); while (itUsers.hasNext()) { CmsUser user = itUsers.next(); if (!user.getOuFqn().equals(ouFqn)) { itUsers.remove(); } } } // make user list unmodifiable for caching allUsers = Collections.unmodifiableList(new ArrayList(users)); if (dbc.getProjectId().isNullUUID()) { m_monitor.cacheUserList(cacheKey, allUsers); } } return allUsers; } /** * Reads all resources that are inside and changed in a specified project.

* * @param dbc the current database context * @param projectId the ID of the project * @param mode one of the {@link CmsReadChangedProjectResourceMode} constants * * @return a List with all resources inside the specified project * * @throws CmsException if something goes wrong */ private List readChangedResourcesInsideProject( CmsDbContext dbc, CmsUUID projectId, CmsReadChangedProjectResourceMode mode) throws CmsException { String cacheKey = projectId + "_" + mode.toString(); List result = m_monitor.getCachedProjectResources(cacheKey); if (result != null) { return result; } List projectResources = readProjectResources(dbc, readProject(dbc, projectId)); result = new ArrayList(); String currentProjectResource = null; List resources = new ArrayList(); CmsResource currentResource = null; CmsLock currentLock = null; for (int i = 0; i < projectResources.size(); i++) { // read all resources that are inside the project by visiting each project resource currentProjectResource = projectResources.get(i); try { currentResource = readResource(dbc, currentProjectResource, CmsResourceFilter.ALL); if (currentResource.isFolder()) { resources.addAll(readResources(dbc, currentResource, CmsResourceFilter.ALL, true)); } else { resources.add(currentResource); } } catch (CmsException e) { // the project resource probably doesn't exist (anymore)... if (!(e instanceof CmsVfsResourceNotFoundException)) { throw e; } } } for (int j = 0; j < resources.size(); j++) { currentResource = resources.get(j); currentLock = getLock(dbc, currentResource).getEditionLock(); if (!currentResource.getState().isUnchanged()) { if ((currentLock.isNullLock() && (currentResource.getProjectLastModified().equals(projectId))) || (currentLock.isOwnedBy(dbc.currentUser()) && (currentLock.getProjectId().equals(projectId)))) { // add only resources that are // - inside the project, // - changed in the project, // - either unlocked, or locked for the current user in the project if ((mode == RCPRM_FILES_AND_FOLDERS_MODE) || (currentResource.isFolder() && (mode == RCPRM_FOLDERS_ONLY_MODE)) || (currentResource.isFile() && (mode == RCPRM_FILES_ONLY_MODE))) { result.add(currentResource); } } } } resources.clear(); resources = null; m_monitor.cacheProjectResources(cacheKey, result); return result; } /** * Sorts the given list of {@link CmsAccessControlEntry} objects.

* * The the 'all others' ace in first place, the 'overwrite all' ace in second.

* * @param aces the list of ACEs to sort * * @return true if the list contains the 'overwrite all' ace */ private boolean sortAceList(List aces) { // sort the list of entries Collections.sort(aces, CmsAccessControlEntry.COMPARATOR_ACE); // after sorting just the first 2 positions come in question for (int i = 0; i < Math.min(aces.size(), 2); i++) { CmsAccessControlEntry acEntry = aces.get(i); if (acEntry.getPrincipal().equals(CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID)) { return true; } } return false; } /** * All permissions and resources attributes of the principal * are transfered to a replacement principal.

* * @param dbc the current database context * @param project the current project * @param principalId the id of the principal to be replaced * @param replacementId the user to be transfered * @param withACEs flag to signal if the ACEs should also be transfered or just deleted * * @throws CmsException if operation was not successful */ private void transferPrincipalResources( CmsDbContext dbc, CmsProject project, CmsUUID principalId, CmsUUID replacementId, boolean withACEs) throws CmsException { // get all resources for the given user including resources associated by ACEs or attributes I_CmsUserDriver userDriver = getUserDriver(dbc); I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); Set resources = getResourcesForPrincipal(dbc, project, principalId, null, true); Iterator it = resources.iterator(); while (it.hasNext()) { CmsResource resource = it.next(); // check resource attributes boolean attrModified = false; CmsUUID createdUser = null; if (resource.getUserCreated().equals(principalId)) { createdUser = replacementId; attrModified = true; } CmsUUID lastModUser = null; if (resource.getUserLastModified().equals(principalId)) { lastModUser = replacementId; attrModified = true; } if (attrModified) { vfsDriver.transferResource(dbc, project, resource, createdUser, lastModUser); // clear the cache m_monitor.clearResourceCache(); } boolean aceModified = false; // check aces if (withACEs) { Iterator itAces = userDriver.readAccessControlEntries( dbc, project, resource.getResourceId(), false).iterator(); while (itAces.hasNext()) { CmsAccessControlEntry ace = itAces.next(); if (ace.getPrincipal().equals(principalId)) { CmsAccessControlEntry newAce = new CmsAccessControlEntry( ace.getResource(), replacementId, ace.getAllowedPermissions(), ace.getDeniedPermissions(), ace.getFlags()); // write the new ace userDriver.writeAccessControlEntry(dbc, project, newAce); aceModified = true; } } if (aceModified) { // clear the cache m_monitor.clearAccessControlListCache(); } } if (attrModified || aceModified) { // fire the event Map data = new HashMap(2); data.put(I_CmsEventListener.KEY_RESOURCE, resource); data.put( I_CmsEventListener.KEY_CHANGE, Integer.valueOf( ((attrModified) ? CHANGED_RESOURCE : 0) | ((aceModified) ? CHANGED_ACCESSCONTROL : 0))); OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data)); } } } /** * Undoes all content changes of a resource.

* * @param dbc the database context * @param onlineProject the online project * @param offlineResource the offline resource, or null if deleted * @param onlineResource the online resource * @param newState the new resource state * @param moveUndone is a move operation on the same resource has been made * * @throws CmsException if something goes wrong */ private void undoContentChanges( CmsDbContext dbc, CmsProject onlineProject, CmsResource offlineResource, CmsResource onlineResource, CmsResourceState newState, boolean moveUndone) throws CmsException { String path = ((moveUndone || (offlineResource == null)) ? onlineResource.getRootPath() : offlineResource.getRootPath()); // change folder or file? I_CmsUserDriver userDriver = getUserDriver(dbc); I_CmsVfsDriver vfsDriver = getVfsDriver(dbc); if (onlineResource.isFolder()) { CmsFolder restoredFolder = new CmsFolder( onlineResource.getStructureId(), onlineResource.getResourceId(), path, onlineResource.getTypeId(), onlineResource.getFlags(), dbc.currentProject().getUuid(), newState, onlineResource.getDateCreated(), onlineResource.getUserCreated(), onlineResource.getDateLastModified(), onlineResource.getUserLastModified(), onlineResource.getDateReleased(), onlineResource.getDateExpired(), onlineResource.getVersion()); // version number does not matter since it will be computed later // write the folder in the offline project // this sets a flag so that the folder date is not set to the current time restoredFolder.setDateLastModified(onlineResource.getDateLastModified()); // write the folder vfsDriver.writeResource(dbc, dbc.currentProject().getUuid(), restoredFolder, NOTHING_CHANGED); // restore the properties from the online project vfsDriver.deletePropertyObjects( dbc, dbc.currentProject().getUuid(), restoredFolder, CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES); List propertyInfos = vfsDriver.readPropertyObjects(dbc, onlineProject, onlineResource); vfsDriver.writePropertyObjects(dbc, dbc.currentProject(), restoredFolder, propertyInfos); // restore the access control entries from the online project userDriver.removeAccessControlEntries(dbc, dbc.currentProject(), onlineResource.getResourceId()); ListIterator aceList = userDriver.readAccessControlEntries( dbc, onlineProject, onlineResource.getResourceId(), false).listIterator(); while (aceList.hasNext()) { CmsAccessControlEntry ace = aceList.next(); userDriver.createAccessControlEntry( dbc, dbc.currentProject(), onlineResource.getResourceId(), ace.getPrincipal(), ace.getPermissions().getAllowedPermissions(), ace.getPermissions().getDeniedPermissions(), ace.getFlags()); } } else { byte[] onlineContent = vfsDriver.readContent( dbc, CmsProject.ONLINE_PROJECT_ID, onlineResource.getResourceId()); CmsFile restoredFile = new CmsFile( onlineResource.getStructureId(), onlineResource.getResourceId(), path, onlineResource.getTypeId(), onlineResource.getFlags(), dbc.currentProject().getUuid(), newState, onlineResource.getDateCreated(), onlineResource.getUserCreated(), onlineResource.getDateLastModified(), onlineResource.getUserLastModified(), onlineResource.getDateReleased(), onlineResource.getDateExpired(), 0, onlineResource.getLength(), onlineResource.getDateContent(), onlineResource.getVersion(), // version number does not matter since it will be computed later onlineContent); // write the file in the offline project // this sets a flag so that the file date is not set to the current time restoredFile.setDateLastModified(onlineResource.getDateLastModified()); // collect the old properties List properties = vfsDriver.readPropertyObjects(dbc, onlineProject, onlineResource); if (offlineResource != null) { // bug fix 1020: delete all properties (inclum_rejectStructureIdded shared), // shared properties will be recreated by the next call of #createResource(...) vfsDriver.deletePropertyObjects( dbc, dbc.currentProject().getUuid(), onlineResource, CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES); // implementation notes: // undo changes can become complex e.g. if a resource was deleted, and then // another resource was copied over the deleted file as a sibling // therefore we must "clean" delete the offline resource, and then create // an new resource with the create method // note that this does NOT apply to folders, since a folder cannot be replaced // like a resource anyway deleteResource(dbc, offlineResource, CmsResource.DELETE_PRESERVE_SIBLINGS); } CmsResource res = createResource( dbc, restoredFile.getRootPath(), restoredFile, restoredFile.getContents(), properties, false); // copy the access control entries from the online project if (offlineResource != null) { userDriver.removeAccessControlEntries(dbc, dbc.currentProject(), onlineResource.getResourceId()); } ListIterator aceList = userDriver.readAccessControlEntries( dbc, onlineProject, onlineResource.getResourceId(), false).listIterator(); while (aceList.hasNext()) { CmsAccessControlEntry ace = aceList.next(); userDriver.createAccessControlEntry( dbc, dbc.currentProject(), res.getResourceId(), ace.getPrincipal(), ace.getPermissions().getAllowedPermissions(), ace.getPermissions().getDeniedPermissions(), ace.getFlags()); } vfsDriver.deleteUrlNameMappingEntries( dbc, false, CmsUrlNameMappingFilter.ALL.filterStructureId(res.getStructureId()).filterStates( CmsUrlNameMappingEntry.MAPPING_STATUS_NEW, CmsUrlNameMappingEntry.MAPPING_STATUS_REPLACE_ON_PUBLISH)); // restore the state to unchanged res.setState(newState); m_vfsDriver.writeResourceState(dbc, dbc.currentProject(), res, UPDATE_ALL, false); } // delete all offline relations if (offlineResource != null) { vfsDriver.deleteRelations(dbc, dbc.currentProject().getUuid(), offlineResource, CmsRelationFilter.TARGETS); } // get online relations List relations = vfsDriver.readRelations( dbc, CmsProject.ONLINE_PROJECT_ID, onlineResource, CmsRelationFilter.TARGETS); // write offline relations Iterator itRelations = relations.iterator(); while (itRelations.hasNext()) { CmsRelation relation = itRelations.next(); vfsDriver.createRelation(dbc, dbc.currentProject().getUuid(), relation); } // update the cache m_monitor.clearResourceCache(); m_monitor.flushCache(CmsMemoryMonitor.CacheType.PROPERTY, CmsMemoryMonitor.CacheType.PROPERTY_LIST); if ((offlineResource == null) || offlineResource.getRootPath().equals(onlineResource.getRootPath())) { log( dbc, new CmsLogEntry( dbc, onlineResource.getStructureId(), CmsLogEntryType.RESOURCE_RESTORED, new String[] {onlineResource.getRootPath()}), false); } else { log( dbc, new CmsLogEntry( dbc, offlineResource.getStructureId(), CmsLogEntryType.RESOURCE_MOVE_RESTORED, new String[] {offlineResource.getRootPath(), onlineResource.getRootPath()}), false); } if (offlineResource != null) { OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCE, offlineResource))); } else { OpenCms.fireCmsEvent( new CmsEvent( I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED, Collections. singletonMap(I_CmsEventListener.KEY_RESOURCE, onlineResource))); } } /** * Updates the current users context dates with the given resource.

* * This checks the date information of the resource based on * {@link CmsResource#getDateLastModified()} as well as * {@link CmsResource#getDateReleased()} and {@link CmsResource#getDateExpired()}. * The current users request context is updated with the the "latest" dates found.

* * This is required in order to ensure proper setting of "last-modified" http headers * and also for expiration of cached elements in the Flex cache. * Consider the following use case: Page A is generated from resources x, y and z. * If either x, y or z has an expiration / release date set, then page A must expire at a certain point * in time. This is ensured by the context date check here.

* * @param dbc the current database context * @param resource the resource to get the date information from */ private void updateContextDates(CmsDbContext dbc, CmsResource resource) { CmsFlexRequestContextInfo info = dbc.getFlexRequestContextInfo(); if (info != null) { info.updateFromResource(resource); } } /** * Updates the current users context dates with each {@link CmsResource} object in the given list.

* * The given input list is returned unmodified.

* * Please see {@link #updateContextDates(CmsDbContext, CmsResource)} for an explanation of what this method does.

* * @param dbc the current database context * @param resourceList a list of {@link CmsResource} objects * * @return the original list of CmsResources with the full resource name set */ private List updateContextDates(CmsDbContext dbc, List resourceList) { CmsFlexRequestContextInfo info = dbc.getFlexRequestContextInfo(); if (info != null) { for (int i = 0; i < resourceList.size(); i++) { CmsResource resource = resourceList.get(i); info.updateFromResource(resource); } } return resourceList; } /** * Returns a List of {@link CmsResource} objects generated when applying the given filter to the given list, * also updates the current users context dates with each {@link CmsResource} object in the given list, * also applies the selected resource filter to all resources in the list and returns the remaining resources.

* * Please see {@link #updateContextDates(CmsDbContext, CmsResource)} for an explanation of what this method does.

* * @param dbc the current database context * @param resourceList a list of {@link CmsResource} objects * @param filter the resource filter to use * * @return a List of {@link CmsResource} objects generated when applying the given filter to the given list */ private List updateContextDates( CmsDbContext dbc, List resourceList, CmsResourceFilter filter) { if (CmsResourceFilter.ALL == filter) { // if there is no filter required, then use the simpler method that does not apply the filter return new ArrayList(updateContextDates(dbc, resourceList)); } CmsFlexRequestContextInfo info = dbc.getFlexRequestContextInfo(); List result = new ArrayList(resourceList.size()); for (int i = 0; i < resourceList.size(); i++) { CmsResource resource = resourceList.get(i); if (filter.isValid(dbc.getRequestContext(), resource)) { result.add(resource); } // must also include "invalid" resources for the update of context dates // since a resource may be invalid because of release / expiration date if (info != null) { info.updateFromResource(resource); } } return result; } /** * Updates the state of a resource, depending on the resourceState parameter.

* * @param dbc the db context * @param resource the resource * @param resourceState if true the resource state will be updated, if not just the structure state. * * @throws CmsDataAccessException if something goes wrong */ private void updateState(CmsDbContext dbc, CmsResource resource, boolean resourceState) throws CmsDataAccessException { CmsUUID projectId = ((dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID()) ? dbc.currentProject().getUuid() : dbc.getProjectId(); resource.setUserLastModified(dbc.currentUser().getId()); if (resourceState) { // update the whole resource state getVfsDriver(dbc).writeResource(dbc, projectId, resource, UPDATE_RESOURCE_STATE); } else { // update the structure state getVfsDriver(dbc).writeResource(dbc, projectId, resource, UPDATE_STRUCTURE_STATE); } } /** * Wraps a driver object with a dynamic proxy that counts method calls and their durations.

* * @param newDriverInstance the driver instance to wrap * @return the proxy */ private Object wrapDriverInProfilingProxy(Object newDriverInstance) { Class cls = getDriverInterfaceForProxy(newDriverInstance); if (cls == null) { return newDriverInstance; } return Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(), new Class[] {cls}, new CmsProfilingInvocationHandler(newDriverInstance, CmsDefaultProfilingHandler.INSTANCE)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy