org.opencms.db.CmsDriverManager Maven / Gradle / Ivy
Show all versions of opencms-core Show documentation
/*
* 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