001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.db;
029
030import org.opencms.ade.publish.CmsTooManyPublishResourcesException;
031import org.opencms.configuration.CmsConfigurationManager;
032import org.opencms.configuration.CmsSystemConfiguration;
033import org.opencms.db.generic.CmsPublishHistoryCleanupFilter;
034import org.opencms.db.log.CmsLogEntry;
035import org.opencms.db.log.CmsLogFilter;
036import org.opencms.db.urlname.CmsUrlNameMappingEntry;
037import org.opencms.db.urlname.CmsUrlNameMappingFilter;
038import org.opencms.file.CmsDataAccessException;
039import org.opencms.file.CmsFile;
040import org.opencms.file.CmsFolder;
041import org.opencms.file.CmsGroup;
042import org.opencms.file.CmsObject;
043import org.opencms.file.CmsProject;
044import org.opencms.file.CmsProperty;
045import org.opencms.file.CmsPropertyDefinition;
046import org.opencms.file.CmsRequestContext;
047import org.opencms.file.CmsResource;
048import org.opencms.file.CmsResourceFilter;
049import org.opencms.file.CmsUser;
050import org.opencms.file.CmsUserSearchParameters;
051import org.opencms.file.CmsVfsException;
052import org.opencms.file.CmsVfsResourceAlreadyExistsException;
053import org.opencms.file.CmsVfsResourceNotFoundException;
054import org.opencms.file.history.CmsHistoryPrincipal;
055import org.opencms.file.history.CmsHistoryProject;
056import org.opencms.file.history.I_CmsHistoryResource;
057import org.opencms.file.types.CmsResourceTypeJsp;
058import org.opencms.gwt.shared.alias.CmsAliasImportResult;
059import org.opencms.gwt.shared.alias.CmsAliasMode;
060import org.opencms.i18n.CmsMessageContainer;
061import org.opencms.lock.CmsLock;
062import org.opencms.lock.CmsLockException;
063import org.opencms.lock.CmsLockFilter;
064import org.opencms.lock.CmsLockManager;
065import org.opencms.lock.CmsLockType;
066import org.opencms.main.CmsEvent;
067import org.opencms.main.CmsException;
068import org.opencms.main.CmsIllegalArgumentException;
069import org.opencms.main.CmsInitException;
070import org.opencms.main.CmsLog;
071import org.opencms.main.CmsMultiException;
072import org.opencms.main.I_CmsEventListener;
073import org.opencms.main.OpenCms;
074import org.opencms.publish.CmsPublishEngine;
075import org.opencms.relations.CmsLink;
076import org.opencms.relations.CmsRelation;
077import org.opencms.relations.CmsRelationFilter;
078import org.opencms.relations.CmsRelationType;
079import org.opencms.report.I_CmsReport;
080import org.opencms.security.CmsAccessControlEntry;
081import org.opencms.security.CmsAccessControlList;
082import org.opencms.security.CmsDefaultPermissionHandler;
083import org.opencms.security.CmsOrganizationalUnit;
084import org.opencms.security.CmsPermissionSet;
085import org.opencms.security.CmsPermissionSetCustom;
086import org.opencms.security.CmsPermissionViolationException;
087import org.opencms.security.CmsPrincipal;
088import org.opencms.security.CmsRole;
089import org.opencms.security.CmsRoleViolationException;
090import org.opencms.security.CmsSecurityException;
091import org.opencms.security.I_CmsPermissionHandler;
092import org.opencms.security.I_CmsPermissionHandler.LockCheck;
093import org.opencms.security.I_CmsPrincipal;
094import org.opencms.security.twofactor.CmsSecondFactorInfo;
095import org.opencms.util.CmsFileUtil;
096import org.opencms.util.CmsStringUtil;
097import org.opencms.util.CmsUUID;
098
099import java.sql.Connection;
100import java.sql.SQLException;
101import java.util.ArrayList;
102import java.util.Collection;
103import java.util.Collections;
104import java.util.Date;
105import java.util.HashMap;
106import java.util.HashSet;
107import java.util.Iterator;
108import java.util.List;
109import java.util.Locale;
110import java.util.Map;
111import java.util.Set;
112
113import org.apache.commons.logging.Log;
114
115/**
116 * The OpenCms security manager.<p>
117 *
118 * The security manager checks the permissions required for a user action invoke by the Cms object. If permissions
119 * are granted, the security manager invokes a method on the OpenCms driver manager to access the database.<p>
120 *
121 * @since 6.0.0
122 */
123public final class CmsSecurityManager {
124
125    /** The log object for this class. */
126    private static final Log LOG = CmsLog.getLog(CmsSecurityManager.class);
127
128    /** The factory to create runtime info objects. */
129    protected I_CmsDbContextFactory m_dbContextFactory;
130
131    /** The initialized OpenCms driver manager to access the database. */
132    protected CmsDriverManager m_driverManager;
133
134    /** The lock manager. */
135    private CmsLockManager m_lockManager;
136
137    /** Permission handler implementation. */
138    private I_CmsPermissionHandler m_permissionHandler;
139
140    /**
141     * Default constructor.<p>
142     */
143    private CmsSecurityManager() {
144
145        // intentionally left blank
146    }
147
148    /**
149     * Creates a new instance of the OpenCms security manager.<p>
150     *
151     * @param configurationManager the configuration manager
152     * @param runtimeInfoFactory the initialized OpenCms runtime info factory
153     * @param publishEngine the publish engine
154     *
155     * @return a new instance of the OpenCms security manager
156     *
157     * @throws CmsInitException if the security manager could not be initialized
158     */
159    public static CmsSecurityManager newInstance(
160        CmsConfigurationManager configurationManager,
161        I_CmsDbContextFactory runtimeInfoFactory,
162        CmsPublishEngine publishEngine)
163    throws CmsInitException {
164
165        if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_2_INITIALIZING) {
166            // OpenCms is already initialized
167            throw new CmsInitException(
168                org.opencms.main.Messages.get().container(org.opencms.main.Messages.ERR_ALREADY_INITIALIZED_0));
169        }
170
171        CmsSecurityManager securityManager = new CmsSecurityManager();
172        securityManager.init(configurationManager, runtimeInfoFactory, publishEngine);
173
174        return securityManager;
175    }
176
177    /**
178     * Adds an alias.<p>
179     *
180     * @param context the current request context
181     * @param alias the alias to add
182     * @throws CmsException if something goes wrong
183     */
184    public void addAlias(CmsRequestContext context, CmsAlias alias) throws CmsException {
185
186        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
187        try {
188            m_driverManager.addAlias(dbc, context.getCurrentProject(), alias);
189        } catch (Exception e) {
190            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
191        } finally {
192            dbc.clear();
193        }
194    }
195
196    /**
197     * Adds a new relation to a given resource.<p>
198     *
199     * @param context the request context
200     * @param resource the resource to add the relation to
201     * @param target the target of the relation
202     * @param type the type of the relation
203     * @param importCase if importing relations
204     *
205     * @throws CmsException if something goes wrong
206     *
207     * @see #deleteRelationsForResource(CmsRequestContext, CmsResource, CmsRelationFilter)
208     * @see CmsObject#addRelationToResource(String, String, String)
209     */
210    public void addRelationToResource(
211        CmsRequestContext context,
212        CmsResource resource,
213        CmsResource target,
214        CmsRelationType type,
215        boolean importCase)
216    throws CmsException {
217
218        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
219        try {
220            checkOfflineProject(dbc);
221            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
222            m_driverManager.addRelationToResource(dbc, resource, target, type, importCase);
223        } catch (Exception e) {
224            dbc.report(
225                null,
226                Messages.get().container(
227                    Messages.ERR_ADD_RELATION_TO_RESOURCE_3,
228                    context.getSitePath(resource),
229                    context.getSitePath(target),
230                    type),
231                e);
232
233        } finally {
234            dbc.clear();
235        }
236    }
237
238    /**
239     * Adds a resource to the given organizational unit.<p>
240     *
241     * @param context the current request context
242     * @param orgUnit the organizational unit to add the resource to
243     * @param resource the resource that is to be added to the organizational unit
244     *
245     * @throws CmsException if something goes wrong
246     *
247     * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String)
248     * @see org.opencms.security.CmsOrgUnitManager#removeResourceFromOrgUnit(CmsObject, String, String)
249     */
250    public void addResourceToOrgUnit(CmsRequestContext context, CmsOrganizationalUnit orgUnit, CmsResource resource)
251    throws CmsException {
252
253        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
254        try {
255            checkOfflineProject(dbc);
256            checkRole(dbc, CmsRole.ADMINISTRATOR.forOrgUnit(orgUnit.getName()));
257            m_driverManager.addResourceToOrgUnit(dbc, orgUnit, resource);
258        } catch (Exception e) {
259            dbc.report(
260                null,
261                Messages.get().container(
262                    Messages.ERR_ADD_RESOURCE_TO_ORGUNIT_2,
263                    orgUnit.getName(),
264                    dbc.removeSiteRoot(resource.getRootPath())),
265                e);
266        } finally {
267            dbc.clear();
268        }
269    }
270
271    /**
272     * Adds a user to a group.<p>
273     *
274     * @param context the current request context
275     * @param username the name of the user that is to be added to the group
276     * @param groupname the name of the group
277     * @param readRoles if reading roles or groups
278     *
279     * @throws CmsException if operation was not successful
280     */
281    public void addUserToGroup(CmsRequestContext context, String username, String groupname, boolean readRoles)
282    throws CmsException {
283
284        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
285        try {
286            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(username));
287            checkRoleForUserModification(dbc, username, role);
288            m_driverManager.addUserToGroup(
289                dbc,
290                CmsOrganizationalUnit.removeLeadingSeparator(username),
291                CmsOrganizationalUnit.removeLeadingSeparator(groupname),
292                readRoles);
293        } catch (Exception e) {
294            dbc.report(null, Messages.get().container(Messages.ERR_ADD_USER_GROUP_FAILED_2, username, groupname), e);
295        } finally {
296            dbc.clear();
297        }
298    }
299
300    /**
301     * Changes the lock of a resource to the current user, that is "steals" the lock from another user.<p>
302     *
303     * @param context the current request context
304     * @param resource the resource to change the lock for
305     *
306     * @throws CmsException if something goes wrong
307     *
308     * @see org.opencms.file.types.I_CmsResourceType#changeLock(CmsObject, CmsSecurityManager, CmsResource)
309     */
310    public void changeLock(CmsRequestContext context, CmsResource resource) throws CmsException {
311
312        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
313        checkOfflineProject(dbc);
314        try {
315            m_driverManager.changeLock(dbc, resource, CmsLockType.EXCLUSIVE);
316        } catch (Exception e) {
317            dbc.report(
318                null,
319                Messages.get().container(
320                    Messages.ERR_CHANGE_LOCK_OF_RESOURCE_2,
321                    context.getSitePath(resource),
322                    " - " + e.getMessage()),
323                e);
324        } finally {
325            dbc.clear();
326        }
327    }
328
329    /**
330     * Returns a list with all sub resources of a given folder that have set the given property,
331     * matching the current property's value with the given old value and replacing it by a given new value.<p>
332     *
333     * @param context the current request context
334     * @param resource the resource on which property definition values are changed
335     * @param propertyDefinition the name of the property definition to change the value
336     * @param oldValue the old value of the property definition
337     * @param newValue the new value of the property definition
338     * @param recursive if true, change recursively all property values on sub-resources (only for folders)
339     *
340     * @return a list with the <code>{@link CmsResource}</code>'s where the property value has been changed
341     *
342     * @throws CmsVfsException for now only when the search for the old value fails
343     * @throws CmsException if operation was not successful
344     */
345    public synchronized List<CmsResource> changeResourcesInFolderWithProperty(
346        CmsRequestContext context,
347        CmsResource resource,
348        String propertyDefinition,
349        String oldValue,
350        String newValue,
351        boolean recursive)
352    throws CmsException, CmsVfsException {
353
354        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
355        List<CmsResource> result = null;
356        try {
357            result = m_driverManager.changeResourcesInFolderWithProperty(
358                dbc,
359                resource,
360                propertyDefinition,
361                oldValue,
362                newValue,
363                recursive);
364        } catch (Exception e) {
365            dbc.report(
366                null,
367                Messages.get().container(
368                    Messages.ERR_CHANGE_RESOURCES_IN_FOLDER_WITH_PROP_4,
369                    new Object[] {propertyDefinition, oldValue, newValue, context.getSitePath(resource)}),
370                e);
371        } finally {
372            dbc.clear();
373        }
374        return result;
375    }
376
377    /**
378     * Checks user name / password and other things which would prevent the user from logging in, but does not check the second factor for 2FA.
379     *
380     * <p>Throws an exception like the normal login method if these checks fail. If it succeeds, nothing actually happens.
381     *
382     * @param context the request context
383     * @param username the user name
384     * @param password the password
385     * @param remoteAddress the remote address
386     * @throws CmsException if the login check fails
387     */
388    public void checkLogin(CmsRequestContext context, String username, String password, String remoteAddress)
389    throws CmsException {
390
391        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
392        CmsUser result = null;
393        try {
394            result = m_driverManager.loginUser(
395                dbc,
396                CmsOrganizationalUnit.removeLeadingSeparator(username),
397                password,
398                null,
399                remoteAddress,
400                CmsDriverManager.LoginUserMode.checkOnly);
401        } finally {
402            dbc.clear();
403        }
404    }
405
406    /**
407     * Checks if the current user has management access to the given project.<p>
408     *
409     * @param dbc the current database context
410     * @param project the project to check
411     *
412     * @throws CmsRoleViolationException if the user does not have the required role permissions
413     */
414    public void checkManagerOfProjectRole(CmsDbContext dbc, CmsProject project) throws CmsRoleViolationException {
415
416        boolean hasRole = false;
417        try {
418            if (hasRole(dbc, dbc.currentUser(), CmsRole.ROOT_ADMIN)) {
419                return;
420            }
421            hasRole = m_driverManager.getAllManageableProjects(
422                dbc,
423                m_driverManager.readOrganizationalUnit(dbc, project.getOuFqn()),
424                false).contains(project);
425        } catch (CmsException e) {
426            // should never happen
427            if (LOG.isErrorEnabled()) {
428                LOG.error(e.getLocalizedMessage(), e);
429            }
430        }
431        if (!hasRole) {
432            throw new CmsRoleViolationException(
433                org.opencms.security.Messages.get().container(
434                    org.opencms.security.Messages.ERR_NOT_MANAGER_OF_PROJECT_2,
435                    dbc.currentUser().getName(),
436                    dbc.currentProject().getName()));
437        }
438    }
439
440    /**
441     * Checks if the project in the given database context is not the "Online" project,
442     * and throws an Exception if this is the case.<p>
443     *
444     * This is used to ensure a user is in an "Offline" project
445     * before write access to VFS resources is granted.<p>
446     *
447     * @param dbc the current OpenCms users database context
448     *
449     * @throws CmsVfsException if the project in the given database context is the "Online" project
450     */
451    public void checkOfflineProject(CmsDbContext dbc) throws CmsVfsException {
452
453        if (dbc.currentProject().isOnlineProject()) {
454            throw new CmsVfsException(
455                org.opencms.file.Messages.get().container(
456                    org.opencms.file.Messages.ERR_NOT_ALLOWED_IN_ONLINE_PROJECT_0));
457        }
458    }
459
460    /**
461     * Performs a blocking permission check on a resource.<p>
462     *
463     * If the required permissions are not satisfied by the permissions the user has on the resource,
464     * an exception is thrown.<p>
465     *
466     * @param context the current request context
467     * @param resource the resource on which permissions are required
468     * @param requiredPermissions the set of permissions required to access the resource
469     * @param checkLock if true, the lock status of the resource is also checked
470     * @param filter the filter for the resource
471     *
472     * @throws CmsException in case of any i/o error
473     * @throws CmsSecurityException if the required permissions are not satisfied
474     *
475     * @see #checkPermissions(CmsRequestContext, CmsResource, CmsPermissionSet, I_CmsPermissionHandler.CmsPermissionCheckResult)
476     */
477    public void checkPermissions(
478        CmsRequestContext context,
479        CmsResource resource,
480        CmsPermissionSet requiredPermissions,
481        boolean checkLock,
482        CmsResourceFilter filter)
483    throws CmsException, CmsSecurityException {
484
485        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
486        try {
487            // check the access permissions
488            checkPermissions(dbc, resource, requiredPermissions, checkLock, filter);
489        } finally {
490            dbc.clear();
491        }
492    }
493
494    /**
495     * Checks if the current user has the permissions to publish the given publish list
496     * (which contains the information about the resources / project to publish).<p>
497     *
498     * @param dbc the current OpenCms users database context
499     * @param publishList the publish list to check (contains the information about the resources / project to publish)
500     *
501     * @throws CmsException if the user does not have the required permissions because of project lock state
502     * @throws CmsMultiException if issues occur like a direct publish is attempted on a resource
503     *         whose parent folder is new or deleted in the offline project,
504     *         or if the current user has no management access to the current project
505     */
506    public void checkPublishPermissions(CmsDbContext dbc, CmsPublishList publishList)
507    throws CmsException, CmsMultiException {
508
509        // is the current project an "offline" project?
510        checkOfflineProject(dbc);
511
512        // check if this is a "direct publish" attempt
513        if (!publishList.isDirectPublish()) {
514            // check if the user is a manager of the current project, in this case he has publish permissions
515            checkManagerOfProjectRole(dbc, dbc.getRequestContext().getCurrentProject());
516        } else {
517            // direct publish, create exception containers
518            CmsMultiException resourceIssues = new CmsMultiException();
519            CmsMultiException permissionIssues = new CmsMultiException();
520            // iterate all resources in the direct publish list
521            Iterator<CmsResource> it = publishList.getDirectPublishResources().iterator();
522            List<String> parentFolders = new ArrayList<String>();
523            while (it.hasNext()) {
524                CmsResource res = it.next();
525                // the parent folder must not be new or deleted
526                String parentFolder = CmsResource.getParentFolder(res.getRootPath());
527                if ((parentFolder != null) && !parentFolders.contains(parentFolder)) {
528                    // check each parent folder only once
529                    CmsResource parent = readResource(dbc, parentFolder, CmsResourceFilter.ALL);
530                    if (parent.getState().isDeleted()) {
531                        if (!(publishList.isUserPublishList() && publishList.getDeletedFolderList().contains(parent))) {
532                            // parent folder is deleted - direct publish not allowed
533                            resourceIssues.addException(
534                                new CmsVfsException(
535                                    Messages.get().container(
536                                        Messages.ERR_DIRECT_PUBLISH_PARENT_DELETED_2,
537                                        dbc.getRequestContext().removeSiteRoot(res.getRootPath()),
538                                        parentFolder)));
539                        }
540                    }
541                    if (parent.getState().isNew()) {
542                        if (!(publishList.isUserPublishList() && publishList.getFolderList().contains(parent))) {
543                            // parent folder is new - direct publish not allowed
544                            resourceIssues.addException(
545                                new CmsVfsException(
546                                    Messages.get().container(
547                                        Messages.ERR_DIRECT_PUBLISH_PARENT_NEW_2,
548                                        dbc.removeSiteRoot(res.getRootPath()),
549                                        parentFolder)));
550                        }
551                    }
552                    // add checked parent folder to prevent duplicate checks
553                    parentFolders.add(parentFolder);
554                }
555                // check if the user has the explicit permission to direct publish the selected resource
556                if (I_CmsPermissionHandler.PERM_ALLOWED != hasPermissions(
557                    dbc.getRequestContext(),
558                    res,
559                    CmsPermissionSet.ACCESS_DIRECT_PUBLISH,
560                    true,
561                    CmsResourceFilter.ALL)) {
562
563                    // the user has no "direct publish" permissions on the resource
564                    permissionIssues.addException(
565                        new CmsSecurityException(
566                            Messages.get().container(
567                                Messages.ERR_DIRECT_PUBLISH_NO_PERMISSIONS_1,
568                                dbc.removeSiteRoot(res.getRootPath()))));
569                }
570            }
571            if (resourceIssues.hasExceptions() || permissionIssues.hasExceptions()) {
572                // there are issues, permission check has failed
573                resourceIssues.addExceptions(permissionIssues.getExceptions());
574                throw resourceIssues;
575            }
576        }
577        // no issues have been found , permissions are granted
578    }
579
580    /**
581     * Checks if the user of the current database context has permissions to impersonate the given role
582     * in the given organizational unit.<p>
583     *
584     * If the organizational unit is <code>null</code>, this method will check if the
585     * given user has the given role for at least one organizational unit.<p>
586     *
587     * @param dbc the current OpenCms users database context
588     * @param role the role to check
589     *
590     * @throws CmsRoleViolationException if the user does not have the required role permissions
591     *
592     * @see org.opencms.security.CmsRoleManager#checkRole(CmsObject, CmsRole)
593     */
594    public void checkRole(CmsDbContext dbc, CmsRole role) throws CmsRoleViolationException {
595
596        if (!hasRole(dbc, dbc.currentUser(), role)) {
597            if (role.getOuFqn() != null) {
598                throw role.createRoleViolationExceptionForOrgUnit(dbc.getRequestContext(), role.getOuFqn());
599            } else {
600                throw role.createRoleViolationException(dbc.getRequestContext());
601            }
602        }
603    }
604
605    /**
606     * Checks if the user of the current context has permissions to impersonate the given role.<p>
607     *
608     * If the organizational unit is <code>null</code>, this method will check if the
609     * given user has the given role for at least one organizational unit.<p>
610     *
611     * @param context the current request context
612     * @param role the role to check
613     *
614     * @throws CmsRoleViolationException if the user does not have the required role permissions
615     */
616    public void checkRole(CmsRequestContext context, CmsRole role) throws CmsRoleViolationException {
617
618        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
619        try {
620            checkRole(dbc, role);
621        } finally {
622            dbc.clear();
623        }
624    }
625
626    /**
627     * Checks if the user of the current database context has permissions to impersonate the given role
628     * for the given resource.<p>
629     *
630     * @param dbc the current OpenCms users database context
631     * @param role the role to check
632     * @param resource the resource to check the role for
633     *
634     * @throws CmsRoleViolationException if the user does not have the required role permissions
635     *
636     * @see org.opencms.security.CmsRoleManager#checkRole(CmsObject, CmsRole)
637     */
638    public void checkRoleForResource(CmsDbContext dbc, CmsRole role, CmsResource resource)
639    throws CmsRoleViolationException {
640
641        if (!hasRoleForResource(dbc, dbc.currentUser(), role, resource)) {
642            throw role.createRoleViolationExceptionForResource(dbc.getRequestContext(), resource);
643        }
644    }
645
646    /**
647     * Checks if the user of the current context has permissions to impersonate the given role
648     * for the given resource.<p>
649     *
650     * @param context the current request context
651     * @param role the role to check
652     * @param resource the resource to check the role for
653     *
654     * @throws CmsRoleViolationException if the user does not have the required role permissions
655     */
656    public void checkRoleForResource(CmsRequestContext context, CmsRole role, CmsResource resource)
657    throws CmsRoleViolationException {
658
659        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
660        try {
661            checkRoleForResource(dbc, role, resource);
662        } finally {
663            dbc.clear();
664        }
665    }
666
667    /**
668     * Changes the resource flags of a resource.<p>
669     *
670     * The resource flags are used to indicate various "special" conditions
671     * for a resource. Most notably, the "internal only" setting which signals
672     * that a resource can not be directly requested with it's URL.<p>
673     *
674     * @param context the current request context
675     * @param resource the resource to change the flags for
676     * @param flags the new resource flags for this resource
677     *
678     * @throws CmsException if something goes wrong
679     * @throws CmsSecurityException if the user has insufficient permission for the given resource (({@link CmsPermissionSet#ACCESS_WRITE} required)
680     *
681     * @see org.opencms.file.types.I_CmsResourceType#chflags(CmsObject, CmsSecurityManager, CmsResource, int)
682     */
683    public void chflags(CmsRequestContext context, CmsResource resource, int flags)
684    throws CmsException, CmsSecurityException {
685
686        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
687        try {
688            checkOfflineProject(dbc);
689            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
690            m_driverManager.chflags(dbc, resource, flags);
691        } catch (Exception e) {
692            dbc.report(
693                null,
694                Messages.get().container(Messages.ERR_CHANGE_RESOURCE_FLAGS_1, context.getSitePath(resource)),
695                e);
696        } finally {
697            dbc.clear();
698        }
699    }
700
701    /**
702     * Changes the resource type of a resource.<p>
703     *
704     * OpenCms handles resources according to the resource type,
705     * not the file suffix. This is e.g. why a JSP in OpenCms can have the
706     * suffix ".html" instead of ".jsp" only. Changing the resource type
707     * makes sense e.g. if you want to make a plain text file a JSP resource,
708     * or a binary file an image, etc.<p>
709     *
710     * @param context the current request context
711     * @param resource the resource to change the type for
712     * @param type the new resource type for this resource
713     *
714     * @throws CmsException if something goes wrong
715     * @throws CmsSecurityException if the user has insufficient permission for the given resource (({@link CmsPermissionSet#ACCESS_WRITE} required))
716     *
717     * @see org.opencms.file.types.I_CmsResourceType#chtype(CmsObject, CmsSecurityManager, CmsResource, int)
718     * @see CmsObject#chtype(String, int)
719     */
720    @SuppressWarnings("javadoc")
721    public void chtype(CmsRequestContext context, CmsResource resource, int type)
722    throws CmsException, CmsSecurityException {
723
724        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
725        try {
726            checkOfflineProject(dbc);
727            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
728            if (CmsResourceTypeJsp.isJspTypeId(type)) {
729                // security check preventing the creation of a jsp file without permissions
730                checkRoleForResource(dbc, CmsRole.VFS_MANAGER, resource);
731            }
732            m_driverManager.chtype(dbc, resource, type);
733        } catch (Exception e) {
734            dbc.report(
735                null,
736                Messages.get().container(Messages.ERR_CHANGE_RESOURCE_TYPE_1, context.getSitePath(resource)),
737                e);
738        } finally {
739            dbc.clear();
740        }
741    }
742
743    /**
744     * Cleans up publish history entries according to the given filter object.
745     *
746     * @param context the request context
747     * @param filter the filter describing what to clean up
748     * @return the number of cleaned up rows
749     * @throws CmsException if something goes wrong
750     */
751    public int cleanupPublishHistory(CmsRequestContext context, CmsPublishHistoryCleanupFilter filter)
752    throws CmsException {
753
754        checkRole(context, CmsRole.VFS_MANAGER);
755        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
756        try {
757            return m_driverManager.cleanupPublishHistory(dbc, filter);
758        } catch (Exception e) {
759            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
760            return 0;
761        } finally {
762            dbc.clear();
763        }
764
765    }
766
767    /**
768     * Copies the access control entries of a given resource to a destination resource.<p>
769     *
770     * Already existing access control entries of the destination resource are removed.<p>
771     *
772     * @param context the current request context
773     * @param source the resource to copy the access control entries from
774     * @param destination the resource to which the access control entries are copied
775     *
776     * @throws CmsException if something goes wrong
777     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_CONTROL} required)
778     */
779    public void copyAccessControlEntries(CmsRequestContext context, CmsResource source, CmsResource destination)
780    throws CmsException, CmsSecurityException {
781
782        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
783        try {
784            checkOfflineProject(dbc);
785            checkPermissions(dbc, source, CmsPermissionSet.ACCESS_READ, true, CmsResourceFilter.ALL);
786            checkPermissions(dbc, destination, CmsPermissionSet.ACCESS_CONTROL, true, CmsResourceFilter.ALL);
787            m_driverManager.copyAccessControlEntries(dbc, source, destination, true);
788        } catch (Exception e) {
789            CmsRequestContext rc = context;
790            dbc.report(
791                null,
792                Messages.get().container(
793                    Messages.ERR_COPY_ACE_2,
794                    rc.removeSiteRoot(source.getRootPath()),
795                    rc.removeSiteRoot(destination.getRootPath())),
796                e);
797        } finally {
798            dbc.clear();
799        }
800    }
801
802    /**
803     * Copies a resource.<p>
804     *
805     * You must ensure that the destination path is an absolute, valid and
806     * existing VFS path. Relative paths from the source are currently not supported.<p>
807     *
808     * The copied resource will always be locked to the current user
809     * after the copy operation.<p>
810     *
811     * In case the target resource already exists, it is overwritten with the
812     * source resource.<p>
813     *
814     * The <code>siblingMode</code> parameter controls how to handle siblings
815     * during the copy operation.<br>
816     * Possible values for this parameter are: <br>
817     * <ul>
818     * <li><code>{@link org.opencms.file.CmsResource#COPY_AS_NEW}</code></li>
819     * <li><code>{@link org.opencms.file.CmsResource#COPY_AS_SIBLING}</code></li>
820     * <li><code>{@link org.opencms.file.CmsResource#COPY_PRESERVE_SIBLING}</code></li>
821     * </ul><p>
822     *
823     * @param context the current request context
824     * @param source the resource to copy
825     * @param destination the name of the copy destination with complete path
826     * @param siblingMode indicates how to handle siblings during copy
827     *
828     * @throws CmsException if something goes wrong
829     * @throws CmsSecurityException if resource could not be copied
830     *
831     * @see CmsObject#copyResource(String, String, CmsResource.CmsResourceCopyMode)
832     * @see org.opencms.file.types.I_CmsResourceType#copyResource(CmsObject, CmsSecurityManager, CmsResource, String, CmsResource.CmsResourceCopyMode)
833     */
834    public void copyResource(
835        CmsRequestContext context,
836        CmsResource source,
837        String destination,
838        CmsResource.CmsResourceCopyMode siblingMode)
839    throws CmsException, CmsSecurityException {
840
841        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
842        try {
843            checkOfflineProject(dbc);
844            checkPermissions(dbc, source, CmsPermissionSet.ACCESS_READ, true, CmsResourceFilter.ALL);
845            if (source.isFolder() && destination.startsWith(source.getRootPath())) {
846                throw new CmsVfsException(
847                    Messages.get().container(
848                        Messages.ERR_RECURSIVE_INCLUSION_2,
849                        dbc.removeSiteRoot(source.getRootPath()),
850                        dbc.removeSiteRoot(destination)));
851            }
852            // target permissions will be checked later
853            m_driverManager.copyResource(dbc, source, destination, siblingMode);
854        } catch (Exception e) {
855            dbc.report(
856                null,
857                Messages.get().container(
858                    Messages.ERR_COPY_RESOURCE_2,
859                    dbc.removeSiteRoot(source.getRootPath()),
860                    dbc.removeSiteRoot(destination)),
861                e);
862        } finally {
863            dbc.clear();
864        }
865    }
866
867    /**
868     * Copies a resource to the current project of the user.<p>
869     *
870     * @param context the current request context
871     * @param resource the resource to apply this operation to
872     *
873     * @throws CmsException if something goes wrong
874     * @throws CmsRoleViolationException if the current user does not have management access to the project
875     *
876     * @see org.opencms.file.types.I_CmsResourceType#copyResourceToProject(CmsObject, CmsSecurityManager, CmsResource)
877     */
878    public void copyResourceToProject(CmsRequestContext context, CmsResource resource)
879    throws CmsException, CmsRoleViolationException {
880
881        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
882        try {
883            checkOfflineProject(dbc);
884            checkManagerOfProjectRole(dbc, context.getCurrentProject());
885
886            m_driverManager.copyResourceToProject(dbc, resource);
887        } catch (Exception e) {
888            dbc.report(
889                null,
890                Messages.get().container(
891                    Messages.ERR_COPY_RESOURCE_TO_PROJECT_2,
892                    context.getSitePath(resource),
893                    context.getCurrentProject().getName()),
894                e);
895        } finally {
896            dbc.clear();
897        }
898    }
899
900    /**
901     * Counts the locked resources in this project.<p>
902     *
903     * @param context the current request context
904     * @param id the id of the project
905     *
906     * @return the amount of locked resources in this project
907     *
908     * @throws CmsException if something goes wrong
909     * @throws CmsRoleViolationException if the current user does not have management access to the project
910     */
911    public int countLockedResources(CmsRequestContext context, CmsUUID id)
912    throws CmsException, CmsRoleViolationException {
913
914        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
915        CmsProject project = null;
916        int result = 0;
917        try {
918            project = m_driverManager.readProject(dbc, id);
919            checkManagerOfProjectRole(dbc, project);
920            result = m_driverManager.countLockedResources(project);
921        } catch (Exception e) {
922            dbc.report(
923                null,
924                Messages.get().container(
925                    Messages.ERR_COUNT_LOCKED_RESOURCES_PROJECT_2,
926                    (project == null) ? "<failed to read>" : project.getName(),
927                    id),
928                e);
929        } finally {
930            dbc.clear();
931        }
932        return result;
933    }
934
935    /**
936     * Counts the total number of users which match the given search criteria.<p>
937     *
938     * @param requestContext the request context
939     * @param searchParams the search criteria object
940     *
941     * @return the number of users which match the search criteria
942     * @throws CmsException if something goes wrong
943     */
944    public long countUsers(CmsRequestContext requestContext, CmsUserSearchParameters searchParams) throws CmsException {
945
946        CmsDbContext dbc = m_dbContextFactory.getDbContext(requestContext);
947        try {
948            return m_driverManager.countUsers(dbc, searchParams);
949        } catch (Exception e) {
950            dbc.report(null, Messages.get().container(Messages.ERR_COUNT_USERS_0), e);
951            return -1;
952        } finally {
953            dbc.clear();
954        }
955    }
956
957    /**
958     * Creates a new user group.<p>
959     *
960     * @param context the current request context
961     * @param name the name of the new group
962     * @param description the description for the new group
963     * @param flags the flags for the new group
964     * @param parent the name of the parent group (or <code>null</code>)
965     *
966     * @return a <code>{@link CmsGroup}</code> object representing the newly created group
967     *
968     * @throws CmsException if operation was not successful.
969     * @throws CmsRoleViolationException if the  role {@link CmsRole#ACCOUNT_MANAGER} is not owned by the current user
970     */
971    public CmsGroup createGroup(CmsRequestContext context, String name, String description, int flags, String parent)
972    throws CmsException, CmsRoleViolationException {
973
974        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
975
976        CmsGroup result = null;
977        try {
978            checkRole(dbc, CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(name)));
979            result = m_driverManager.createGroup(dbc, new CmsUUID(), name, description, flags, parent);
980        } catch (Exception e) {
981            dbc.report(null, Messages.get().container(Messages.ERR_CREATE_GROUP_1, name), e);
982        } finally {
983            dbc.clear();
984        }
985        return result;
986    }
987
988    /**
989     * Creates a new organizational unit.<p>
990     *
991     * @param context the current request context
992     * @param ouFqn the fully qualified name of the new organizational unit
993     * @param description the description of the new organizational unit
994     * @param flags the flags for the new organizational unit
995     * @param resource the first associated resource
996     *
997     * @return a <code>{@link CmsOrganizationalUnit}</code> object representing
998     *          the newly created organizational unit
999     *
1000     * @throws CmsException if operation was not successful
1001     *
1002     * @see org.opencms.security.CmsOrgUnitManager#createOrganizationalUnit(CmsObject, String, String, int, String)
1003     */
1004    public CmsOrganizationalUnit createOrganizationalUnit(
1005        CmsRequestContext context,
1006        String ouFqn,
1007        String description,
1008        int flags,
1009        CmsResource resource)
1010    throws CmsException {
1011
1012        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1013        CmsOrganizationalUnit result = null;
1014        try {
1015            checkRole(dbc, CmsRole.ADMINISTRATOR.forOrgUnit(getParentOrganizationalUnit(ouFqn)));
1016            checkOfflineProject(dbc);
1017            result = m_driverManager.createOrganizationalUnit(
1018                dbc,
1019                CmsOrganizationalUnit.removeLeadingSeparator(ouFqn),
1020                description,
1021                flags,
1022                resource);
1023        } catch (Exception e) {
1024            dbc.report(null, Messages.get().container(Messages.ERR_CREATE_ORGUNIT_1, ouFqn), e);
1025        } finally {
1026            dbc.clear();
1027        }
1028        return result;
1029    }
1030
1031    /**
1032     * Creates a project.<p>
1033     *
1034     * @param context the current request context
1035     * @param name the name of the project to create
1036     * @param description the description of the project
1037     * @param groupname the project user group to be set
1038     * @param managergroupname the project manager group to be set
1039     * @param projecttype the type of the project
1040     *
1041     * @return the created project
1042     *
1043     * @throws CmsException if something goes wrong
1044     * @throws CmsRoleViolationException if the current user does not own the role {@link CmsRole#PROJECT_MANAGER}
1045     */
1046    public CmsProject createProject(
1047        CmsRequestContext context,
1048        String name,
1049        String description,
1050        String groupname,
1051        String managergroupname,
1052        CmsProject.CmsProjectType projecttype)
1053    throws CmsException, CmsRoleViolationException {
1054
1055        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1056        CmsProject result = null;
1057        try {
1058            checkRole(dbc, CmsRole.PROJECT_MANAGER.forOrgUnit(getParentOrganizationalUnit(name)));
1059            result = m_driverManager.createProject(
1060                dbc,
1061                CmsOrganizationalUnit.removeLeadingSeparator(name),
1062                description,
1063                CmsOrganizationalUnit.removeLeadingSeparator(groupname),
1064                CmsOrganizationalUnit.removeLeadingSeparator(managergroupname),
1065                projecttype);
1066        } catch (Exception e) {
1067            dbc.report(null, Messages.get().container(Messages.ERR_CREATE_PROJECT_1, name), e);
1068        } finally {
1069            dbc.clear();
1070        }
1071        return result;
1072    }
1073
1074    /**
1075     * Creates a property definition.<p>
1076     *
1077     * Property definitions are valid for all resource types.<p>
1078     *
1079     * @param context the current request context
1080     * @param name the name of the property definition to create
1081     *
1082     * @return the created property definition
1083     *
1084     * @throws CmsException if something goes wrong
1085     * @throws CmsSecurityException if the current project is online.
1086     * @throws CmsRoleViolationException if the current user does not own the role {@link CmsRole#WORKPLACE_MANAGER}
1087     */
1088    public CmsPropertyDefinition createPropertyDefinition(CmsRequestContext context, String name)
1089    throws CmsException, CmsSecurityException, CmsRoleViolationException {
1090
1091        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1092        CmsPropertyDefinition result = null;
1093
1094        try {
1095            checkOfflineProject(dbc);
1096            checkRole(dbc, CmsRole.WORKPLACE_MANAGER.forOrgUnit(null));
1097            result = m_driverManager.createPropertyDefinition(dbc, name);
1098        } catch (Exception e) {
1099            dbc.report(null, Messages.get().container(Messages.ERR_CREATE_PROPDEF_1, name), e);
1100        } finally {
1101            dbc.clear();
1102        }
1103        return result;
1104    }
1105
1106    /**
1107     * Creates a new resource with the provided content and properties.<p>
1108     * An exception is thrown if a resource with the given name already exists.<p>
1109     *
1110     * @param context the current request context
1111     * @param resourcePath the name of the resource to create (full path)
1112     * @param resource the new resource to create
1113     * @param content the content for the new resource
1114     * @param properties the properties for the new resource
1115    *
1116     * @return the created resource
1117     *
1118     * @throws CmsVfsResourceAlreadyExistsException if a resource with the given name already exists
1119     * @throws CmsVfsException if the project in the given database context is the "Online" project
1120     * @throws CmsException if something goes wrong
1121     */
1122    public CmsResource createResource(
1123        CmsRequestContext context,
1124        String resourcePath,
1125        CmsResource resource,
1126        byte[] content,
1127        List<CmsProperty> properties)
1128    throws CmsVfsResourceAlreadyExistsException, CmsVfsException, CmsException {
1129
1130        if (existsResource(context, resourcePath, CmsResourceFilter.IGNORE_EXPIRATION)) {
1131            // check if the resource already exists by name
1132            throw new CmsVfsResourceAlreadyExistsException(
1133                org.opencms.db.generic.Messages.get().container(
1134                    org.opencms.db.generic.Messages.ERR_RESOURCE_WITH_NAME_ALREADY_EXISTS_1,
1135                    resource.getRootPath()));
1136        }
1137        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1138        CmsResource newResource = null;
1139        try {
1140            checkOfflineProject(dbc);
1141            newResource = m_driverManager.createResource(dbc, resourcePath, resource, content, properties, false);
1142        } catch (Exception e) {
1143            dbc.report(
1144                null,
1145                Messages.get().container(Messages.ERR_IMPORT_RESOURCE_2, context.getSitePath(resource), resourcePath),
1146                e);
1147        } finally {
1148            dbc.clear();
1149        }
1150        return newResource;
1151    }
1152
1153    /**
1154     * Creates a new resource of the given resource type with the provided content and properties.<p>
1155     *
1156     * If the provided content is null and the resource is not a folder, the content will be set to an empty byte array.<p>
1157     *
1158     * @param context the current request context
1159     * @param resourcename the name of the resource to create (full path)
1160     * @param type the type of the resource to create
1161     * @param content the content for the new resource
1162     * @param properties the properties for the new resource
1163     *
1164     * @return the created resource
1165     *
1166     * @throws CmsException if something goes wrong
1167     *
1168     * @see org.opencms.file.types.I_CmsResourceType#createResource(CmsObject, CmsSecurityManager, String, byte[], List)
1169     */
1170    public synchronized CmsResource createResource(
1171        CmsRequestContext context,
1172        String resourcename,
1173        int type,
1174        byte[] content,
1175        List<CmsProperty> properties)
1176    throws CmsException {
1177
1178        String checkExistsPath = "/".equals(resourcename) ? "/" : CmsFileUtil.removeTrailingSeparator(resourcename);
1179        // We use checkExistsPath instead of resourcename because when creating a folder /foo/bar/, we want to fail
1180        // if a file /foo/bar already exists.
1181
1182        if (existsResource(context, checkExistsPath, CmsResourceFilter.ALL)) {
1183            // check if the resource already exists by name
1184            throw new CmsVfsResourceAlreadyExistsException(
1185                org.opencms.db.generic.Messages.get().container(
1186                    org.opencms.db.generic.Messages.ERR_RESOURCE_WITH_NAME_ALREADY_EXISTS_1,
1187                    resourcename));
1188        }
1189        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1190        CmsResource newResource = null;
1191        try {
1192            checkOfflineProject(dbc);
1193            newResource = m_driverManager.createResource(dbc, resourcename, type, content, properties);
1194        } catch (Exception e) {
1195            dbc.report(null, Messages.get().container(Messages.ERR_CREATE_RESOURCE_1, resourcename), e);
1196        } finally {
1197            dbc.clear();
1198        }
1199        return newResource;
1200    }
1201
1202    /**
1203     * Creates a new sibling of the source resource.<p>
1204     *
1205     * @param context the current request context
1206     * @param source the resource to create a sibling for
1207     * @param destination the name of the sibling to create with complete path
1208     * @param properties the individual properties for the new sibling
1209     *
1210     * @return the new created sibling
1211     *
1212     * @throws CmsException if something goes wrong
1213     *
1214     * @see org.opencms.file.types.I_CmsResourceType#createSibling(CmsObject, CmsSecurityManager, CmsResource, String, List)
1215     */
1216    public CmsResource createSibling(
1217        CmsRequestContext context,
1218        CmsResource source,
1219        String destination,
1220        List<CmsProperty> properties)
1221    throws CmsException {
1222
1223        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1224        CmsResource sibling = null;
1225        try {
1226            checkOfflineProject(dbc);
1227            sibling = m_driverManager.createSibling(dbc, source, destination, properties);
1228        } catch (Exception e) {
1229            dbc.report(
1230                null,
1231                Messages.get().container(Messages.ERR_CREATE_SIBLING_1, context.removeSiteRoot(source.getRootPath())),
1232                e);
1233        } finally {
1234            dbc.clear();
1235        }
1236        return sibling;
1237    }
1238
1239    /**
1240     * Creates the project for the temporary workplace files.<p>
1241     *
1242     * @param context the current request context
1243     *
1244     * @return the created project for the temporary workplace files
1245     *
1246     * @throws CmsException if something goes wrong
1247     */
1248    public CmsProject createTempfileProject(CmsRequestContext context) throws CmsException {
1249
1250        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1251
1252        CmsProject result = null;
1253        try {
1254            checkRole(dbc, CmsRole.PROJECT_MANAGER.forOrgUnit(null));
1255            result = m_driverManager.createTempfileProject(dbc);
1256        } catch (Exception e) {
1257            dbc.report(null, Messages.get().container(Messages.ERR_CREATE_TEMPFILE_PROJECT_0), e);
1258        } finally {
1259            dbc.clear();
1260        }
1261        return result;
1262    }
1263
1264    /**
1265     * Creates a new user.<p>
1266     *
1267     * @param context the current request context
1268     * @param name the name for the new user
1269     * @param password the password for the new user
1270     * @param description the description for the new user
1271     * @param additionalInfos the additional infos for the user
1272     *
1273     * @return the created user
1274     *
1275     * @see CmsObject#createUser(String, String, String, Map)
1276     *
1277     * @throws CmsException if something goes wrong
1278     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
1279     */
1280    public CmsUser createUser(
1281        CmsRequestContext context,
1282        String name,
1283        String password,
1284        String description,
1285        Map<String, Object> additionalInfos)
1286    throws CmsException, CmsRoleViolationException {
1287
1288        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1289
1290        CmsUser result = null;
1291        try {
1292            checkRole(dbc, CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(name)));
1293            result = m_driverManager.createUser(
1294                dbc,
1295                CmsOrganizationalUnit.removeLeadingSeparator(name),
1296                password,
1297                description,
1298                additionalInfos);
1299        } catch (Exception e) {
1300            dbc.report(null, Messages.get().container(Messages.ERR_CREATE_USER_1, name), e);
1301        } finally {
1302            dbc.clear();
1303        }
1304        return result;
1305    }
1306
1307    /**
1308     * Deletes alias entries matching a filter.<p>
1309     *
1310     * @param context the request context
1311     * @param filter the alias filter
1312     *
1313     * @throws CmsException if something goes wrong
1314     */
1315    public void deleteAliases(CmsRequestContext context, CmsAliasFilter filter) throws CmsException {
1316
1317        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1318        try {
1319            m_driverManager.deleteAliases(dbc, context.getCurrentProject(), filter);
1320        } catch (Exception e) {
1321            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
1322        } finally {
1323            dbc.clear();
1324        }
1325
1326    }
1327
1328    /**
1329     * Deletes all entries in the published resource table.<p>
1330     *
1331     * @param context the current request context
1332     * @param linkType the type of resource deleted (0= non-parameter, 1=parameter)
1333     *
1334     * @throws CmsException if something goes wrong
1335     */
1336    public void deleteAllStaticExportPublishedResources(CmsRequestContext context, int linkType) throws CmsException {
1337
1338        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1339        try {
1340            m_driverManager.deleteAllStaticExportPublishedResources(dbc, linkType);
1341        } catch (Exception e) {
1342            dbc.report(null, Messages.get().container(Messages.ERR_DELETE_STATEXP_PUBLISHED_RESOURCES_0), e);
1343        } finally {
1344            dbc.clear();
1345        }
1346    }
1347
1348    /**
1349     * Deletes a group, where all permissions, users and children of the group
1350     * are transfered to a replacement group.<p>
1351     *
1352     * @param context the current request context
1353     * @param groupId the id of the group to be deleted
1354     * @param replacementId the id of the group to be transfered, can be <code>null</code>
1355     *
1356     * @throws CmsException if operation was not successful
1357     * @throws CmsSecurityException if the group is a default group.
1358     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
1359     */
1360    public void deleteGroup(CmsRequestContext context, CmsUUID groupId, CmsUUID replacementId)
1361    throws CmsException, CmsRoleViolationException, CmsSecurityException {
1362
1363        CmsGroup group = readGroup(context, groupId);
1364        if (group.isRole()) {
1365            throw new CmsSecurityException(Messages.get().container(Messages.ERR_DELETE_ROLE_GROUP_1, group.getName()));
1366        }
1367        CmsDbContext dbc = null;
1368        try {
1369            dbc = getDbContextForDeletePrincipal(context);
1370            // catch own exception as special cause for general "Error deleting group".
1371            checkRole(dbc, CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(group.getName())));
1372            m_driverManager.deleteGroup(dbc, group, replacementId);
1373        } catch (Exception e) {
1374            CmsDbContext dbcForException = m_dbContextFactory.getDbContext(context);
1375            dbcForException.report(null, Messages.get().container(Messages.ERR_DELETE_GROUP_1, group.getName()), e);
1376            dbcForException.clear();
1377        } finally {
1378            if (null != dbc) {
1379                dbc.clear();
1380            }
1381        }
1382    }
1383
1384    /**
1385     * Delete a user group.<p>
1386     *
1387     * Only groups that contain no subgroups can be deleted.<p>
1388     *
1389     * @param context the current request context
1390     * @param name the name of the group that is to be deleted
1391     *
1392     * @throws CmsException if operation was not successful
1393     * @throws CmsSecurityException if the group is a default group.
1394     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
1395     */
1396    public void deleteGroup(CmsRequestContext context, String name)
1397    throws CmsException, CmsRoleViolationException, CmsSecurityException {
1398
1399        CmsGroup group = readGroup(context, name);
1400        if (group.isRole()) {
1401            throw new CmsSecurityException(Messages.get().container(Messages.ERR_DELETE_ROLE_GROUP_1, name));
1402        }
1403        CmsDbContext dbc = null;
1404        try {
1405            dbc = getDbContextForDeletePrincipal(context);
1406            // catch own exception as special cause for general "Error deleting group".
1407            checkRole(dbc, CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(name)));
1408            m_driverManager.deleteGroup(dbc, group, null);
1409        } catch (Exception e) {
1410            CmsDbContext dbcForException = m_dbContextFactory.getDbContext(context);
1411            dbcForException.report(null, Messages.get().container(Messages.ERR_DELETE_GROUP_1, name), e);
1412            dbcForException.clear();
1413        } finally {
1414            if (null != dbc) {
1415                dbc.clear();
1416            }
1417        }
1418
1419    }
1420
1421    /**
1422     * Deletes the versions from the history tables, keeping the given number of versions per resource.<p>
1423     *
1424     * @param context the current request context
1425     * @param versionsToKeep number of versions to keep, is ignored if negative
1426     * @param versionsDeleted number of versions to keep for deleted resources, is ignored if negative
1427     * @param timeDeleted deleted resources older than this will also be deleted, is ignored if negative
1428     * @param report the report for output logging
1429     *
1430     * @throws CmsException if operation was not successful
1431     * @throws CmsRoleViolationException if the current user does not own the role {@link CmsRole#WORKPLACE_MANAGER}
1432     */
1433    public void deleteHistoricalVersions(
1434        CmsRequestContext context,
1435        int versionsToKeep,
1436        int versionsDeleted,
1437        long timeDeleted,
1438        I_CmsReport report)
1439    throws CmsException, CmsRoleViolationException {
1440
1441        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1442        try {
1443            CmsFolder root = readFolder(dbc, "/", CmsResourceFilter.ALL);
1444            checkRole(dbc, CmsRole.WORKPLACE_MANAGER.forOrgUnit(null));
1445            checkPermissions(dbc, root, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL);
1446            m_driverManager.deleteHistoricalVersions(dbc, versionsToKeep, versionsDeleted, timeDeleted, report);
1447        } catch (Exception e) {
1448            dbc.report(
1449                null,
1450                Messages.get().container(
1451                    Messages.ERR_DELETE_HISTORY_4,
1452                    new Object[] {
1453                        "/",
1454                        new Integer(versionsToKeep),
1455                        new Integer(versionsDeleted),
1456                        new Date(timeDeleted)}),
1457                e);
1458        } finally {
1459            dbc.clear();
1460        }
1461    }
1462
1463    /**
1464     * Deletes all log entries matching the given filter.<p>
1465     *
1466     * @param context the current user context
1467     * @param filter the filter to use for deletion
1468     *
1469     * @throws CmsException if something goes wrong
1470     *
1471     * @see #getLogEntries(CmsRequestContext, CmsLogFilter)
1472     * @see CmsObject#deleteLogEntries(CmsLogFilter)
1473     */
1474    public void deleteLogEntries(CmsRequestContext context, CmsLogFilter filter) throws CmsException {
1475
1476        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1477        try {
1478            checkRole(dbc, CmsRole.WORKPLACE_MANAGER);
1479            m_driverManager.deleteLogEntries(dbc, filter);
1480        } catch (Exception e) {
1481            dbc.report(null, Messages.get().container(Messages.ERR_DELETE_LOG_0), e);
1482        } finally {
1483            dbc.clear();
1484        }
1485    }
1486
1487    /**
1488     * Deletes an organizational unit.<p>
1489     *
1490     * Only organizational units that contain no sub organizational unit can be deleted.<p>
1491     *
1492     * The organizational unit can not be delete if it is used in the request context,
1493     * or if the current user belongs to it.<p>
1494     *
1495     * All users and groups in the given organizational unit will be deleted.<p>
1496     *
1497     * @param context the current request context
1498     * @param organizationalUnit the organizational unit to delete
1499     *
1500     * @throws CmsException if operation was not successful
1501     *
1502     * @see org.opencms.security.CmsOrgUnitManager#deleteOrganizationalUnit(CmsObject, String)
1503     */
1504    public void deleteOrganizationalUnit(CmsRequestContext context, CmsOrganizationalUnit organizationalUnit)
1505    throws CmsException {
1506
1507        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1508        try {
1509            // check for root ou
1510            if (organizationalUnit.getParentFqn() == null) {
1511                throw new CmsDataAccessException(
1512                    org.opencms.security.Messages.get().container(
1513                        org.opencms.security.Messages.ERR_ORGUNIT_ROOT_EDITION_0));
1514            }
1515
1516            checkRole(dbc, CmsRole.ADMINISTRATOR.forOrgUnit(getParentOrganizationalUnit(organizationalUnit.getName())));
1517            checkOfflineProject(dbc);
1518            m_driverManager.deleteOrganizationalUnit(dbc, organizationalUnit);
1519        } catch (Exception e) {
1520            dbc.report(null, Messages.get().container(Messages.ERR_DELETE_ORGUNIT_1, organizationalUnit.getName()), e);
1521        } finally {
1522            dbc.clear();
1523        }
1524    }
1525
1526    /**
1527     * Deletes a project.<p>
1528     *
1529     * All modified resources currently inside this project will be reset to their online state.<p>
1530     *
1531     * @param context the current request context
1532     * @param projectId the ID of the project to be deleted
1533     *
1534     * @throws CmsException if something goes wrong
1535     * @throws CmsRoleViolationException if the current user does not own management access to the project
1536     */
1537    public void deleteProject(CmsRequestContext context, CmsUUID projectId)
1538    throws CmsException, CmsRoleViolationException {
1539
1540        if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) {
1541            // online project must not be deleted
1542            throw new CmsVfsException(
1543                org.opencms.file.Messages.get().container(
1544                    org.opencms.file.Messages.ERR_NOT_ALLOWED_IN_ONLINE_PROJECT_0));
1545        }
1546
1547        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1548        CmsProject deleteProject = null;
1549        try {
1550            // read the project that should be deleted
1551            deleteProject = m_driverManager.readProject(dbc, projectId);
1552            checkManagerOfProjectRole(dbc, deleteProject);
1553            m_driverManager.deleteProject(dbc, deleteProject);
1554        } catch (Exception e) {
1555            String projectName = (deleteProject == null ? String.valueOf(projectId) : deleteProject.getName());
1556            dbc.report(null, Messages.get().container(Messages.ERR_DELETE_PROJECT_1, projectName), e);
1557        } finally {
1558            dbc.clear();
1559        }
1560    }
1561
1562    /**
1563     * Deletes a property definition.<p>
1564     *
1565     * @param context the current request context
1566     * @param name the name of the property definition to delete
1567     *
1568     * @throws CmsException if something goes wrong
1569     * @throws CmsSecurityException if the project to delete is the "Online" project
1570     * @throws CmsRoleViolationException if the current user does not own the role {@link CmsRole#WORKPLACE_MANAGER}
1571     */
1572    public void deletePropertyDefinition(CmsRequestContext context, String name)
1573    throws CmsException, CmsSecurityException, CmsRoleViolationException {
1574
1575        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1576        try {
1577            checkOfflineProject(dbc);
1578            checkRole(dbc, CmsRole.WORKPLACE_MANAGER.forOrgUnit(null));
1579            m_driverManager.deletePropertyDefinition(dbc, name);
1580        } catch (Exception e) {
1581            dbc.report(null, Messages.get().container(Messages.ERR_DELETE_PROPERTY_1, name), e);
1582        } finally {
1583            dbc.clear();
1584        }
1585    }
1586
1587    /**
1588     * Deletes all relations for the given resource matching the given filter.<p>
1589     *
1590     * @param context the current user context
1591     * @param resource the resource to delete the relations for
1592     * @param filter the filter to use for deletion
1593     *
1594     * @throws CmsException if something goes wrong
1595     *
1596     * @see #addRelationToResource(CmsRequestContext, CmsResource, CmsResource, CmsRelationType, boolean)
1597     * @see CmsObject#deleteRelationsFromResource(String, CmsRelationFilter)
1598     */
1599    public void deleteRelationsForResource(CmsRequestContext context, CmsResource resource, CmsRelationFilter filter)
1600    throws CmsException {
1601
1602        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1603        try {
1604            checkOfflineProject(dbc);
1605            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
1606            m_driverManager.deleteRelationsForResource(dbc, resource, filter);
1607        } catch (Exception e) {
1608            dbc.report(
1609                null,
1610                Messages.get().container(Messages.ERR_DELETE_RELATIONS_1, dbc.removeSiteRoot(resource.getRootPath())),
1611                e);
1612        } finally {
1613            dbc.clear();
1614        }
1615    }
1616
1617    /**
1618     * Deletes a resource given its name.<p>
1619     *
1620     * The <code>siblingMode</code> parameter controls how to handle siblings
1621     * during the delete operation.<br>
1622     * Possible values for this parameter are: <br>
1623     * <ul>
1624     * <li><code>{@link CmsResource#DELETE_REMOVE_SIBLINGS}</code></li>
1625     * <li><code>{@link CmsResource#DELETE_PRESERVE_SIBLINGS}</code></li>
1626     * </ul><p>
1627     *
1628     * @param context the current request context
1629     * @param resource the name of the resource to delete (full path)
1630     * @param siblingMode indicates how to handle siblings of the deleted resource
1631     *
1632     * @throws CmsException if something goes wrong
1633     * @throws CmsSecurityException if the user does not have {@link CmsPermissionSet#ACCESS_WRITE} on the given resource
1634     *
1635     * @see org.opencms.file.types.I_CmsResourceType#deleteResource(CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceDeleteMode)
1636     */
1637    public void deleteResource(
1638        CmsRequestContext context,
1639        CmsResource resource,
1640        CmsResource.CmsResourceDeleteMode siblingMode)
1641    throws CmsException, CmsSecurityException {
1642
1643        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1644        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(context);
1645        final CmsUUID forbiddenFolderId = OpenCms.getPublishManager().getPublishListVerifier().addForbiddenParentFolder(
1646            resource.getRootPath(),
1647            Messages.get().getBundle(locale).key(Messages.ERR_FORBIDDEN_PARENT_CURRENTLY_DELETING_0));
1648        try {
1649            checkOfflineProject(dbc);
1650            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
1651            checkSystemLocks(dbc, resource);
1652
1653            // check write permissions for subresources in case of deleting a folder
1654            if (resource.isFolder()) {
1655                dbc.getRequestContext().setAttribute(I_CmsVfsDriver.REQ_ATTR_CHECK_PERMISSIONS, Boolean.TRUE);
1656                try {
1657                    m_driverManager.getVfsDriver(dbc).removeFolder(dbc, dbc.currentProject(), resource);
1658                } catch (CmsDataAccessException e) {
1659                    // unwrap the permission violation exception
1660                    if (e.getCause() instanceof CmsPermissionViolationException) {
1661                        throw (CmsPermissionViolationException)e.getCause();
1662                    } else {
1663                        throw e;
1664                    }
1665                }
1666                dbc.getRequestContext().removeAttribute(I_CmsVfsDriver.REQ_ATTR_CHECK_PERMISSIONS);
1667            }
1668
1669            deleteResource(dbc, resource, siblingMode);
1670        } catch (Exception e) {
1671            dbc.report(
1672                null,
1673                Messages.get().container(Messages.ERR_DELETE_RESOURCE_1, context.getSitePath(resource)),
1674                e);
1675        } finally {
1676            OpenCms.getPublishManager().getPublishListVerifier().removeForbiddenParentFolder(forbiddenFolderId);
1677            dbc.clear();
1678        }
1679    }
1680
1681    /**
1682     * Deletes an entry in the published resource table.<p>
1683     *
1684     * @param context the current request context
1685     * @param resourceName The name of the resource to be deleted in the static export
1686     * @param linkType the type of resource deleted (0= non-parameter, 1=parameter)
1687     * @param linkParameter the parameters of the resource
1688     *
1689     * @throws CmsException if something goes wrong
1690     */
1691    public void deleteStaticExportPublishedResource(
1692        CmsRequestContext context,
1693        String resourceName,
1694        int linkType,
1695        String linkParameter)
1696    throws CmsException {
1697
1698        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1699        try {
1700            m_driverManager.deleteStaticExportPublishedResource(dbc, resourceName, linkType, linkParameter);
1701        } catch (Exception e) {
1702            dbc.report(
1703                null,
1704                Messages.get().container(Messages.ERR_DELETE_STATEXP_PUBLISHES_RESOURCE_1, resourceName),
1705                e);
1706        } finally {
1707            dbc.clear();
1708        }
1709    }
1710
1711    /**
1712     * Deletes a user.<p>
1713     *
1714     * @param context the current request context
1715     * @param userId the Id of the user to be deleted
1716     *
1717     * @throws CmsException if something goes wrong
1718     */
1719    public void deleteUser(CmsRequestContext context, CmsUUID userId) throws CmsException {
1720
1721        CmsUser user = readUser(context, userId);
1722        deleteUser(context, user, null);
1723    }
1724
1725    /**
1726     * Deletes a user, where all permissions and resources attributes of the user
1727     * were transfered to a replacement user.<p>
1728     *
1729     * @param context the current request context
1730     * @param userId the id of the user to be deleted
1731     * @param replacementId the id of the user to be transfered
1732     *
1733     * @throws CmsException if operation was not successful
1734     */
1735    public void deleteUser(CmsRequestContext context, CmsUUID userId, CmsUUID replacementId) throws CmsException {
1736
1737        CmsUser user = readUser(context, userId);
1738        CmsUser replacementUser = null;
1739        if ((replacementId != null) && !replacementId.isNullUUID()) {
1740            replacementUser = readUser(context, replacementId);
1741        }
1742        deleteUser(context, user, replacementUser);
1743    }
1744
1745    /**
1746     * Deletes a user.<p>
1747     *
1748     * @param context the current request context
1749     * @param username the name of the user to be deleted
1750     *
1751     * @throws CmsException if something goes wrong
1752     */
1753    public void deleteUser(CmsRequestContext context, String username) throws CmsException {
1754
1755        CmsUser user = readUser(context, username);
1756        deleteUser(context, user, null);
1757    }
1758
1759    /**
1760     * Destroys this security manager.<p>
1761     *
1762     * @throws Throwable if something goes wrong
1763     */
1764    public synchronized void destroy() throws Throwable {
1765
1766        try {
1767            if (m_driverManager != null) {
1768                if (m_driverManager.getLockManager() != null) {
1769                    try {
1770                        writeLocks();
1771                    } catch (Throwable t) {
1772                        if (LOG.isErrorEnabled()) {
1773                            LOG.error(
1774                                org.opencms.lock.Messages.get().getBundle().key(
1775                                    org.opencms.lock.Messages.ERR_WRITE_LOCKS_FINAL_0),
1776                                t);
1777                        }
1778                    }
1779                }
1780                m_driverManager.destroy();
1781            }
1782        } catch (Throwable t) {
1783            if (LOG.isErrorEnabled()) {
1784                LOG.error(Messages.get().getBundle().key(Messages.LOG_ERR_DRIVER_MANAGER_CLOSE_0), t);
1785            }
1786        }
1787
1788        m_driverManager = null;
1789        m_dbContextFactory = null;
1790
1791        if (CmsLog.INIT.isInfoEnabled()) {
1792            CmsLog.INIT.info(
1793                Messages.get().getBundle().key(Messages.INIT_SECURITY_MANAGER_SHUTDOWN_1, this.getClass().getName()));
1794        }
1795    }
1796
1797    /**
1798     * Checks the availability of a resource in the VFS,
1799     * using the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
1800     *
1801     * A resource may be of type <code>{@link CmsFile}</code> or
1802     * <code>{@link CmsFolder}</code>.<p>
1803     *
1804     * The specified filter controls what kind of resources should be "found"
1805     * during the read operation. This will depend on the application. For example,
1806     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
1807     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
1808     * will ignore the date release / date expired information of the resource.<p>
1809     *
1810     * This method also takes into account the user permissions, so if
1811     * the given resource exists, but the current user has not the required
1812     * permissions, then this method will return <code>false</code>.<p>
1813     *
1814     * @param context the current request context
1815     * @param structureId the structure id of the resource to check
1816     * @param filter the resource filter to use while reading
1817     *
1818     * @return <code>true</code> if the resource is available
1819     *
1820     * @see CmsObject#existsResource(CmsUUID, CmsResourceFilter)
1821     * @see CmsObject#existsResource(CmsUUID)
1822     */
1823    public boolean existsResource(CmsRequestContext context, CmsUUID structureId, CmsResourceFilter filter) {
1824
1825        boolean result = false;
1826        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1827        try {
1828            readResource(dbc, structureId, filter);
1829            result = true;
1830        } catch (Exception e) {
1831            result = false;
1832        } finally {
1833            dbc.clear();
1834        }
1835        return result;
1836    }
1837
1838    /**
1839     * Checks the availability of a resource in the VFS,
1840     * using the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
1841     *
1842     * A resource may be of type <code>{@link CmsFile}</code> or
1843     * <code>{@link CmsFolder}</code>.<p>
1844     *
1845     * The specified filter controls what kind of resources should be "found"
1846     * during the read operation. This will depend on the application. For example,
1847     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
1848     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
1849     * will ignore the date release / date expired information of the resource.<p>
1850     *
1851     * This method also takes into account the user permissions, so if
1852     * the given resource exists, but the current user has not the required
1853     * permissions, then this method will return <code>false</code>.<p>
1854     *
1855     * @param context the current request context
1856     * @param resourcePath the name of the resource to read (full path)
1857     * @param filter the resource filter to use while reading
1858     *
1859     * @return <code>true</code> if the resource is available
1860     *
1861     * @see CmsObject#existsResource(String, CmsResourceFilter)
1862     * @see CmsObject#existsResource(String)
1863     */
1864    public boolean existsResource(CmsRequestContext context, String resourcePath, CmsResourceFilter filter) {
1865
1866        boolean result = false;
1867        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1868        try {
1869            readResource(dbc, resourcePath, filter);
1870            result = true;
1871        } catch (Exception e) {
1872            result = false;
1873        } finally {
1874            dbc.clear();
1875        }
1876        return result;
1877    }
1878
1879    /**
1880     * Fills the given publish list with the the VFS resources that actually get published.<p>
1881     *
1882     * Please refer to the source code of this method for the rules on how to decide whether a
1883     * new/changed/deleted <code>{@link CmsResource}</code> object can be published or not.<p>
1884     *
1885     * @param context the current request context
1886     * @param publishList must be initialized with basic publish information (Project or direct publish operation)
1887     *
1888     * @return the given publish list filled with all new/changed/deleted files from the current (offline) project
1889     *      that will be published actually
1890     *
1891     * @throws CmsException if something goes wrong
1892     *
1893     * @see org.opencms.db.CmsPublishList
1894     */
1895    public CmsPublishList fillPublishList(CmsRequestContext context, CmsPublishList publishList) throws CmsException {
1896
1897        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1898        try {
1899            m_driverManager.fillPublishList(dbc, publishList);
1900            checkPublishPermissions(dbc, publishList);
1901        } catch (CmsTooManyPublishResourcesException e) {
1902            throw e;
1903        } catch (Exception e) {
1904            if (publishList.isDirectPublish()) {
1905                dbc.report(
1906                    null,
1907                    Messages.get().container(
1908                        Messages.ERR_GET_PUBLISH_LIST_DIRECT_1,
1909                        CmsFileUtil.formatResourceNames(context, publishList.getDirectPublishResources())),
1910                    e);
1911            } else {
1912                dbc.report(
1913                    null,
1914                    Messages.get().container(
1915                        Messages.ERR_GET_PUBLISH_LIST_PROJECT_1,
1916                        context.getCurrentProject().getName()),
1917                    e);
1918            }
1919        } finally {
1920            dbc.clear();
1921        }
1922        return publishList;
1923    }
1924
1925    /**
1926     * Returns the list of access control entries of a resource given its name.<p>
1927     *
1928     * @param context the current request context
1929     * @param resource the resource to read the access control entries for
1930     * @param getInherited true if the result should include all access control entries inherited by parent folders
1931     *
1932     * @return a list of <code>{@link CmsAccessControlEntry}</code> objects defining all permissions for the given resource
1933     *
1934     * @throws CmsException if something goes wrong
1935     */
1936    public List<CmsAccessControlEntry> getAccessControlEntries(
1937        CmsRequestContext context,
1938        CmsResource resource,
1939        boolean getInherited)
1940    throws CmsException {
1941
1942        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1943        List<CmsAccessControlEntry> result = null;
1944        try {
1945            result = m_driverManager.getAccessControlEntries(dbc, resource, getInherited);
1946        } catch (Exception e) {
1947            dbc.report(
1948                null,
1949                Messages.get().container(Messages.ERR_GET_ACL_ENTRIES_1, context.getSitePath(resource)),
1950                e);
1951        } finally {
1952            dbc.clear();
1953        }
1954        return result;
1955    }
1956
1957    /**
1958     * Returns the access control list (summarized access control entries) of a given resource.<p>
1959     *
1960     * If <code>inheritedOnly</code> is set, only inherited access control entries are returned.<p>
1961     *
1962     * @param context the current request context
1963     * @param resource the resource
1964     * @param inheritedOnly skip non-inherited entries if set
1965     *
1966     * @return the access control list of the resource
1967     *
1968     * @throws CmsException if something goes wrong
1969     */
1970    public CmsAccessControlList getAccessControlList(
1971        CmsRequestContext context,
1972        CmsResource resource,
1973        boolean inheritedOnly)
1974    throws CmsException {
1975
1976        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
1977        CmsAccessControlList result = null;
1978        try {
1979            result = m_driverManager.getAccessControlList(dbc, resource, inheritedOnly);
1980        } catch (Exception e) {
1981            dbc.report(
1982                null,
1983                Messages.get().container(Messages.ERR_GET_ACL_ENTRIES_1, context.getSitePath(resource)),
1984                e);
1985
1986        } finally {
1987            dbc.clear();
1988        }
1989        return result;
1990    }
1991
1992    /**
1993     * Gets the aliases for a given site.<p>
1994     *
1995     * @param requestContext the current request context
1996     * @param siteRoot the site root
1997     *
1998     * @return the list of aliases for the given site root
1999     *
2000     * @throws CmsException if something goes wrong
2001     */
2002    public List<CmsAlias> getAliasesForSite(CmsRequestContext requestContext, String siteRoot) throws CmsException {
2003
2004        CmsDbContext dbc = m_dbContextFactory.getDbContext(requestContext);
2005        try {
2006            List<CmsAlias> aliases = m_driverManager.readAliasesBySite(
2007                dbc,
2008                requestContext.getCurrentProject(),
2009                siteRoot);
2010            return aliases;
2011        } catch (Exception e) {
2012            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
2013            return null; // will never be executed
2014        } finally {
2015            dbc.clear();
2016        }
2017    }
2018
2019    /**
2020     * Gets all access control entries.<p>
2021     *
2022     * @param context the current request context
2023     * @return the list of all access control entries
2024     *
2025     * @throws CmsException if something goes wrong
2026     */
2027    public List<CmsAccessControlEntry> getAllAccessControlEntries(CmsRequestContext context) throws CmsException {
2028
2029        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2030        List<CmsAccessControlEntry> result = null;
2031        try {
2032            result = m_driverManager.getAllAccessControlEntries(dbc);
2033        } catch (Exception e) {
2034            dbc.report(null, Messages.get().container(Messages.ERR_GET_ACL_ENTRIES_1, "<all resources>"), e);
2035        } finally {
2036            dbc.clear();
2037        }
2038        return result;
2039
2040    }
2041
2042    /**
2043     * Returns all projects which are owned by the current user or which are
2044     * accessible for the group of the user.<p>
2045     *
2046     * @param context the current request context
2047     * @param orgUnit the organizational unit to search project in
2048     * @param includeSubOus if to include sub organizational units
2049     *
2050     * @return a list of objects of type <code>{@link CmsProject}</code>
2051     *
2052     * @throws CmsException if something goes wrong
2053     */
2054    public List<CmsProject> getAllAccessibleProjects(
2055        CmsRequestContext context,
2056        CmsOrganizationalUnit orgUnit,
2057        boolean includeSubOus)
2058    throws CmsException {
2059
2060        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2061        List<CmsProject> result = null;
2062        try {
2063            result = m_driverManager.getAllAccessibleProjects(dbc, orgUnit, includeSubOus);
2064        } catch (Exception e) {
2065            dbc.report(
2066                null,
2067                Messages.get().container(Messages.ERR_GET_ALL_ACCESSIBLE_PROJECTS_1, dbc.currentUser().getName()),
2068                e);
2069        } finally {
2070            dbc.clear();
2071        }
2072        return result;
2073    }
2074
2075    /**
2076     * Returns a list with all projects from history.<p>
2077     *
2078     * @param context the current request context
2079     *
2080     * @return list of <code>{@link CmsHistoryProject}</code> objects
2081     *           with all projects from history.
2082     *
2083     * @throws CmsException if operation was not successful
2084     */
2085    public List<CmsHistoryProject> getAllHistoricalProjects(CmsRequestContext context) throws CmsException {
2086
2087        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2088        List<CmsHistoryProject> result = null;
2089        try {
2090            result = m_driverManager.getAllHistoricalProjects(dbc);
2091        } catch (Exception e) {
2092            dbc.report(
2093                null,
2094                Messages.get().container(Messages.ERR_GET_ALL_ACCESSIBLE_PROJECTS_1, dbc.currentUser().getName()),
2095                e);
2096        } finally {
2097            dbc.clear();
2098        }
2099        return result;
2100    }
2101
2102    /**
2103     * Returns all projects which are owned by the current user or which are manageable
2104     * for the group of the user.<p>
2105     *
2106     * @param context the current request context
2107     * @param orgUnit the organizational unit to search project in
2108     * @param includeSubOus if to include sub organizational units
2109     *
2110     * @return a list of objects of type <code>{@link CmsProject}</code>
2111     *
2112     * @throws CmsException if operation was not successful
2113     */
2114    public List<CmsProject> getAllManageableProjects(
2115        CmsRequestContext context,
2116        CmsOrganizationalUnit orgUnit,
2117        boolean includeSubOus)
2118    throws CmsException {
2119
2120        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2121        List<CmsProject> result = null;
2122        try {
2123            result = m_driverManager.getAllManageableProjects(dbc, orgUnit, includeSubOus);
2124        } catch (Exception e) {
2125            dbc.report(
2126                null,
2127                Messages.get().container(Messages.ERR_GET_ALL_MANAGEABLE_PROJECTS_1, dbc.currentUser().getName()),
2128                e);
2129        } finally {
2130            dbc.clear();
2131        }
2132        return result;
2133    }
2134
2135    /**
2136     * Returns all child groups of a group.<p>
2137     *
2138     * This method also returns all sub-child groups of the current group.<p>
2139     *
2140     * @param context the current request context
2141     * @param groupname the name of the group
2142     * @param includeSubChildren if set also returns all sub-child groups of the given group
2143     *
2144     * @return a list of all child <code>{@link CmsGroup}</code> objects or <code>null</code>
2145     *
2146     * @throws CmsException if operation was not successful
2147     */
2148    public List<CmsGroup> getChildren(CmsRequestContext context, String groupname, boolean includeSubChildren)
2149    throws CmsException {
2150
2151        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2152        List<CmsGroup> result = null;
2153        try {
2154            result = m_driverManager.getChildren(
2155                dbc,
2156                m_driverManager.readGroup(dbc, CmsOrganizationalUnit.removeLeadingSeparator(groupname)),
2157                includeSubChildren);
2158        } catch (Exception e) {
2159            dbc.report(null, Messages.get().container(Messages.ERR_GET_CHILD_GROUPS_TRANSITIVE_1, groupname), e);
2160        } finally {
2161            dbc.clear();
2162        }
2163        return result;
2164    }
2165
2166    /**
2167     * Gets a connection from a connection pool.<p>
2168     * @param poolUrl the connection pool url
2169     * @return a new connection from the pool
2170     *
2171     * @throws SQLException if getting the connection fails
2172     */
2173    public Connection getConnection(String poolUrl) throws SQLException {
2174
2175        CmsDbPoolV11 pool = CmsDriverManager.m_pools.get(poolUrl);
2176        return pool.getConnection();
2177
2178    }
2179
2180    /**
2181     * Returns the date when the resource was last visited by the user.<p>
2182     *
2183     * @param context the request context
2184     * @param poolName the name of the database pool to use
2185     * @param user the user to check the date
2186     * @param resource the resource to check the date
2187     *
2188     * @return the date when the resource was last visited by the user
2189     *
2190     * @throws CmsException if something goes wrong
2191     */
2192    public long getDateLastVisitedBy(CmsRequestContext context, String poolName, CmsUser user, CmsResource resource)
2193    throws CmsException {
2194
2195        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2196        long result = 0;
2197        try {
2198            result = m_driverManager.getDateLastVisitedBy(dbc, poolName, user, resource);
2199        } catch (Exception e) {
2200            dbc.report(
2201                null,
2202                Messages.get().container(
2203                    Messages.ERR_GET_DATE_LASTVISITED_2,
2204                    user.getName(),
2205                    context.getSitePath(resource)),
2206                e);
2207        } finally {
2208            dbc.clear();
2209        }
2210        return result;
2211    }
2212
2213    /**
2214     * Returns all groups of the given organizational unit.<p>
2215     *
2216     * @param context the current request context
2217     * @param orgUnit the organizational unit to get the groups for
2218     * @param includeSubOus if all groups of sub-organizational units should be retrieved too
2219     * @param readRoles if to read roles or groups
2220     *
2221     * @return all <code>{@link CmsGroup}</code> objects in the organizational unit
2222     *
2223     * @throws CmsException if operation was not successful
2224     *
2225     * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String)
2226     * @see org.opencms.security.CmsOrgUnitManager#getGroups(CmsObject, String, boolean)
2227     * @see org.opencms.security.CmsOrgUnitManager#getUsers(CmsObject, String, boolean)
2228     */
2229    public List<CmsGroup> getGroups(
2230        CmsRequestContext context,
2231        CmsOrganizationalUnit orgUnit,
2232        boolean includeSubOus,
2233        boolean readRoles)
2234    throws CmsException {
2235
2236        List<CmsGroup> result = null;
2237        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2238        try {
2239            result = m_driverManager.getGroups(dbc, orgUnit, includeSubOus, readRoles);
2240        } catch (Exception e) {
2241            dbc.report(null, Messages.get().container(Messages.ERR_READ_ORGUNIT_GROUPS_1, orgUnit.getName()), e);
2242        } finally {
2243            dbc.clear();
2244        }
2245        return result;
2246    }
2247
2248    /**
2249     * Returns the list of groups to which the user directly belongs to.<p>
2250     *
2251     * @param context the current request context
2252     * @param username The name of the user
2253     * @param ouFqn the fully qualified name of the organizational unit to restrict the result set for
2254     * @param includeChildOus include groups of child organizational units
2255     * @param readRoles if to read roles or groups
2256     * @param directGroupsOnly if set only the direct assigned groups will be returned, if not also indirect roles
2257     * @param remoteAddress the IP address to filter the groups in the result list
2258     *
2259     * @return a list of <code>{@link CmsGroup}</code> objects filtered by the given IP address
2260     *
2261     * @throws CmsException if operation was not successful
2262     */
2263    public List<CmsGroup> getGroupsOfUser(
2264        CmsRequestContext context,
2265        String username,
2266        String ouFqn,
2267        boolean includeChildOus,
2268        boolean readRoles,
2269        boolean directGroupsOnly,
2270        String remoteAddress)
2271    throws CmsException {
2272
2273        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2274        List<CmsGroup> result = null;
2275        try {
2276            result = m_driverManager.getGroupsOfUser(
2277                dbc,
2278                CmsOrganizationalUnit.removeLeadingSeparator(username),
2279                CmsOrganizationalUnit.removeLeadingSeparator(ouFqn),
2280                includeChildOus,
2281                readRoles,
2282                directGroupsOnly,
2283                remoteAddress);
2284        } catch (Exception e) {
2285            dbc.report(null, Messages.get().container(Messages.ERR_GET_GROUPS_OF_USER_2, username, remoteAddress), e);
2286        } finally {
2287            dbc.clear();
2288        }
2289        return result;
2290    }
2291
2292    /**
2293     * Returns the lock state of a resource.<p>
2294     *
2295     * @param context the current request context
2296     * @param resource the resource to return the lock state for
2297     *
2298     * @return the lock state of the resource
2299     *
2300     * @throws CmsException if something goes wrong
2301     */
2302    public CmsLock getLock(CmsRequestContext context, CmsResource resource) throws CmsException {
2303
2304        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2305        CmsLock result = null;
2306        try {
2307            result = m_driverManager.getLock(dbc, resource);
2308        } catch (Exception e) {
2309            dbc.report(null, Messages.get().container(Messages.ERR_GET_LOCK_1, context.getSitePath(resource)), e);
2310        } finally {
2311            dbc.clear();
2312        }
2313        return result;
2314    }
2315
2316    /**
2317     * Returns all locked resources in a given folder.<p>
2318     *
2319     * @param context the current request context
2320     * @param resource the folder to search in
2321     * @param filter the lock filter
2322     *
2323     * @return a list of locked resource paths (relative to current site)
2324     *
2325     * @throws CmsException if something goes wrong
2326     */
2327    public List<String> getLockedResources(CmsRequestContext context, CmsResource resource, CmsLockFilter filter)
2328    throws CmsException {
2329
2330        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2331        List<String> result = null;
2332        try {
2333            checkOfflineProject(dbc);
2334            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, false, CmsResourceFilter.ALL);
2335            result = m_driverManager.getLockedResources(dbc, resource, filter);
2336        } catch (Exception e) {
2337            dbc.report(
2338                null,
2339                Messages.get().container(Messages.ERR_COUNT_LOCKED_RESOURCES_FOLDER_1, context.getSitePath(resource)),
2340                e);
2341        } finally {
2342            dbc.clear();
2343        }
2344        return result;
2345    }
2346
2347    /**
2348     * Returns all locked resources in a given folder.<p>
2349     *
2350     * @param context the current request context
2351     * @param resource the folder to search in
2352     * @param filter the lock filter
2353     *
2354     * @return a list of locked resource paths (relative to current site)
2355     *
2356     * @throws CmsException if something goes wrong
2357     */
2358    public List<CmsResource> getLockedResourcesObjects(
2359        CmsRequestContext context,
2360        CmsResource resource,
2361        CmsLockFilter filter)
2362    throws CmsException {
2363
2364        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2365        List<CmsResource> result = null;
2366        try {
2367            checkOfflineProject(dbc);
2368            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, false, CmsResourceFilter.ALL);
2369            result = m_driverManager.getLockedResourcesObjects(dbc, resource, filter);
2370        } catch (Exception e) {
2371            dbc.report(
2372                null,
2373                Messages.get().container(Messages.ERR_COUNT_LOCKED_RESOURCES_FOLDER_1, context.getSitePath(resource)),
2374                e);
2375        } finally {
2376            dbc.clear();
2377        }
2378        return result;
2379    }
2380
2381    /**
2382     * Returns all locked resources in a given folder, but uses a cache for resource lookups.<p>
2383     *
2384     * @param context the current request context
2385     * @param resource the folder to search in
2386     * @param filter the lock filter
2387     * @param cache the cache to use
2388     *
2389     * @return a list of locked resource paths (relative to current site)
2390     *
2391     * @throws CmsException if something goes wrong
2392     */
2393    public List<CmsResource> getLockedResourcesObjectsWithCache(
2394        CmsRequestContext context,
2395        CmsResource resource,
2396        CmsLockFilter filter,
2397        Map<String, CmsResource> cache)
2398    throws CmsException {
2399
2400        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2401        List<CmsResource> result = null;
2402        try {
2403            checkOfflineProject(dbc);
2404            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, false, CmsResourceFilter.ALL);
2405            result = m_driverManager.getLockedResourcesObjectsWithCache(dbc, resource, filter, cache);
2406        } catch (Exception e) {
2407            dbc.report(
2408                null,
2409                Messages.get().container(Messages.ERR_COUNT_LOCKED_RESOURCES_FOLDER_1, context.getSitePath(resource)),
2410                e);
2411        } finally {
2412            dbc.clear();
2413        }
2414        return result;
2415    }
2416
2417    /**
2418     * Returns the lock manger.<p>
2419     *
2420     * @return the lock manager
2421     */
2422    public CmsLockManager getLockManager() {
2423
2424        return m_lockManager;
2425    }
2426
2427    /**
2428     * Returns all log entries matching the given filter.<p>
2429     *
2430     * @param context the current user context
2431     * @param filter the filter to match the log entries
2432     *
2433     * @return all log entries matching the given filter
2434     *
2435     * @throws CmsException if something goes wrong
2436     *
2437     * @see CmsObject#getLogEntries(CmsLogFilter)
2438     */
2439    public List<CmsLogEntry> getLogEntries(CmsRequestContext context, CmsLogFilter filter) throws CmsException {
2440
2441        List<CmsLogEntry> result = null;
2442        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2443        try {
2444            result = m_driverManager.getLogEntries(dbc, filter);
2445        } catch (Exception e) {
2446            dbc.report(null, Messages.get().container(Messages.ERR_READ_LOG_ENTRIES_0), e);
2447        } finally {
2448            dbc.clear();
2449        }
2450        return result;
2451    }
2452
2453    /**
2454     * Returns all resources of organizational units for which the current user has
2455     * the given role role.<p>
2456     *
2457     * @param context the current request context
2458     * @param role the role to check
2459     *
2460     * @return a list of {@link org.opencms.file.CmsResource} objects
2461     *
2462     * @throws CmsException if something goes wrong
2463     */
2464    public List<CmsResource> getManageableResources(CmsRequestContext context, CmsRole role) throws CmsException {
2465
2466        List<CmsResource> resources;
2467        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2468        try {
2469            resources = getManageableResources(dbc, role);
2470        } finally {
2471            dbc.clear();
2472        }
2473        return resources;
2474    }
2475
2476    /**
2477     * Returns all child organizational units of the given parent organizational unit including
2478     * hierarchical deeper organization units if needed.<p>
2479     *
2480     * @param context the current request context
2481     * @param parent the parent organizational unit
2482     * @param includeChildren if hierarchical deeper organization units should also be returned
2483     *
2484     * @return a list of <code>{@link CmsOrganizationalUnit}</code> objects
2485     *
2486     * @throws CmsException if operation was not successful
2487     *
2488     * @see org.opencms.security.CmsOrgUnitManager#getOrganizationalUnits(CmsObject, String, boolean)
2489     */
2490    public List<CmsOrganizationalUnit> getOrganizationalUnits(
2491        CmsRequestContext context,
2492        CmsOrganizationalUnit parent,
2493        boolean includeChildren)
2494    throws CmsException {
2495
2496        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2497        List<CmsOrganizationalUnit> result = null;
2498        try {
2499            result = m_driverManager.getOrganizationalUnits(dbc, parent, includeChildren);
2500        } catch (Exception e) {
2501            dbc.report(null, Messages.get().container(Messages.ERR_GET_ORGUNITS_1, parent.getName()), e);
2502        } finally {
2503            dbc.clear();
2504        }
2505        return result;
2506    }
2507
2508    /**
2509     * Returns all the organizational units for which the current user has the given role.<p>
2510     *
2511     * @param requestContext the current request context
2512     * @param role the role to check
2513     * @param includeSubOus if sub organizational units should be included in the search
2514     *
2515     * @return a list of {@link org.opencms.security.CmsOrganizationalUnit} objects
2516     *
2517     * @throws CmsException if something goes wrong
2518     */
2519    public List<CmsOrganizationalUnit> getOrgUnitsForRole(
2520        CmsRequestContext requestContext,
2521        CmsRole role,
2522        boolean includeSubOus)
2523    throws CmsException {
2524
2525        CmsDbContext dbc = m_dbContextFactory.getDbContext(requestContext);
2526        List<CmsOrganizationalUnit> result = null;
2527        try {
2528            result = m_driverManager.getOrgUnitsForRole(dbc, role, includeSubOus);
2529        } catch (Exception e) {
2530            dbc.report(
2531                null,
2532                Messages.get().container(Messages.ERR_GET_ORGUNITS_ROLE_1, role.getName(requestContext.getLocale())),
2533                e);
2534        } finally {
2535            dbc.clear();
2536        }
2537        return result;
2538    }
2539
2540    /**
2541     * Returns the parent group of a group.<p>
2542     *
2543     * @param context the current request context
2544     * @param groupname the name of the group
2545     *
2546     * @return group the parent group or <code>null</code>
2547     *
2548     * @throws CmsException if operation was not successful
2549     */
2550    public CmsGroup getParent(CmsRequestContext context, String groupname) throws CmsException {
2551
2552        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2553        CmsGroup result = null;
2554        try {
2555            result = m_driverManager.getParent(dbc, CmsOrganizationalUnit.removeLeadingSeparator(groupname));
2556        } catch (Exception e) {
2557            dbc.report(null, Messages.get().container(Messages.ERR_GET_PARENT_GROUP_1, groupname), e);
2558        } finally {
2559            dbc.clear();
2560        }
2561        return result;
2562    }
2563
2564    /**
2565     * Returns the set of permissions of the current user for a given resource.<p>
2566     *
2567     * @param context the current request context
2568     * @param resource the resource
2569     * @param user the user
2570     *
2571     * @return bit set with allowed permissions
2572     *
2573     * @throws CmsException if something goes wrong
2574     */
2575    public CmsPermissionSetCustom getPermissions(CmsRequestContext context, CmsResource resource, CmsUser user)
2576    throws CmsException {
2577
2578        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2579        CmsPermissionSetCustom result = null;
2580        try {
2581            result = m_driverManager.getPermissions(dbc, resource, user);
2582        } catch (Exception e) {
2583            dbc.report(
2584                null,
2585                Messages.get().container(Messages.ERR_GET_PERMISSIONS_2, user.getName(), context.getSitePath(resource)),
2586                e);
2587        } finally {
2588            dbc.clear();
2589        }
2590        return result;
2591    }
2592
2593    /**
2594     * Returns the uuid id for the given id,
2595     * remove this method as soon as possible.<p>
2596     *
2597     * @param context the current cms context
2598     * @param id the old project id
2599     *
2600     * @return the new uuid for the given id
2601     *
2602     * @throws CmsException if something goes wrong
2603     */
2604    public CmsUUID getProjectId(CmsRequestContext context, int id) throws CmsException {
2605
2606        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2607        CmsUUID result = null;
2608        try {
2609            result = m_driverManager.getProjectId(dbc, id);
2610        } catch (CmsException e) {
2611            dbc.report(null, e.getMessageContainer(), e);
2612        } finally {
2613            dbc.clear();
2614        }
2615        return result;
2616    }
2617
2618    /**
2619     * Returns a new publish list that contains the unpublished resources related
2620     * to all resources in the given publish list, the related resources exclude
2621     * all resources in the given publish list and also locked (by other users) resources.<p>
2622     *
2623     * @param context the current cms context
2624     * @param publishList the publish list to exclude from result
2625     * @param filter the relation filter to use to get the related resources
2626     *
2627     * @return a new publish list that contains the related resources
2628     *
2629     * @throws CmsException if something goes wrong
2630     *
2631     * @see org.opencms.publish.CmsPublishManager#getRelatedResourcesToPublish(CmsObject, CmsPublishList)
2632     */
2633    public CmsPublishList getRelatedResourcesToPublish(
2634        CmsRequestContext context,
2635        CmsPublishList publishList,
2636        CmsRelationFilter filter)
2637    throws CmsException {
2638
2639        if (!publishList.isDirectPublish()) {
2640            throw new CmsIllegalArgumentException(
2641                Messages.get().container(Messages.ERR_GET_RELATED_RESOURCES_PUBLISH_PROJECT_0));
2642        }
2643
2644        CmsPublishList ret = null;
2645        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2646        try {
2647            ret = m_driverManager.getRelatedResourcesToPublish(dbc, publishList, filter);
2648            checkPublishPermissions(dbc, ret);
2649        } catch (Exception e) {
2650            dbc.report(
2651                null,
2652                Messages.get().container(
2653                    Messages.ERR_GET_RELATED_RESOURCES_PUBLISH_DIRECT_1,
2654                    CmsFileUtil.formatResourceNames(context, publishList.getDirectPublishResources())),
2655                e);
2656        } finally {
2657            dbc.clear();
2658        }
2659        return ret;
2660    }
2661
2662    /**
2663     * Returns all relations for the given resource matching the given filter.<p>
2664     *
2665     * @param context the current user context
2666     * @param resource the resource to retrieve the relations for
2667     * @param filter the filter to match the relation
2668     *
2669     * @return all {@link org.opencms.relations.CmsRelation} objects for the given resource matching the given filter
2670     *
2671     * @throws CmsException if something goes wrong
2672     *
2673     * @see CmsObject#getRelationsForResource(String, CmsRelationFilter)
2674     */
2675    public List<CmsRelation> getRelationsForResource(
2676        CmsRequestContext context,
2677        CmsResource resource,
2678        CmsRelationFilter filter)
2679    throws CmsException {
2680
2681        List<CmsRelation> result = null;
2682        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2683        try {
2684            // check the access permissions
2685            if (resource != null) {
2686                checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_VIEW, false, CmsResourceFilter.ALL);
2687            }
2688            result = m_driverManager.getRelationsForResource(dbc, resource, filter);
2689        } catch (Exception e) {
2690            dbc.report(
2691                null,
2692                Messages.get().container(
2693                    Messages.ERR_READ_RELATIONS_1,
2694                    (resource != null) ? context.removeSiteRoot(resource.getRootPath()) : "null"),
2695                e);
2696        } finally {
2697            dbc.clear();
2698        }
2699        return result;
2700    }
2701
2702    /**
2703     * Returns all resources of the given organizational unit.<p>
2704     *
2705     * @param context the current request context
2706     * @param orgUnit the organizational unit to get all resources for
2707     *
2708     * @return all <code>{@link CmsResource}</code> objects in the organizational unit
2709     *
2710     * @throws CmsException if operation was not successful
2711     *
2712     * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String)
2713     * @see org.opencms.security.CmsOrgUnitManager#getGroups(CmsObject, String, boolean)
2714     * @see org.opencms.security.CmsOrgUnitManager#getUsers(CmsObject, String, boolean)
2715     */
2716    public List<CmsResource> getResourcesForOrganizationalUnit(CmsRequestContext context, CmsOrganizationalUnit orgUnit)
2717    throws CmsException {
2718
2719        List<CmsResource> result = null;
2720        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2721        try {
2722            result = m_driverManager.getResourcesForOrganizationalUnit(dbc, orgUnit);
2723        } catch (Exception e) {
2724            dbc.report(null, Messages.get().container(Messages.ERR_READ_ORGUNIT_RESOURCES_1, orgUnit.getName()), e);
2725        } finally {
2726            dbc.clear();
2727        }
2728        return result;
2729    }
2730
2731    /**
2732     * Returns all resources associated to a given principal via an ACE with the given permissions.<p>
2733     *
2734     * If the <code>includeAttr</code> flag is set it returns also all resources associated to
2735     * a given principal through some of following attributes.<p>
2736     *
2737     * <ul>
2738     *    <li>User Created</li>
2739     *    <li>User Last Modified</li>
2740     * </ul><p>
2741     *
2742     * @param context the current request context
2743     * @param principalId the id of the principal
2744     * @param permissions a set of permissions to match, can be <code>null</code> for all ACEs
2745     * @param includeAttr a flag to include resources associated by attributes
2746     *
2747     * @return a set of <code>{@link CmsResource}</code> objects
2748     *
2749     * @throws CmsException if something goes wrong
2750     */
2751    public Set<CmsResource> getResourcesForPrincipal(
2752        CmsRequestContext context,
2753        CmsUUID principalId,
2754        CmsPermissionSet permissions,
2755        boolean includeAttr)
2756    throws CmsException {
2757
2758        Set<CmsResource> dependencies;
2759        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2760        try {
2761            dependencies = m_driverManager.getResourcesForPrincipal(
2762                dbc,
2763                dbc.currentProject(),
2764                principalId,
2765                permissions,
2766                includeAttr);
2767        } catch (Exception e) {
2768            dbc.report(null, Messages.get().container(Messages.ERR_READ_RESOURCES_FOR_PRINCIPAL_LOG_1, principalId), e);
2769            dependencies = new HashSet<CmsResource>();
2770        } finally {
2771            dbc.clear();
2772        }
2773        return dependencies;
2774    }
2775
2776    /**
2777     * Gets the rewrite aliases matching a given filter.<p>
2778     *
2779     * @param requestContext the current request context
2780     * @param filter the filter used for selecting the rewrite aliases
2781     * @return the rewrite aliases matching the given filter
2782     *
2783     * @throws CmsException if something goes wrong
2784     */
2785    public List<CmsRewriteAlias> getRewriteAliases(CmsRequestContext requestContext, CmsRewriteAliasFilter filter)
2786    throws CmsException {
2787
2788        CmsDbContext dbc = m_dbContextFactory.getDbContext(requestContext);
2789        try {
2790            return m_driverManager.getRewriteAliases(dbc, filter);
2791        } catch (Exception e) {
2792            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
2793            return null; // will never be executed
2794        } finally {
2795            dbc.clear();
2796        }
2797
2798    }
2799
2800    /**
2801     * Gets the groups which constitute a given role.<p>
2802     *
2803     * @param context the request context
2804     * @param role the role
2805     * @param directUsersOnly if true, only direct users of the role group will be returned
2806     *
2807     * @return the role's groups
2808     *
2809     * @throws CmsException if something goes wrong
2810     */
2811    public Set<CmsGroup> getRoleGroups(CmsRequestContext context, CmsRole role, boolean directUsersOnly)
2812    throws CmsException {
2813
2814        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2815        try {
2816            return m_driverManager.getRoleGroups(dbc, role.getGroupName(), directUsersOnly);
2817        } catch (Exception e) {
2818            dbc.report(null, Messages.get().container(Messages.ERR_GET_ROLE_GROUPS_1, role.toString()), e);
2819            return null; // will never be executed
2820        } finally {
2821            dbc.clear();
2822        }
2823    }
2824
2825    /**
2826     * Returns all roles the given user has for the given resource.<p>
2827     *
2828     * @param context the current request context
2829     * @param user the user to check
2830     * @param resource the resource to check the roles for
2831     *
2832     * @return a list of {@link CmsRole} objects
2833     *
2834     * @throws CmsException is something goes wrong
2835     */
2836    public List<CmsRole> getRolesForResource(CmsRequestContext context, CmsUser user, CmsResource resource)
2837    throws CmsException {
2838
2839        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2840        List<CmsRole> result = null;
2841        try {
2842            result = m_driverManager.getRolesForResource(dbc, user, resource);
2843        } catch (Exception e) {
2844            dbc.report(
2845                null,
2846                Messages.get().container(
2847                    Messages.ERR_GET_ROLES_FOR_RESOURCE_2,
2848                    user.getName(),
2849                    context.getSitePath(resource)),
2850                e);
2851        } finally {
2852            dbc.clear();
2853        }
2854        return result;
2855    }
2856
2857    /**
2858     * Returns an instance of the common sql manager.<p>
2859     *
2860     * @return an instance of the common sql manager
2861     */
2862    public CmsSqlManager getSqlManager() {
2863
2864        return m_driverManager.getSqlManager();
2865    }
2866
2867    /**
2868     * Returns all users of the given organizational unit.<p>
2869     *
2870     * @param context the current request context
2871     * @param orgUnit the organizational unit to get the users for
2872     * @param recursive if all users of sub-organizational units should be retrieved too
2873     *
2874     * @return all <code>{@link CmsUser}</code> objects in the organizational unit
2875     *
2876     * @throws CmsException if operation was not successful
2877     *
2878     * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String)
2879     * @see org.opencms.security.CmsOrgUnitManager#getGroups(CmsObject, String, boolean)
2880     * @see org.opencms.security.CmsOrgUnitManager#getUsers(CmsObject, String, boolean)
2881     */
2882    public List<CmsUser> getUsers(CmsRequestContext context, CmsOrganizationalUnit orgUnit, boolean recursive)
2883    throws CmsException {
2884
2885        List<CmsUser> result = null;
2886        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2887        try {
2888            result = m_driverManager.getUsers(dbc, orgUnit, recursive);
2889        } catch (Exception e) {
2890            dbc.report(null, Messages.get().container(Messages.ERR_READ_ORGUNIT_USERS_1, orgUnit.getName()), e);
2891        } finally {
2892            dbc.clear();
2893        }
2894        return result;
2895    }
2896
2897    /**
2898     * Returns a list of users in a group.<p>
2899     *
2900     * @param context the current request context
2901     * @param groupname the name of the group to list users from
2902     * @param includeOtherOuUsers include users of other organizational units
2903     * @param directUsersOnly if set only the direct assigned users will be returned,
2904     *                          if not also indirect users, ie. members of child groups
2905     * @param readRoles if to read roles or groups
2906     *
2907     * @return all <code>{@link CmsUser}</code> objects in the group
2908     *
2909     * @throws CmsException if operation was not successful
2910     */
2911    public List<CmsUser> getUsersOfGroup(
2912        CmsRequestContext context,
2913        String groupname,
2914        boolean includeOtherOuUsers,
2915        boolean directUsersOnly,
2916        boolean readRoles)
2917    throws CmsException {
2918
2919        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2920        List<CmsUser> result = null;
2921        try {
2922            result = m_driverManager.getUsersOfGroup(
2923                dbc,
2924                CmsOrganizationalUnit.removeLeadingSeparator(groupname),
2925                includeOtherOuUsers,
2926                directUsersOnly,
2927                readRoles);
2928        } catch (Exception e) {
2929            dbc.report(null, Messages.get().container(Messages.ERR_GET_USERS_OF_GROUP_1, groupname), e);
2930        } finally {
2931            dbc.clear();
2932        }
2933        return result;
2934    }
2935
2936    /**
2937     * Returns the current user's publish list.<p>
2938     *
2939     * @param context the request context
2940     *
2941     * @return the current user's publish list
2942     *
2943     * @throws CmsException if something goes wrong
2944     */
2945    public List<CmsResource> getUsersPubList(CmsRequestContext context) throws CmsException {
2946
2947        List<CmsResource> result = null;
2948        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2949        try {
2950            result = m_driverManager.getUsersPubList(dbc, context.getCurrentUser().getId());
2951        } catch (Exception e) {
2952            dbc.report(
2953                null,
2954                Messages.get().container(Messages.ERR_READ_USER_PUBLIST_1, context.getCurrentUser().getName()),
2955                e);
2956
2957        } finally {
2958            dbc.clear();
2959        }
2960        return result;
2961    }
2962
2963    /**
2964     * Returns all users of the given organizational unit.<p>
2965     *
2966     * @param context the current request context
2967     * @param orgUnit the organizational unit to get the users for
2968     * @param recursive if all users of sub-organizational units should be retrieved too
2969     *
2970     * @return all <code>{@link CmsUser}</code> objects in the organizational unit
2971     *
2972     * @throws CmsException if operation was not successful
2973     *
2974     * @see org.opencms.security.CmsOrgUnitManager#getResourcesForOrganizationalUnit(CmsObject, String)
2975     * @see org.opencms.security.CmsOrgUnitManager#getGroups(CmsObject, String, boolean)
2976     * @see org.opencms.security.CmsOrgUnitManager#getUsers(CmsObject, String, boolean)
2977     */
2978    public List<CmsUser> getUsersWithoutAdditionalInfo(
2979        CmsRequestContext context,
2980        CmsOrganizationalUnit orgUnit,
2981        boolean recursive)
2982    throws CmsException {
2983
2984        List<CmsUser> result = null;
2985        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
2986        try {
2987            result = m_driverManager.getUsersWithoutAdditionalInfo(dbc, orgUnit, recursive);
2988        } catch (Exception e) {
2989            dbc.report(null, Messages.get().container(Messages.ERR_READ_ORGUNIT_USERS_1, orgUnit.getName()), e);
2990        } finally {
2991            dbc.clear();
2992        }
2993        return result;
2994    }
2995
2996    /**
2997     * Performs a non-blocking permission check on a resource.<p>
2998     *
2999     * This test will not throw an exception in case the required permissions are not
3000     * available for the requested operation. Instead, it will return one of the
3001     * following values:<ul>
3002     * <li><code>{@link I_CmsPermissionHandler#PERM_ALLOWED}</code></li>
3003     * <li><code>{@link I_CmsPermissionHandler#PERM_FILTERED}</code></li>
3004     * <li><code>{@link I_CmsPermissionHandler#PERM_DENIED}</code></li></ul><p>
3005     *
3006     * @param context the current request context
3007     * @param resource the resource on which permissions are required
3008     * @param requiredPermissions the set of permissions required for the operation
3009     * @param checkLock if true, a lock for the current user is required for
3010     *      all write operations, if false it's ok to write as long as the resource
3011     *      is not locked by another user
3012     * @param filter the resource filter to use
3013     *
3014     * @return <code>{@link I_CmsPermissionHandler#PERM_ALLOWED}</code> if the user has sufficient permissions on the resource
3015     *      for the requested operation
3016     *
3017     * @throws CmsException in case of i/o errors (NOT because of insufficient permissions)
3018     *
3019     * @see #hasPermissions(CmsDbContext, CmsResource, CmsPermissionSet, boolean, CmsResourceFilter)
3020     */
3021    public I_CmsPermissionHandler.CmsPermissionCheckResult hasPermissions(
3022        CmsRequestContext context,
3023        CmsResource resource,
3024        CmsPermissionSet requiredPermissions,
3025        boolean checkLock,
3026        CmsResourceFilter filter)
3027    throws CmsException {
3028
3029        I_CmsPermissionHandler.CmsPermissionCheckResult result = null;
3030        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3031        try {
3032            result = hasPermissions(
3033                dbc,
3034                resource,
3035                requiredPermissions,
3036                checkLock ? LockCheck.yes : LockCheck.no,
3037                filter);
3038        } finally {
3039            dbc.clear();
3040        }
3041        return result;
3042    }
3043
3044    /**
3045     * Performs a non-blocking permission check on a resource.<p>
3046     *
3047     * This test will not throw an exception in case the required permissions are not
3048     * available for the requested operation. Instead, it will return one of the
3049     * following values:<ul>
3050     * <li><code>{@link I_CmsPermissionHandler#PERM_ALLOWED}</code></li>
3051     * <li><code>{@link I_CmsPermissionHandler#PERM_FILTERED}</code></li>
3052     * <li><code>{@link I_CmsPermissionHandler#PERM_DENIED}</code></li></ul><p>
3053     *
3054     * @param context the current request context
3055     * @param resource the resource on which permissions are required
3056     * @param requiredPermissions the set of permissions required for the operation
3057     * @param checkLock if true, a lock for the current user is required for
3058     *      all write operations, if false it's ok to write as long as the resource
3059     *      is not locked by another user
3060     * @param filter the resource filter to use
3061     *
3062     * @return <code>{@link I_CmsPermissionHandler#PERM_ALLOWED}</code> if the user has sufficient permissions on the resource
3063     *      for the requested operation
3064     *
3065     * @throws CmsException in case of i/o errors (NOT because of insufficient permissions)
3066     *
3067     * @see #hasPermissions(CmsDbContext, CmsResource, CmsPermissionSet, boolean, CmsResourceFilter)
3068     */
3069    public I_CmsPermissionHandler.CmsPermissionCheckResult hasPermissions(
3070        CmsRequestContext context,
3071        CmsResource resource,
3072        CmsPermissionSet requiredPermissions,
3073        LockCheck checkLock,
3074        CmsResourceFilter filter)
3075    throws CmsException {
3076
3077        I_CmsPermissionHandler.CmsPermissionCheckResult result = null;
3078        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3079        try {
3080            result = hasPermissions(dbc, resource, requiredPermissions, checkLock, filter);
3081        } finally {
3082            dbc.clear();
3083        }
3084        return result;
3085    }
3086
3087    /**
3088     * Checks if the given user has the given role in the given organizational unit.<p>
3089     *
3090     * If the organizational unit is <code>null</code>, this method will check if the
3091     * given user has the given role for at least one organizational unit.<p>
3092     *
3093     * @param dbc the current OpenCms users database context
3094     * @param user the user to check the role for
3095     * @param role the role to check
3096     *
3097     * @return <code>true</code> if the given user has the given role in the given organizational unit
3098     */
3099    public boolean hasRole(CmsDbContext dbc, CmsUser user, CmsRole role) {
3100
3101        // try to read from cache
3102        String key = role.getGroupName() + "," + role.getOuFqn();
3103        Boolean result = OpenCms.getMemoryMonitor().getGroupListCache().getHasRole(user.getId(), key);
3104        if (result != null) {
3105            return result.booleanValue();
3106        }
3107
3108        // read all roles of the current user
3109        List<CmsGroup> roles;
3110        try {
3111            roles = m_driverManager.getGroupsOfUser(
3112                dbc,
3113                user.getName(),
3114                "",
3115                true,
3116                true,
3117                false,
3118                dbc.getRequestContext().getRemoteAddress());
3119        } catch (CmsException e) {
3120            if (LOG.isErrorEnabled()) {
3121                LOG.error(e.getLocalizedMessage(), e);
3122            }
3123            // any exception: return false
3124            return false;
3125        }
3126
3127        boolean hasRole = hasRole(role, roles);
3128
3129        // hack: require individual user based confirmation for certain roles
3130        // this is for updated older systems where content managers have been WORKPLACE_USER only
3131        // to prevent access to certain ADE management functions
3132        if (hasRole && ((CmsRole.CATEGORY_EDITOR.equals(role)) || (CmsRole.GALLERY_EDITOR.equals(role)))) {
3133            String info = CmsRole.CONFIRM_ROLE_PREFIX + role.getRoleName();
3134            Object prop = OpenCms.getRuntimeProperty(info);
3135            if ((prop != null) && Boolean.valueOf(prop.toString()).booleanValue()) {
3136                // individual user based confirmation for the role is required
3137                // if the user is a WORKPLACE_USER
3138                Object val = user.getAdditionalInfo(info);
3139                if ((val == null) || !Boolean.valueOf(val.toString()).booleanValue()) {
3140                    // no individual user confirmation present
3141                    if (hasRole(CmsRole.WORKPLACE_USER, roles)
3142                        && !hasRole(CmsRole.DEVELOPER, roles)
3143                        && !hasRole(CmsRole.PROJECT_MANAGER, roles)
3144                        && !hasRole(CmsRole.ACCOUNT_MANAGER, roles)) {
3145                        // user is a WORKPLACE_USER, confirmation is required but not present
3146                        hasRole = false;
3147                    }
3148                }
3149            }
3150        }
3151
3152        result = Boolean.valueOf(hasRole);
3153        OpenCms.getMemoryMonitor().getGroupListCache().setHasRole(user, key, result);
3154        return result.booleanValue();
3155    }
3156
3157    /**
3158     * Checks if the given user has the given role in the given organizational unit.<p>
3159     *
3160     * If the organizational unit is <code>null</code>, this method will check if the
3161     * given user has the given role for at least one organizational unit.<p>
3162     *
3163     * @param context the current request context
3164     * @param user the user to check the role for
3165     * @param role the role to check
3166     *
3167     * @return <code>true</code> if the given user has the given role in the given organizational unit
3168     */
3169    public boolean hasRole(CmsRequestContext context, CmsUser user, CmsRole role) {
3170
3171        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3172        boolean result;
3173        try {
3174            result = hasRole(dbc, user, role);
3175        } finally {
3176            dbc.clear();
3177        }
3178        return result;
3179    }
3180
3181    /**
3182     * Checks if the given user has the given role for the given resource.<p>
3183     *
3184     * @param dbc the current OpenCms users database context
3185     * @param user the user to check the role for
3186     * @param role the role to check
3187     * @param resource the resource to check the role for
3188     *
3189     * @return <code>true</code> if the given user has the given role for the given resource
3190     */
3191    public boolean hasRoleForResource(CmsDbContext dbc, CmsUser user, CmsRole role, CmsResource resource) {
3192
3193        // guest user has no role
3194        if (user.isGuestUser()) {
3195            return false;
3196        }
3197
3198        // try to read from cache
3199
3200        // ***
3201        // NOTE: We do intentionally *not* use the new group list cache here, as we have no good way to limit it at the moment, and this might generate a large amount of entries
3202        // ***
3203        String key = user.getId().toString() + role.getGroupName() + resource.getRootPath();
3204        Boolean result = OpenCms.getMemoryMonitor().getCachedRole(key);
3205        if (result != null) {
3206            return result.booleanValue();
3207        }
3208
3209        // read all roles of the current user
3210        List<CmsGroup> roles;
3211        try {
3212            roles = new ArrayList<CmsGroup>(
3213                m_driverManager.getGroupsOfUser(
3214                    dbc,
3215                    user.getName(),
3216                    "",
3217                    true,
3218                    true,
3219                    true,
3220                    dbc.getRequestContext().getRemoteAddress()));
3221        } catch (CmsException e) {
3222            if (LOG.isErrorEnabled()) {
3223                LOG.error(e.getLocalizedMessage(), e);
3224            }
3225            // any exception: return false
3226            return false;
3227        }
3228
3229        // first check the user has the role at all
3230        if (!hasRole(role.forOrgUnit(null), roles)) {
3231            result = Boolean.FALSE;
3232        }
3233
3234        // then check if one applies to the given resource
3235        Iterator<CmsGroup> it = roles.iterator();
3236        while ((result == null) && it.hasNext()) {
3237            CmsGroup group = it.next();
3238            CmsRole givenRole = CmsRole.valueOf(group);
3239            if (hasRole(role.forOrgUnit(null), Collections.singletonList(group))) {
3240                // we have the same role, now check the resource if needed
3241                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(givenRole.getOuFqn())) {
3242                    try {
3243                        CmsOrganizationalUnit orgUnit = m_driverManager.readOrganizationalUnit(
3244                            dbc,
3245                            givenRole.getOuFqn());
3246                        Iterator<CmsResource> itResources = m_driverManager.getResourcesForOrganizationalUnit(
3247                            dbc,
3248                            orgUnit).iterator();
3249                        while (itResources.hasNext()) {
3250                            CmsResource givenResource = itResources.next();
3251                            if (resource.getRootPath().startsWith(givenResource.getRootPath())) {
3252                                result = Boolean.TRUE;
3253                                break;
3254                            }
3255                        }
3256                    } catch (CmsException e) {
3257                        if (LOG.isErrorEnabled()) {
3258                            LOG.error(e.getLocalizedMessage(), e);
3259                        }
3260                        // ignore
3261                    }
3262                } else {
3263                    result = Boolean.TRUE;
3264                }
3265            }
3266        }
3267
3268        if (result == null) {
3269            result = Boolean.FALSE;
3270        }
3271        OpenCms.getMemoryMonitor().cacheRole(key, result.booleanValue());
3272        return result.booleanValue();
3273    }
3274
3275    /**
3276     * Checks if the given user has the given role for the given resource.<p>
3277     *
3278     * @param context the current request context
3279     * @param user the user to check
3280     * @param role the role to check
3281     * @param resource the resource to check the role for
3282     *
3283     * @return <code>true</code> if the given user has the given role for the given resource
3284     */
3285    public boolean hasRoleForResource(CmsRequestContext context, CmsUser user, CmsRole role, CmsResource resource) {
3286
3287        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3288        boolean result;
3289        try {
3290            result = hasRoleForResource(dbc, user, role, resource);
3291        } finally {
3292            dbc.clear();
3293        }
3294        return result;
3295    }
3296
3297    /**
3298     * Writes a list of access control entries as new access control entries of a given resource.<p>
3299     *
3300     * Already existing access control entries of this resource are removed before.<p>
3301     *
3302     * Access is granted, if:<p>
3303     * <ul>
3304     * <li>the current user has control permission on the resource</li>
3305     * </ul><p>
3306     *
3307     * @param context the current request context
3308     * @param resource the resource
3309     * @param acEntries a list of <code>{@link CmsAccessControlEntry}</code> objects
3310     *
3311     * @throws CmsException if something goes wrong
3312     * @throws CmsSecurityException if the required permissions are not satisfied
3313     */
3314    public void importAccessControlEntries(
3315        CmsRequestContext context,
3316        CmsResource resource,
3317        List<CmsAccessControlEntry> acEntries)
3318    throws CmsException, CmsSecurityException {
3319
3320        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3321        try {
3322            checkOfflineProject(dbc);
3323            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_CONTROL, true, CmsResourceFilter.ALL);
3324            m_driverManager.importAccessControlEntries(dbc, resource, acEntries);
3325        } catch (Exception e) {
3326            dbc.report(
3327                null,
3328                Messages.get().container(Messages.ERR_IMPORT_ACL_ENTRIES_1, context.getSitePath(resource)),
3329                e);
3330        } finally {
3331            dbc.clear();
3332        }
3333    }
3334
3335    /**
3336     * Creates a new resource with the provided content and properties.<p>
3337     *
3338     * The <code>content</code> parameter may be null if the resource id already exists.
3339     * If so, the created resource will be made a sibling of the existing resource,
3340     * the existing content will remain unchanged.
3341     * This is used during file import for import of siblings as the
3342     * <code>manifest.xml</code> only contains one binary copy per file.
3343     * If the resource id exists but the <code>content</code> is not null,
3344     * the created resource will be made a sibling of the existing resource,
3345     * and both will share the new content.<p>
3346     *
3347     * @param context the current request context
3348     * @param resourcePath the name of the resource to create (full path)
3349     * @param resource the new resource to create
3350     * @param content the content for the new resource
3351     * @param properties the properties for the new resource
3352     * @param importCase if <code>true</code>, signals that this operation is done while importing resource,
3353     *                   causing different lock behavior and potential "lost and found" usage
3354     *
3355     * @return the created resource
3356     *
3357     * @throws CmsException if something goes wrong
3358     */
3359    public CmsResource importResource(
3360        CmsRequestContext context,
3361        String resourcePath,
3362        CmsResource resource,
3363        byte[] content,
3364        List<CmsProperty> properties,
3365        boolean importCase)
3366    throws CmsException {
3367
3368        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3369        CmsResource newResource = null;
3370        try {
3371            checkOfflineProject(dbc);
3372            newResource = m_driverManager.createResource(dbc, resourcePath, resource, content, properties, importCase);
3373        } catch (Exception e) {
3374            dbc.report(
3375                null,
3376                Messages.get().container(Messages.ERR_IMPORT_RESOURCE_2, context.getSitePath(resource), resourcePath),
3377                e);
3378        } finally {
3379            dbc.clear();
3380        }
3381        return newResource;
3382    }
3383
3384    /**
3385     * Imports a rewrite alias.<p>
3386     *
3387     * @param requestContext the current request context
3388     * @param siteRoot the site root
3389     * @param source the rewrite alias source
3390     * @param target the rewrite alias target
3391     * @param mode the alias mode
3392     * @return the import result
3393     *
3394     * @throws CmsException if something goes wrong
3395     */
3396    public CmsAliasImportResult importRewriteAlias(
3397        CmsRequestContext requestContext,
3398        String siteRoot,
3399        String source,
3400        String target,
3401        CmsAliasMode mode)
3402    throws CmsException {
3403
3404        CmsDbContext dbc = m_dbContextFactory.getDbContext(requestContext);
3405        try {
3406            return m_driverManager.importRewriteAlias(dbc, siteRoot, source, target, mode);
3407        } catch (Exception e) {
3408            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
3409            return null;
3410        } finally {
3411            dbc.clear();
3412        }
3413    }
3414
3415    /**
3416     * Creates a new user by import.<p>
3417     *
3418     * @param context the current request context
3419     * @param id the id of the user
3420     * @param name the new name for the user
3421     * @param password the new password for the user
3422     * @param firstname the first name of the user
3423     * @param lastname the last name of the user
3424     * @param email the email of the user
3425     * @param flags the flags for a user (for example <code>{@link I_CmsPrincipal#FLAG_ENABLED}</code>)
3426     * @param dateCreated the creation date
3427     * @param additionalInfos the additional user infos
3428     *
3429     * @return the imported user
3430     *
3431     * @throws CmsException if something goes wrong
3432     * @throws CmsRoleViolationException if the  role {@link CmsRole#ACCOUNT_MANAGER} is not owned by the current user.
3433     */
3434    public CmsUser importUser(
3435        CmsRequestContext context,
3436        String id,
3437        String name,
3438        String password,
3439        String firstname,
3440        String lastname,
3441        String email,
3442        int flags,
3443        long dateCreated,
3444        Map<String, Object> additionalInfos)
3445    throws CmsException, CmsRoleViolationException {
3446
3447        CmsUser newUser = null;
3448
3449        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3450
3451        try {
3452            checkRole(dbc, CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(name)));
3453            newUser = m_driverManager.importUser(
3454                dbc,
3455                id,
3456                CmsOrganizationalUnit.removeLeadingSeparator(name),
3457                password,
3458                firstname,
3459                lastname,
3460                email,
3461                flags,
3462                dateCreated,
3463                additionalInfos);
3464
3465        } catch (Exception e) {
3466            dbc.report(
3467                null,
3468                Messages.get().container(
3469                    Messages.ERR_IMPORT_USER_7,
3470                    new Object[] {
3471                        name,
3472                        firstname,
3473                        lastname,
3474                        email,
3475                        new Integer(flags),
3476                        new Date(dateCreated),
3477                        additionalInfos}),
3478                e);
3479        } finally {
3480            dbc.clear();
3481        }
3482
3483        return newUser;
3484    }
3485
3486    /**
3487     * Increments a counter and returns its old value.<p>
3488     *
3489     * @param context the request context
3490     * @param name the name of the counter
3491     *
3492     * @return the value of the counter before incrementing
3493     *
3494     * @throws CmsException if something goes wrong
3495     */
3496    public int incrementCounter(CmsRequestContext context, String name) throws CmsException {
3497
3498        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3499        try {
3500            return m_driverManager.incrementCounter(dbc, name);
3501        } catch (Exception e) {
3502            dbc.report(null, Messages.get().container(Messages.ERR_INCREMENT_COUNTER_1, name), e);
3503            return -1; // will never be reached
3504        } finally {
3505            dbc.clear();
3506        }
3507    }
3508
3509    /**
3510     * Initializes this security manager with a given runtime info factory.<p>
3511     *
3512     * @param configurationManager the configurationManager
3513     * @param dbContextFactory the initialized OpenCms runtime info factory
3514     * @param publishEngine the publish engine
3515     *
3516     * @throws CmsInitException if the initialization fails
3517     */
3518    public void init(
3519        CmsConfigurationManager configurationManager,
3520        I_CmsDbContextFactory dbContextFactory,
3521        CmsPublishEngine publishEngine)
3522    throws CmsInitException {
3523
3524        if (dbContextFactory == null) {
3525            throw new CmsInitException(
3526                org.opencms.main.Messages.get().container(org.opencms.main.Messages.ERR_CRITICAL_NO_DB_CONTEXT_0));
3527        }
3528
3529        m_dbContextFactory = dbContextFactory;
3530
3531        CmsSystemConfiguration systemConfiguration = (CmsSystemConfiguration)configurationManager.getConfiguration(
3532            CmsSystemConfiguration.class);
3533
3534        // create the driver manager
3535        m_driverManager = CmsDriverManager.newInstance(configurationManager, this, dbContextFactory, publishEngine);
3536
3537        try {
3538            // invoke the init method of the driver manager
3539            m_driverManager.init(configurationManager, dbContextFactory);
3540            if (CmsLog.INIT.isInfoEnabled()) {
3541                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_PHASE4_OK_0));
3542            }
3543        } catch (Exception exc) {
3544            CmsMessageContainer message = Messages.get().container(Messages.LOG_ERR_DRIVER_MANAGER_START_0);
3545            if (LOG.isFatalEnabled()) {
3546                LOG.fatal(message.key(), exc);
3547            }
3548            throw new CmsInitException(message, exc);
3549        }
3550
3551        // create a new lock manager
3552        m_lockManager = m_driverManager.getLockManager();
3553
3554        // initialize the permission handler
3555        String permHandlerClassName = systemConfiguration.getPermissionHandler();
3556        if (permHandlerClassName == null) {
3557            // use default implementation
3558            m_permissionHandler = new CmsDefaultPermissionHandler();
3559        } else {
3560            // use configured permission handler
3561            try {
3562                m_permissionHandler = (I_CmsPermissionHandler)Class.forName(permHandlerClassName).newInstance();
3563            } catch (Exception e) {
3564                throw new CmsInitException(
3565                    org.opencms.main.Messages.get().container(
3566                        org.opencms.main.Messages.ERR_CRITICAL_CLASS_CREATION_1,
3567                        permHandlerClassName),
3568                    e);
3569            }
3570        }
3571
3572        m_permissionHandler.init(m_driverManager, systemConfiguration);
3573
3574        if (CmsLog.INIT.isInfoEnabled()) {
3575            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SECURITY_MANAGER_INIT_0));
3576        }
3577    }
3578
3579    /**
3580     * Initializes the default groups for an organizational unit.<p>
3581     *
3582     * @param context the request context
3583     * @param ou the organizational unit
3584     */
3585    public void initializeOrgUnit(CmsRequestContext context, CmsOrganizationalUnit ou) {
3586
3587        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3588        m_driverManager.initOrgUnit(dbc, ou);
3589
3590    }
3591
3592    /**
3593     * Checks if the specified resource is inside the current project.<p>
3594     *
3595     * The project "view" is determined by a set of path prefixes.
3596     * If the resource starts with any one of this prefixes, it is considered to
3597     * be "inside" the project.<p>
3598     *
3599     * @param context the current request context
3600     * @param resourcename the specified resource name (full path)
3601     *
3602     * @return <code>true</code>, if the specified resource is inside the current project
3603     */
3604    public boolean isInsideCurrentProject(CmsRequestContext context, String resourcename) {
3605
3606        boolean result = false;
3607        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3608        try {
3609            result = m_driverManager.isInsideCurrentProject(dbc, resourcename);
3610        } finally {
3611            dbc.clear();
3612        }
3613        return result;
3614    }
3615
3616    /**
3617     * Checks if the current user has management access to the current project.<p>
3618     *
3619     * @param context the current request context
3620     *
3621     * @return <code>true</code>, if the user has management access to the current project
3622     */
3623    public boolean isManagerOfProject(CmsRequestContext context) {
3624
3625        try {
3626            return getAllManageableProjects(
3627                context,
3628                readOrganizationalUnit(context, context.getCurrentProject().getOuFqn()),
3629                false).contains(context.getCurrentProject());
3630        } catch (CmsException e) {
3631            // should never happen
3632            if (LOG.isErrorEnabled()) {
3633                LOG.error(e.getLocalizedMessage(), e);
3634            }
3635            return false;
3636        }
3637    }
3638
3639    /**
3640     * Checks whether the subscription driver is available.<p>
3641     *
3642     * @return true if the subscription driver is available
3643     */
3644    public boolean isSubscriptionDriverAvailable() {
3645
3646        return m_driverManager.isSubscriptionDriverAvailable();
3647    }
3648
3649    /**
3650     * Locks a resource.<p>
3651     *
3652     * The <code>type</code> parameter controls what kind of lock is used.<br>
3653     * Possible values for this parameter are: <br>
3654     * <ul>
3655     * <li><code>{@link org.opencms.lock.CmsLockType#EXCLUSIVE}</code></li>
3656     * <li><code>{@link org.opencms.lock.CmsLockType#TEMPORARY}</code></li>
3657     * <li><code>{@link org.opencms.lock.CmsLockType#PUBLISH}</code></li>
3658     * </ul><p>
3659     *
3660     * @param context the current request context
3661     * @param resource the resource to lock
3662     * @param type type of the lock
3663     *
3664     * @throws CmsException if something goes wrong
3665     *
3666     * @see CmsObject#lockResource(String)
3667     * @see CmsObject#lockResourceTemporary(String)
3668     * @see org.opencms.file.types.I_CmsResourceType#lockResource(CmsObject, CmsSecurityManager, CmsResource, CmsLockType)
3669     */
3670    public void lockResource(CmsRequestContext context, CmsResource resource, CmsLockType type) throws CmsException {
3671
3672        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3673        try {
3674            checkOfflineProject(dbc);
3675            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL);
3676            m_driverManager.lockResource(dbc, resource, type);
3677        } catch (Exception e) {
3678            CmsMessageContainer messageContainer;
3679            if (e instanceof CmsLockException) {
3680                messageContainer = ((CmsLockException)e).getMessageContainer();
3681            } else {
3682                messageContainer = Messages.get().container(
3683                    Messages.ERR_LOCK_RESOURCE_2,
3684                    context.getSitePath(resource),
3685                    type.toString());
3686            }
3687            dbc.report(null, messageContainer, e);
3688        } finally {
3689            dbc.clear();
3690        }
3691    }
3692
3693    /**
3694     * Attempts to authenticate a user into OpenCms with the given password.<p>
3695     *
3696     * @param context the current request context
3697     * @param username the name of the user to be logged in
3698     * @param password the password of the user
3699     * @param code the additional login information for 2FA
3700     * @param remoteAddress the ip address of the request
3701     *
3702     * @return the logged in user
3703     *
3704     * @throws CmsException if the login was not successful
3705     */
3706    public CmsUser loginUser(
3707        CmsRequestContext context,
3708        String username,
3709        String password,
3710        CmsSecondFactorInfo code,
3711        String remoteAddress)
3712    throws CmsException {
3713
3714        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3715        CmsUser result = null;
3716        try {
3717            result = m_driverManager.loginUser(
3718                dbc,
3719                CmsOrganizationalUnit.removeLeadingSeparator(username),
3720                password,
3721                code,
3722                remoteAddress,
3723                CmsDriverManager.LoginUserMode.standard);
3724        } finally {
3725            dbc.clear();
3726        }
3727        return result;
3728    }
3729
3730    /**
3731     * Lookup and read the user or group with the given UUID.<p>
3732     *
3733     * @param context the current request context
3734     * @param principalId the UUID of the principal to lookup
3735     *
3736     * @return the principal (group or user) if found, otherwise <code>null</code>
3737     */
3738    public I_CmsPrincipal lookupPrincipal(CmsRequestContext context, CmsUUID principalId) {
3739
3740        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3741        I_CmsPrincipal result = null;
3742        try {
3743            result = m_driverManager.lookupPrincipal(dbc, principalId);
3744        } finally {
3745            dbc.clear();
3746        }
3747        return result;
3748    }
3749
3750    /**
3751     * Lookup and read the user or group with the given name.<p>
3752     *
3753     * @param context the current request context
3754     * @param principalName the name of the principal to lookup
3755     *
3756     * @return the principal (group or user) if found, otherwise <code>null</code>
3757     */
3758    public I_CmsPrincipal lookupPrincipal(CmsRequestContext context, String principalName) {
3759
3760        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3761        I_CmsPrincipal result = null;
3762        try {
3763            result = m_driverManager.lookupPrincipal(dbc, CmsOrganizationalUnit.removeLeadingSeparator(principalName));
3764        } finally {
3765            dbc.clear();
3766        }
3767        return result;
3768    }
3769
3770    /**
3771     * Mark the given resource as visited by the user.<p>
3772     *
3773     * @param context the request context
3774     * @param poolName the name of the database pool to use
3775     * @param resource the resource to mark as visited
3776     * @param user the user that visited the resource
3777     *
3778     * @throws CmsException if something goes wrong
3779     */
3780    public void markResourceAsVisitedBy(CmsRequestContext context, String poolName, CmsResource resource, CmsUser user)
3781    throws CmsException {
3782
3783        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3784        try {
3785            m_driverManager.markResourceAsVisitedBy(dbc, poolName, resource, user);
3786        } catch (Exception e) {
3787            dbc.report(
3788                null,
3789                Messages.get().container(
3790                    Messages.ERR_MARK_RESOURCE_AS_VISITED_2,
3791                    context.getSitePath(resource),
3792                    user.getName()),
3793                e);
3794        } finally {
3795            dbc.clear();
3796        }
3797    }
3798
3799    /**
3800     * Returns a new publish list that contains all resources of both given publish lists.<p>
3801     *
3802     * @param context the current request context
3803     * @param pubList1 the first publish list
3804     * @param pubList2 the second publish list
3805     *
3806     * @return a new publish list that contains all resources of both given publish lists
3807     *
3808     * @throws CmsException if something goes wrong
3809     *
3810     * @see org.opencms.publish.CmsPublishManager#mergePublishLists(CmsObject, CmsPublishList, CmsPublishList)
3811     */
3812    public CmsPublishList mergePublishLists(CmsRequestContext context, CmsPublishList pubList1, CmsPublishList pubList2)
3813    throws CmsException {
3814
3815        CmsPublishList ret = null;
3816        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3817        try {
3818            // get all resources from the first list
3819            Set<CmsResource> publishResources = new HashSet<CmsResource>(pubList1.getAllResources());
3820            // get all resources from the second list
3821            publishResources.addAll(pubList2.getAllResources());
3822
3823            // create merged publish list
3824            ret = new CmsPublishList(
3825                pubList1.getDirectPublishResources(),
3826                pubList1.isPublishSiblings(),
3827                pubList1.isPublishSubResources());
3828            ret.addAll(publishResources, false); // ignore files that should not be published
3829            if (pubList1.isUserPublishList()) {
3830                ret.setUserPublishList(true);
3831            }
3832            ret.initialize(); // ensure sort order
3833
3834            checkPublishPermissions(dbc, ret);
3835        } catch (Exception e) {
3836            dbc.report(null, Messages.get().container(Messages.ERR_MERGING_PUBLISH_LISTS_0), e);
3837        } finally {
3838            dbc.clear();
3839        }
3840        return ret;
3841    }
3842
3843    /**
3844     * Moves a resource.<p>
3845     *
3846     * You must ensure that the destination path is an absolute, valid and
3847     * existing VFS path. Relative paths from the source are currently not supported.<p>
3848     *
3849     * The moved resource will always be locked to the current user
3850     * after the move operation.<p>
3851     *
3852     * In case the target resource already exists, it is overwritten with the
3853     * source resource.<p>
3854     *
3855     * @param context the current request context
3856     * @param source the resource to copy
3857     * @param destination the name of the copy destination with complete path
3858     *
3859     * @throws CmsException if something goes wrong
3860     * @throws CmsSecurityException if resource could not be copied
3861     *
3862     * @see CmsObject#moveResource(String, String)
3863     * @see org.opencms.file.types.I_CmsResourceType#moveResource(CmsObject, CmsSecurityManager, CmsResource, String)
3864     */
3865    public void moveResource(CmsRequestContext context, CmsResource source, String destination)
3866    throws CmsException, CmsSecurityException {
3867
3868        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3869        try {
3870            checkOfflineProject(dbc);
3871            // checking if the destination folder exists and is not marked as deleted
3872            readResource(context, CmsResource.getParentFolder(destination), CmsResourceFilter.IGNORE_EXPIRATION);
3873            checkPermissions(dbc, source, CmsPermissionSet.ACCESS_READ, true, CmsResourceFilter.ALL);
3874            checkPermissions(dbc, source, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
3875
3876            checkSystemLocks(dbc, source);
3877
3878            // check write permissions for subresources in case of moving a folder
3879            if (source.isFolder()) {
3880                dbc.getRequestContext().setAttribute(I_CmsVfsDriver.REQ_ATTR_CHECK_PERMISSIONS, Boolean.TRUE);
3881                try {
3882                    m_driverManager.getVfsDriver(
3883                        dbc).moveResource(dbc, dbc.currentProject().getUuid(), source, destination);
3884                } catch (CmsDataAccessException e) {
3885                    // unwrap the permission violation exception
3886                    if (e.getCause() instanceof CmsPermissionViolationException) {
3887                        throw (CmsPermissionViolationException)e.getCause();
3888                    } else {
3889                        throw e;
3890                    }
3891                }
3892                dbc.getRequestContext().removeAttribute(I_CmsVfsDriver.REQ_ATTR_CHECK_PERMISSIONS);
3893            }
3894            Set<CmsResource> allMovedResources = new HashSet<>();
3895            moveResource(dbc, source, destination, allMovedResources);
3896            if (!dbc.currentProject().isOnlineProject()) {
3897                for (CmsResource movedResource : allMovedResources) {
3898                    m_driverManager.repairCategories(
3899                        dbc,
3900                        dbc.getRequestContext().getCurrentProject().getUuid(),
3901                        movedResource);
3902                }
3903            }
3904
3905        } catch (Exception e) {
3906            dbc.report(
3907                null,
3908                Messages.get().container(
3909                    Messages.ERR_MOVE_RESOURCE_2,
3910                    dbc.removeSiteRoot(source.getRootPath()),
3911                    dbc.removeSiteRoot(destination)),
3912                e);
3913        } finally {
3914            dbc.clear();
3915        }
3916    }
3917
3918    /**
3919     * Moves a resource to the "lost and found" folder.<p>
3920     *
3921     * The method can also be used to check get the name of a resource
3922     * in the "lost and found" folder only without actually moving the
3923     * the resource. To do this, the <code>returnNameOnly</code> flag
3924     * must be set to <code>true</code>.<p>
3925     *
3926     * In general, it is the same name as the given resource has, the only exception is
3927     * if a resource in the "lost and found" folder with the same name already exists.
3928     * In such case, a counter is added to the resource name.<p>
3929     *
3930     * @param context the current request context
3931     * @param resource the resource to apply this operation to
3932     * @param returnNameOnly if <code>true</code>, only the name of the resource in the "lost and found"
3933     *        folder is returned, the move operation is not really performed
3934     *
3935     * @return the name of the resource inside the "lost and found" folder
3936     *
3937     * @throws CmsException if something goes wrong
3938     *
3939     * @see CmsObject#moveToLostAndFound(String)
3940     * @see CmsObject#getLostAndFoundName(String)
3941     */
3942    public String moveToLostAndFound(CmsRequestContext context, CmsResource resource, boolean returnNameOnly)
3943    throws CmsException {
3944
3945        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3946        String result = null;
3947        try {
3948            checkOfflineProject(dbc);
3949            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, true, CmsResourceFilter.ALL);
3950            if (!returnNameOnly) {
3951                checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
3952            }
3953            result = m_driverManager.moveToLostAndFound(dbc, resource, returnNameOnly);
3954        } catch (Exception e) {
3955            dbc.report(
3956                null,
3957                Messages.get().container(
3958                    Messages.ERR_MOVE_TO_LOST_AND_FOUND_1,
3959                    dbc.removeSiteRoot(resource.getRootPath())),
3960                e);
3961        } finally {
3962            dbc.clear();
3963        }
3964        return result;
3965    }
3966
3967    /**
3968     * Publishes the resources of a specified publish list.<p>
3969     *
3970     * @param cms the current request context
3971     * @param publishList a publish list
3972     * @param report an instance of <code>{@link I_CmsReport}</code> to print messages
3973     *
3974     * @return the publish history id of the published project
3975     *
3976     * @throws CmsException if something goes wrong
3977     *
3978     * @see #fillPublishList(CmsRequestContext, CmsPublishList)
3979     */
3980    public CmsUUID publishProject(CmsObject cms, CmsPublishList publishList, I_CmsReport report) throws CmsException {
3981
3982        CmsRequestContext context = cms.getRequestContext();
3983        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3984        try {
3985            // check if the current user has the required publish permissions
3986            checkPublishPermissions(dbc, publishList);
3987            m_driverManager.publishProject(cms, dbc, publishList, report);
3988        } finally {
3989            dbc.clear();
3990        }
3991        return publishList.getPublishHistoryId();
3992    }
3993
3994    /**
3995     * Reads the alias with a given path in a given site.<p>
3996     *
3997     * @param context the current request context
3998     * @param siteRoot the site root
3999     * @param path the site relative alias path
4000     * @return the alias for the path, or null if no such alias exists
4001     *
4002     * @throws CmsException if something goes wrong
4003     */
4004    public CmsAlias readAliasByPath(CmsRequestContext context, String siteRoot, String path) throws CmsException {
4005
4006        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4007        try {
4008            CmsAlias alias = m_driverManager.readAliasByPath(dbc, context.getCurrentProject(), siteRoot, path);
4009            return alias;
4010        } catch (Exception e) {
4011            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
4012            return null; // will never be executed
4013        } finally {
4014            dbc.clear();
4015        }
4016    }
4017
4018    /**
4019     * Reads the aliases for a resource with a given structure id.<p>
4020     *
4021     * @param context the current request context
4022     * @param structureId the structure id for which the aliases should be read
4023     *
4024     * @return the aliases for the structure id
4025     *
4026     * @throws CmsException if something goes wrong
4027     */
4028    public List<CmsAlias> readAliasesById(CmsRequestContext context, CmsUUID structureId) throws CmsException {
4029
4030        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4031        try {
4032            List<CmsAlias> aliases = m_driverManager.readAliasesByStructureId(
4033                dbc,
4034                context.getCurrentProject(),
4035                structureId);
4036            return aliases;
4037        } catch (Exception e) {
4038            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
4039            return null; // will never be executed
4040        } finally {
4041            dbc.clear();
4042        }
4043
4044    }
4045
4046    /**
4047     * Reads all historical versions of a resource.<p>
4048     *
4049     * The reading excludes the file content, if the resource is a file.<p>
4050     *
4051     * @param context the current request context
4052     * @param resource the resource to be read
4053     *
4054     * @return a list of historical versions, as <code>{@link I_CmsHistoryResource}</code> objects
4055     *
4056     * @throws CmsException if something goes wrong
4057     */
4058    public List<I_CmsHistoryResource> readAllAvailableVersions(CmsRequestContext context, CmsResource resource)
4059    throws CmsException {
4060
4061        List<I_CmsHistoryResource> result = null;
4062        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4063        try {
4064            result = m_driverManager.readAllAvailableVersions(dbc, resource);
4065        } catch (Exception e) {
4066            dbc.report(
4067                null,
4068                Messages.get().container(Messages.ERR_READ_ALL_HISTORY_FILE_HEADERS_1, context.getSitePath(resource)),
4069                e);
4070        } finally {
4071            dbc.clear();
4072        }
4073        return result;
4074    }
4075
4076    /**
4077     * Reads all property definitions for the given mapping type.<p>
4078     *
4079     * @param context the current request context
4080     *
4081     * @return a list with the <code>{@link CmsPropertyDefinition}</code> objects (may be empty)
4082     *
4083     * @throws CmsException if something goes wrong
4084     */
4085    public List<CmsPropertyDefinition> readAllPropertyDefinitions(CmsRequestContext context) throws CmsException {
4086
4087        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4088        List<CmsPropertyDefinition> result = null;
4089        try {
4090            result = m_driverManager.readAllPropertyDefinitions(dbc);
4091        } catch (Exception e) {
4092            dbc.report(null, Messages.get().container(Messages.ERR_READ_ALL_PROPDEF_0), e);
4093        } finally {
4094            dbc.clear();
4095        }
4096        return result;
4097    }
4098
4099    /**
4100     * Returns all resources subscribed by the given user or group.<p>
4101     *
4102     * @param context the request context
4103     * @param poolName the name of the database pool to use
4104     * @param principal the principal to read the subscribed resources
4105     *
4106     * @return all resources subscribed by the given user or group
4107     *
4108     * @throws CmsException if something goes wrong
4109     */
4110    public List<CmsResource> readAllSubscribedResources(
4111        CmsRequestContext context,
4112        String poolName,
4113        CmsPrincipal principal)
4114    throws CmsException {
4115
4116        List<CmsResource> result = null;
4117        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4118        try {
4119            result = m_driverManager.readAllSubscribedResources(dbc, poolName, principal);
4120        } catch (Exception e) {
4121            if (principal instanceof CmsUser) {
4122                dbc.report(
4123                    null,
4124                    Messages.get().container(Messages.ERR_READ_SUBSCRIBED_RESOURCES_ALL_USER_1, principal.getName()),
4125                    e);
4126            } else {
4127                dbc.report(
4128                    null,
4129                    Messages.get().container(Messages.ERR_READ_SUBSCRIBED_RESOURCES_ALL_GROUP_1, principal.getName()),
4130                    e);
4131            }
4132        } finally {
4133            dbc.clear();
4134        }
4135        return result;
4136    }
4137
4138    /**
4139     * Reads all URL name mapping entries for a given structure id.<p>
4140     *
4141     * @param context the request context
4142     * @param id the structure id
4143     *
4144     * @return the list of URL names for the given structure id
4145     * @throws CmsException if something goes wrong
4146     */
4147    public List<String> readAllUrlNameMappingEntries(CmsRequestContext context, CmsUUID id) throws CmsException {
4148
4149        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4150        try {
4151            List<CmsUrlNameMappingEntry> entries = m_driverManager.readUrlNameMappingEntries(
4152                dbc,
4153                context.getCurrentProject().isOnlineProject(),
4154                CmsUrlNameMappingFilter.ALL.filterStructureId(id));
4155            List<String> result = new ArrayList<String>();
4156            for (CmsUrlNameMappingEntry entry : entries) {
4157                result.add(entry.getName());
4158            }
4159            return result;
4160        } catch (Exception e) {
4161            CmsMessageContainer message = Messages.get().container(
4162                Messages.ERR_READ_NEWEST_URLNAME_FOR_ID_1,
4163                id.toString());
4164            dbc.report(null, message, e);
4165            return null;
4166        } finally {
4167            dbc.clear();
4168        }
4169
4170    }
4171
4172    /**
4173     * Returns the first ancestor folder matching the filter criteria.<p>
4174     *
4175     * If no folder matching the filter criteria is found, null is returned.<p>
4176     *
4177     * @param context the context of the current request
4178     * @param resource the resource to start
4179     * @param filter the resource filter to match while reading the ancestors
4180     *
4181     * @return the first ancestor folder matching the filter criteria or <code>null</code> if no folder was found
4182     *
4183     * @throws CmsException if something goes wrong
4184     */
4185    public CmsFolder readAncestor(CmsRequestContext context, CmsResource resource, CmsResourceFilter filter)
4186    throws CmsException {
4187
4188        // get the full folder path of the resource to start from
4189        String path = CmsResource.getFolderPath(resource.getRootPath());
4190        do {
4191            // check if the current folder matches the given filter
4192            if (existsResource(context, path, filter)) {
4193                // folder matches, return it
4194                return readFolder(context, path, filter);
4195            } else {
4196                // folder does not match filter criteria, go up one folder
4197                path = CmsResource.getParentFolder(path);
4198            }
4199
4200            if (CmsStringUtil.isEmpty(path) || !path.startsWith(context.getSiteRoot())) {
4201                // site root or root folder reached and no matching folder found
4202                return null;
4203            }
4204        } while (true);
4205    }
4206
4207    /**
4208     * Reads the newest URL name which is mapped to the given structure id.<p>
4209     *
4210     * If the structure id is not mapped to any name, null will be returned.<p>
4211     *
4212     * @param context the request context
4213     * @param id the structure id for which the newest mapped name should be returned
4214     * @param locale the locale for the mapping
4215     * @param defaultLocales the default locales to use if there is no URL name mapping for the requested locale
4216     *
4217     * @return an URL name or null
4218     *
4219     * @throws CmsException if something goes wrong
4220     */
4221    public String readBestUrlName(CmsRequestContext context, CmsUUID id, Locale locale, List<Locale> defaultLocales)
4222    throws CmsException {
4223
4224        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4225        try {
4226            return m_driverManager.readBestUrlName(dbc, id, locale, defaultLocales);
4227        } catch (Exception e) {
4228            CmsMessageContainer message = Messages.get().container(
4229                Messages.ERR_READ_NEWEST_URLNAME_FOR_ID_1,
4230                id.toString());
4231            dbc.report(null, message, e);
4232            return null; // will never be reached
4233        } finally {
4234            dbc.clear();
4235        }
4236    }
4237
4238    /**
4239     * Returns the child resources of a resource, that is the resources
4240     * contained in a folder.<p>
4241     *
4242     * With the parameters <code>getFolders</code> and <code>getFiles</code>
4243     * you can control what type of resources you want in the result list:
4244     * files, folders, or both.<p>
4245     *
4246     * This method is mainly used by the workplace explorer.<p>
4247     *
4248     * @param context the current request context
4249     * @param resource the resource to return the child resources for
4250     * @param filter the resource filter to use
4251     * @param getFolders if true the child folders are included in the result
4252     * @param getFiles if true the child files are included in the result
4253     *
4254     * @return a list of all child resources
4255     *
4256     * @throws CmsException if something goes wrong
4257     * @throws CmsSecurityException if the user has insufficient permission for the given resource (read is required)
4258     *
4259     */
4260    public List<CmsResource> readChildResources(
4261        CmsRequestContext context,
4262        CmsResource resource,
4263        CmsResourceFilter filter,
4264        boolean getFolders,
4265        boolean getFiles)
4266    throws CmsException, CmsSecurityException {
4267
4268        List<CmsResource> result = null;
4269        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4270        try {
4271            // check the access permissions
4272            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, true, CmsResourceFilter.ALL);
4273            result = m_driverManager.readChildResources(dbc, resource, filter, getFolders, getFiles, true);
4274        } catch (Exception e) {
4275            dbc.report(
4276                null,
4277                Messages.get().container(Messages.ERR_READ_CHILD_RESOURCES_1, context.getSitePath(resource)),
4278                e);
4279        } finally {
4280            dbc.clear();
4281        }
4282        return result;
4283    }
4284
4285    /**
4286     * Returns the default file for the given folder.<p>
4287     *
4288     * If the given resource is a file, then this file is returned.<p>
4289     *
4290     * Otherwise, in case of a folder:<br>
4291     * <ol>
4292     *   <li>the {@link CmsPropertyDefinition#PROPERTY_DEFAULT_FILE} is checked, and
4293     *   <li>if still no file could be found, the configured default files in the
4294     *       <code>opencms-vfs.xml</code> configuration are iterated until a match is
4295     *       found, and
4296     *   <li>if still no file could be found, <code>null</code> is returned
4297     * </ol><p>
4298     *
4299     * @param context the request context
4300     * @param resource the folder to get the default file for
4301     * @param resourceFilter the resource filter
4302     *
4303     * @return the default file for the given folder
4304     *
4305     * @throws CmsSecurityException if the user has no permissions to read the resulting file
4306     *
4307     * @see CmsObject#readDefaultFile(String)
4308     */
4309    public CmsResource readDefaultFile(
4310        CmsRequestContext context,
4311        CmsResource resource,
4312        CmsResourceFilter resourceFilter)
4313    throws CmsSecurityException {
4314
4315        CmsResource result = null;
4316        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4317        try {
4318            CmsResource tempResult = m_driverManager.readDefaultFile(dbc, resource, resourceFilter);
4319            if (tempResult != null) {
4320                // check if the user has read access to the resource
4321                checkPermissions(dbc, tempResult, CmsPermissionSet.ACCESS_READ, true, resourceFilter);
4322                result = tempResult;
4323            }
4324        } catch (CmsSecurityException se) {
4325            // permissions deny access to the resource
4326            throw se;
4327        } catch (CmsException e) {
4328            // ignore all other exceptions
4329            LOG.debug(e.getLocalizedMessage(), e);
4330        } finally {
4331            dbc.clear();
4332        }
4333        return result;
4334    }
4335
4336    /**
4337     * Reads all deleted (historical) resources below the given path,
4338     * including the full tree below the path, if required.<p>
4339     *
4340     * @param context the current request context
4341     * @param resource the parent resource to read the resources from
4342     * @param readTree <code>true</code> to read all subresources
4343     *
4344     * @return a list of <code>{@link I_CmsHistoryResource}</code> objects
4345     *
4346     * @throws CmsException if something goes wrong
4347     *
4348     * @see CmsObject#readResource(CmsUUID, int)
4349     * @see CmsObject#readResources(String, CmsResourceFilter, boolean)
4350     * @see CmsObject#readDeletedResources(String, boolean)
4351     */
4352    public List<I_CmsHistoryResource> readDeletedResources(
4353        CmsRequestContext context,
4354        CmsResource resource,
4355        boolean readTree)
4356    throws CmsException {
4357
4358        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4359        List<I_CmsHistoryResource> result = null;
4360        try {
4361            boolean isVfsManager = hasRoleForResource(dbc, dbc.currentUser(), CmsRole.VFS_MANAGER, resource);
4362            result = m_driverManager.readDeletedResources(dbc, resource, readTree, isVfsManager);
4363        } catch (CmsException e) {
4364            dbc.report(
4365                null,
4366                Messages.get().container(
4367                    Messages.ERR_READING_DELETED_RESOURCES_1,
4368                    dbc.removeSiteRoot(resource.getRootPath())),
4369                e);
4370        } finally {
4371            dbc.clear();
4372        }
4373        return result;
4374    }
4375
4376    /**
4377     * Reads a file resource (including it's binary content) from the VFS.<p>
4378     *
4379     * In case you do not need the file content,
4380     * use <code>{@link #readResource(CmsRequestContext, String, CmsResourceFilter)}</code> instead.<p>
4381     *
4382     * @param context the current request context
4383     * @param resource the resource to be read
4384     *
4385     * @return the file read from the VFS
4386     *
4387     * @throws CmsException if something goes wrong
4388     */
4389    public CmsFile readFile(CmsRequestContext context, CmsResource resource) throws CmsException {
4390
4391        CmsFile result = null;
4392        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4393        try {
4394            result = m_driverManager.readFile(dbc, resource);
4395        } catch (Exception e) {
4396            if (resource instanceof I_CmsHistoryResource) {
4397                dbc.report(
4398                    null,
4399                    Messages.get().container(
4400                        Messages.ERR_READ_FILE_HISTORY_2,
4401                        context.getSitePath(resource),
4402                        new Integer(resource.getVersion())),
4403                    e);
4404            } else {
4405                dbc.report(null, Messages.get().container(Messages.ERR_READ_FILE_1, context.getSitePath(resource)), e);
4406            }
4407        } finally {
4408            dbc.clear();
4409        }
4410        return result;
4411    }
4412
4413    /**
4414     * Reads a folder resource from the VFS,
4415     * using the specified resource filter.<p>
4416     *
4417     * The specified filter controls what kind of resources should be "found"
4418     * during the read operation. This will depend on the application. For example,
4419     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
4420     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
4421     * will ignore the date release / date expired information of the resource.<p>
4422     *
4423     * @param context the current request context
4424     * @param resourcename the name of the folder to read (full path)
4425     * @param filter the resource filter to use while reading
4426     *
4427     * @return the folder that was read
4428     *
4429     * @throws CmsException if something goes wrong
4430     */
4431    public CmsFolder readFolder(CmsRequestContext context, String resourcename, CmsResourceFilter filter)
4432    throws CmsException {
4433
4434        CmsFolder result = null;
4435        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4436        try {
4437            result = readFolder(dbc, resourcename, filter);
4438        } catch (Exception e) {
4439            dbc.report(null, Messages.get().container(Messages.ERR_READ_FOLDER_2, resourcename, filter), e);
4440        } finally {
4441            dbc.clear();
4442        }
4443        return result;
4444    }
4445
4446    /**
4447     * Reads the group of a project.<p>
4448     *
4449     * @param context the current request context
4450     * @param project the project to read from
4451     *
4452     * @return the group of a resource
4453     */
4454    public CmsGroup readGroup(CmsRequestContext context, CmsProject project) {
4455
4456        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4457        CmsGroup result = null;
4458        try {
4459            result = m_driverManager.readGroup(dbc, project);
4460        } finally {
4461            dbc.clear();
4462        }
4463        return result;
4464    }
4465
4466    /**
4467     * Reads a group based on its id.<p>
4468     *
4469     * @param context the current request context
4470     * @param groupId the id of the group that is to be read
4471     *
4472     * @return the requested group
4473     *
4474     * @throws CmsException if operation was not successful
4475     */
4476    public CmsGroup readGroup(CmsRequestContext context, CmsUUID groupId) throws CmsException {
4477
4478        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4479        CmsGroup result = null;
4480        try {
4481            result = m_driverManager.readGroup(dbc, groupId);
4482        } catch (Exception e) {
4483            dbc.report(null, Messages.get().container(Messages.ERR_READ_GROUP_FOR_ID_1, groupId.toString()), e);
4484        } finally {
4485            dbc.clear();
4486        }
4487        return result;
4488    }
4489
4490    /**
4491     * Reads a group based on its name.<p>
4492     *
4493     * @param context the current request context
4494     * @param groupname the name of the group that is to be read
4495     *
4496     * @return the requested group
4497     *
4498     * @throws CmsException if operation was not successful
4499     */
4500    public CmsGroup readGroup(CmsRequestContext context, String groupname) throws CmsException {
4501
4502        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4503        CmsGroup result = null;
4504        try {
4505            result = m_driverManager.readGroup(dbc, CmsOrganizationalUnit.removeLeadingSeparator(groupname));
4506        } catch (Exception e) {
4507            dbc.report(null, Messages.get().container(Messages.ERR_READ_GROUP_FOR_NAME_1, groupname), e);
4508        } finally {
4509            dbc.clear();
4510        }
4511        return result;
4512    }
4513
4514    /**
4515     * Reads a principal (an user or group) from the historical archive based on its ID.<p>
4516     *
4517     * @param context the current request context
4518     * @param principalId the id of the principal to read
4519     *
4520     * @return the historical principal entry with the given id
4521     *
4522     * @throws CmsException if something goes wrong, ie. {@link CmsDbEntryNotFoundException}
4523     *
4524     * @see CmsObject#readUser(CmsUUID)
4525     * @see CmsObject#readGroup(CmsUUID)
4526     * @see CmsObject#readHistoryPrincipal(CmsUUID)
4527     */
4528    public CmsHistoryPrincipal readHistoricalPrincipal(CmsRequestContext context, CmsUUID principalId)
4529    throws CmsException {
4530
4531        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4532        CmsHistoryPrincipal result = null;
4533        try {
4534            result = m_driverManager.readHistoricalPrincipal(dbc, principalId);
4535        } catch (Exception e) {
4536            dbc.report(null, Messages.get().container(Messages.ERR_READ_HISTORY_PRINCIPAL_1, principalId), e);
4537        } finally {
4538            dbc.clear();
4539        }
4540        return result;
4541    }
4542
4543    /**
4544     * Returns the latest historical project entry with the given id.<p>
4545     *
4546     * @param context the current request context
4547     * @param projectId the project id
4548     *
4549     * @return the requested historical project entry
4550     *
4551     * @throws CmsException if something goes wrong
4552     */
4553    public CmsHistoryProject readHistoryProject(CmsRequestContext context, CmsUUID projectId) throws CmsException {
4554
4555        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4556        CmsHistoryProject result = null;
4557        try {
4558            result = m_driverManager.readHistoryProject(dbc, projectId);
4559        } catch (Exception e) {
4560            dbc.report(
4561                null,
4562                Messages.get().container(
4563                    Messages.ERR_READ_HISTORY_PROJECT_2,
4564                    projectId,
4565                    dbc.currentProject().getName()),
4566                e);
4567        } finally {
4568            dbc.clear();
4569        }
4570        return result;
4571    }
4572
4573    /**
4574     * Returns a historical project entry.<p>
4575     *
4576     * @param context the current request context
4577     * @param publishTag the publish tag of the project
4578     *
4579     * @return the requested historical project entry
4580     *
4581     * @throws CmsException if something goes wrong
4582     */
4583    public CmsHistoryProject readHistoryProject(CmsRequestContext context, int publishTag) throws CmsException {
4584
4585        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4586        CmsHistoryProject result = null;
4587        try {
4588            result = m_driverManager.readHistoryProject(dbc, publishTag);
4589        } catch (Exception e) {
4590            dbc.report(
4591                null,
4592                Messages.get().container(
4593                    Messages.ERR_READ_HISTORY_PROJECT_2,
4594                    new Integer(publishTag),
4595                    dbc.currentProject().getName()),
4596                e);
4597        } finally {
4598            dbc.clear();
4599        }
4600        return result;
4601    }
4602
4603    /**
4604     * Reads the list of all <code>{@link CmsProperty}</code> objects that belong to the given historical resource.<p>
4605     *
4606     * @param context the current request context
4607     * @param resource the historical resource entry to read the properties for
4608     *
4609     * @return the list of <code>{@link CmsProperty}</code> objects
4610     *
4611     * @throws CmsException if something goes wrong
4612     */
4613    public List<CmsProperty> readHistoryPropertyObjects(CmsRequestContext context, I_CmsHistoryResource resource)
4614    throws CmsException {
4615
4616        List<CmsProperty> result = null;
4617        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4618        try {
4619            result = m_driverManager.readHistoryPropertyObjects(dbc, resource);
4620        } catch (Exception e) {
4621            dbc.report(
4622                null,
4623                Messages.get().container(
4624                    Messages.ERR_READ_PROPS_FOR_RESOURCE_1,
4625                    context.getSitePath((CmsResource)resource)),
4626                e);
4627        } finally {
4628            dbc.clear();
4629        }
4630        return result;
4631    }
4632
4633    /**
4634     * Reads the structure id which is mapped to the given URL name, or null if the name is not
4635     * mapped to any structure IDs.<p>
4636     *
4637     * @param context the request context
4638     * @param name an URL name
4639     *
4640     * @return the structure ID which is mapped to the given name
4641     *
4642     * @throws CmsException if something goes wrong
4643     */
4644    public CmsUUID readIdForUrlName(CmsRequestContext context, String name) throws CmsException {
4645
4646        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4647        try {
4648            return m_driverManager.readIdForUrlName(dbc, name);
4649        } catch (Exception e) {
4650            CmsMessageContainer message = Messages.get().container(Messages.ERR_READ_ID_FOR_URLNAME_1, name);
4651            dbc.report(null, message, e);
4652            return null; // will never be reached
4653        } finally {
4654            dbc.clear();
4655        }
4656
4657    }
4658
4659    /**
4660     * Reads the locks that were saved to the database in the previous run of OpenCms.<p>
4661     *
4662     * @throws CmsException if something goes wrong
4663     */
4664    public void readLocks() throws CmsException {
4665
4666        CmsDbContext dbc = m_dbContextFactory.getDbContext();
4667        try {
4668            m_driverManager.readLocks(dbc);
4669        } finally {
4670            dbc.clear();
4671        }
4672    }
4673
4674    /**
4675     * Reads the manager group of a project.<p>
4676     *
4677     * @param context the current request context
4678     * @param project the project to read from
4679     *
4680     * @return the group of a resource
4681     */
4682    public CmsGroup readManagerGroup(CmsRequestContext context, CmsProject project) {
4683
4684        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4685        CmsGroup result = null;
4686        try {
4687            result = m_driverManager.readManagerGroup(dbc, project);
4688        } finally {
4689            dbc.clear();
4690        }
4691        return result;
4692    }
4693
4694    /**
4695     * Reads an organizational Unit based on its fully qualified name.<p>
4696     *
4697     * @param context the current request context
4698     * @param ouFqn the fully qualified name of the organizational Unit to be read
4699     *
4700     * @return the organizational Unit that with the provided fully qualified name
4701     *
4702     * @throws CmsException if something goes wrong
4703     */
4704    public CmsOrganizationalUnit readOrganizationalUnit(CmsRequestContext context, String ouFqn) throws CmsException {
4705
4706        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4707        CmsOrganizationalUnit result = null;
4708        try {
4709            result = m_driverManager.readOrganizationalUnit(dbc, CmsOrganizationalUnit.removeLeadingSeparator(ouFqn));
4710        } catch (Exception e) {
4711            dbc.report(null, Messages.get().container(Messages.ERR_READ_ORGUNIT_1, ouFqn), e);
4712        } finally {
4713            dbc.clear();
4714        }
4715        return result;
4716    }
4717
4718    /**
4719     * Reads the owner of a project from the OpenCms.<p>
4720     *
4721     * @param context the current request context
4722     * @param project the project to get the owner from
4723     *
4724     * @return the owner of a resource
4725     *
4726     * @throws CmsException if something goes wrong
4727     */
4728    public CmsUser readOwner(CmsRequestContext context, CmsProject project) throws CmsException {
4729
4730        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4731        CmsUser result = null;
4732        try {
4733            result = m_driverManager.readOwner(dbc, project);
4734        } catch (Exception e) {
4735            dbc.report(
4736                null,
4737                Messages.get().container(Messages.ERR_READ_OWNER_FOR_PROJECT_2, project.getName(), project.getUuid()),
4738                e);
4739        } finally {
4740            dbc.clear();
4741        }
4742        return result;
4743    }
4744
4745    /**
4746     * Returns the parent folder to the given structure id.<p>
4747     *
4748     * @param context the current request context
4749     * @param structureId the child structure id
4750     *
4751     * @return the parent folder <code>{@link CmsResource}</code>
4752     *
4753     * @throws CmsException if something goes wrong
4754     */
4755    public CmsResource readParentFolder(CmsRequestContext context, CmsUUID structureId) throws CmsException {
4756
4757        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4758        CmsResource result = null;
4759        try {
4760            result = m_driverManager.readParentFolder(dbc, structureId);
4761        } catch (Exception e) {
4762            dbc.report(
4763                null,
4764                Messages.get().container(
4765                    Messages.ERR_READ_PARENT_FOLDER_2,
4766                    dbc.currentProject().getName(),
4767                    structureId),
4768                e);
4769        } finally {
4770            dbc.clear();
4771        }
4772        return result;
4773    }
4774
4775    /**
4776     * Builds a list of resources for a given path.<p>
4777     *
4778     * @param context the current request context
4779     * @param path the requested path
4780     * @param filter a filter object (only "includeDeleted" information is used!)
4781     *
4782     * @return list of <code>{@link CmsResource}</code>s
4783     *
4784     * @throws CmsException if something goes wrong
4785     */
4786    public List<CmsResource> readPath(CmsRequestContext context, String path, CmsResourceFilter filter)
4787    throws CmsException {
4788
4789        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4790        List<CmsResource> result = null;
4791        try {
4792            result = m_driverManager.readPath(dbc, path, filter);
4793        } catch (Exception e) {
4794            dbc.report(
4795                null,
4796                Messages.get().container(Messages.ERR_READ_PATH_2, dbc.currentProject().getName(), path),
4797                e);
4798        } finally {
4799            dbc.clear();
4800        }
4801        return result;
4802    }
4803
4804    /**
4805     * Reads a project given the projects id.<p>
4806     *
4807     * @param id the id of the project
4808     *
4809     * @return the project read
4810     *
4811     * @throws CmsException if something goes wrong
4812     */
4813    public CmsProject readProject(CmsUUID id) throws CmsException {
4814
4815        CmsDbContext dbc = m_dbContextFactory.getDbContext();
4816        CmsProject result = null;
4817        try {
4818            result = m_driverManager.readProject(dbc, id);
4819        } catch (Exception e) {
4820            dbc.report(null, Messages.get().container(Messages.ERR_READ_PROJECT_FOR_ID_1, id), e);
4821        } finally {
4822            dbc.clear();
4823        }
4824        return result;
4825    }
4826
4827    /**
4828     * Reads a project.<p>
4829     *
4830     * Important: Since a project name can be used multiple times, this is NOT the most efficient
4831     * way to read the project. This is only a convenience for front end developing.
4832     * Reading a project by name will return the first project with that name.
4833     * All core classes must use the id version {@link #readProject(CmsUUID)} to ensure the right project is read.<p>
4834     *
4835     * @param name the name of the project
4836     *
4837     * @return the project read
4838     *
4839     * @throws CmsException if something goes wrong
4840     */
4841    public CmsProject readProject(String name) throws CmsException {
4842
4843        CmsDbContext dbc = m_dbContextFactory.getDbContext();
4844        CmsProject result = null;
4845        try {
4846            result = m_driverManager.readProject(dbc, CmsOrganizationalUnit.removeLeadingSeparator(name));
4847        } catch (Exception e) {
4848            dbc.report(null, Messages.get().container(Messages.ERR_READ_PROJECT_FOR_NAME_1, name), e);
4849        } finally {
4850            dbc.clear();
4851        }
4852        return result;
4853    }
4854
4855    /**
4856     * Returns the list of all resource names that define the "view" of the given project.<p>
4857     *
4858     * @param context the current request context
4859     * @param project the project to get the project resources for
4860     *
4861     * @return the list of all resources, as <code>{@link String}</code> objects
4862     *              that define the "view" of the given project
4863     *
4864     * @throws CmsException if something goes wrong
4865     */
4866    public List<String> readProjectResources(CmsRequestContext context, CmsProject project) throws CmsException {
4867
4868        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4869        List<String> result = null;
4870        try {
4871            result = m_driverManager.readProjectResources(dbc, project);
4872        } catch (Exception e) {
4873            dbc.report(
4874                null,
4875                Messages.get().container(Messages.ERR_READ_PROJECT_RESOURCES_2, project.getName(), project.getUuid()),
4876                e);
4877        } finally {
4878            dbc.clear();
4879        }
4880        return result;
4881    }
4882
4883    /**
4884     * Reads all resources of a project that match a given state from the VFS.<p>
4885     *
4886     * Possible values for the <code>state</code> parameter are:<br>
4887     * <ul>
4888     * <li><code>{@link CmsResource#STATE_CHANGED}</code>: Read all "changed" resources in the project</li>
4889     * <li><code>{@link CmsResource#STATE_NEW}</code>: Read all "new" resources in the project</li>
4890     * <li><code>{@link CmsResource#STATE_DELETED}</code>: Read all "deleted" resources in the project</li>
4891     * <li><code>{@link CmsResource#STATE_KEEP}</code>: Read all resources either "changed", "new" or "deleted" in the project</li>
4892     * </ul><p>
4893     *
4894     * @param context the current request context
4895     * @param projectId the id of the project to read the file resources for
4896     * @param state the resource state to match
4897     *
4898     * @return a list of <code>{@link CmsResource}</code> objects matching the filter criteria
4899     *
4900     * @throws CmsException if something goes wrong
4901     *
4902     * @see CmsObject#readProjectView(CmsUUID, CmsResourceState)
4903     */
4904    public List<CmsResource> readProjectView(CmsRequestContext context, CmsUUID projectId, CmsResourceState state)
4905    throws CmsException {
4906
4907        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4908        List<CmsResource> result = null;
4909        try {
4910            result = m_driverManager.readProjectView(dbc, projectId, state);
4911        } catch (Exception e) {
4912            dbc.report(null, Messages.get().container(Messages.ERR_READ_PROJECT_VIEW_1, projectId), e);
4913        } finally {
4914            dbc.clear();
4915        }
4916        return result;
4917    }
4918
4919    /**
4920     * Reads a property definition.<p>
4921     *
4922     * If no property definition with the given name is found,
4923     * <code>null</code> is returned.<p>
4924     *
4925     * @param context the current request context
4926     * @param name the name of the property definition to read
4927     *
4928     * @return the property definition that was read
4929     *
4930     * @throws CmsException a CmsDbEntryNotFoundException is thrown if the property definition does not exist
4931     */
4932    public CmsPropertyDefinition readPropertyDefinition(CmsRequestContext context, String name) throws CmsException {
4933
4934        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4935        CmsPropertyDefinition result = null;
4936        try {
4937            result = m_driverManager.readPropertyDefinition(dbc, name);
4938        } catch (Exception e) {
4939            dbc.report(null, Messages.get().container(Messages.ERR_READ_PROPDEF_1, name), e);
4940        } finally {
4941            dbc.clear();
4942        }
4943        return result;
4944    }
4945
4946    /**
4947     * Reads a property object from a resource specified by a property name.<p>
4948     *
4949     * Returns <code>{@link CmsProperty#getNullProperty()}</code> if the property is not found.<p>
4950     *
4951     * @param context the context of the current request
4952     * @param resource the resource where the property is mapped to
4953     * @param key the property key name
4954     * @param search if <code>true</code>, the property is searched on all parent folders of the resource.
4955     *      if it's not found attached directly to the resource.
4956     *
4957     * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found
4958     *
4959     * @throws CmsException if something goes wrong
4960     */
4961    public CmsProperty readPropertyObject(CmsRequestContext context, CmsResource resource, String key, boolean search)
4962    throws CmsException {
4963
4964        return readPropertyObject(context, resource, key, search, null);
4965    }
4966
4967    /**
4968     * Reads a property object from a resource specified by a property name.<p>
4969     *
4970     * Returns <code>{@link CmsProperty#getNullProperty()}</code> if the property is not found.<p>
4971     *
4972     * @param context the context of the current request
4973     * @param resource the resource where the property is mapped to
4974     * @param key the property key name
4975     * @param search if <code>true</code>, the property is searched on all parent folders of the resource.
4976     *      if it's not found attached directly to the resource.
4977     * @param locale the locale for which the property should be read.
4978     *
4979     * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found
4980     *
4981     * @throws CmsException if something goes wrong
4982     */
4983    public CmsProperty readPropertyObject(
4984        CmsRequestContext context,
4985        CmsResource resource,
4986        String key,
4987        boolean search,
4988        Locale locale)
4989    throws CmsException {
4990
4991        CmsProperty result = null;
4992        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4993        try {
4994            if (null == locale) {
4995                result = m_driverManager.readPropertyObject(dbc, resource, key, search);
4996            } else {
4997                result = m_driverManager.readPropertyObject(dbc, resource, key, search, locale);
4998            }
4999        } catch (Exception e) {
5000            dbc.report(
5001                null,
5002                Messages.get().container(Messages.ERR_READ_PROP_FOR_RESOURCE_2, key, context.getSitePath(resource)),
5003                e);
5004        } finally {
5005            dbc.clear();
5006        }
5007        return result;
5008    }
5009
5010    /**
5011     * Reads all property objects from a resource.<p>
5012     *
5013     * Returns an empty list if no properties are found.<p>
5014     *
5015     * If the <code>search</code> parameter is <code>true</code>, the properties of all
5016     * parent folders of the resource are also read. The results are merged with the
5017     * properties directly attached to the resource. While merging, a property
5018     * on a parent folder that has already been found will be ignored.
5019     * So e.g. if a resource has a property "Title" attached, and it's parent folder
5020     * has the same property attached but with a different value, the result list will
5021     * contain only the property with the value from the resource, not form the parent folder(s).<p>
5022     *
5023     * @param context the context of the current request
5024     * @param resource the resource where the property is mapped to
5025     * @param search <code>true</code>, if the properties should be searched on all parent folders  if not found on the resource
5026     *
5027     * @return a list of <code>{@link CmsProperty}</code> objects
5028     *
5029     * @throws CmsException if something goes wrong
5030     */
5031    public List<CmsProperty> readPropertyObjects(CmsRequestContext context, CmsResource resource, boolean search)
5032    throws CmsException {
5033
5034        List<CmsProperty> result = null;
5035        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5036        try {
5037            result = m_driverManager.readPropertyObjects(dbc, resource, search);
5038        } catch (Exception e) {
5039            dbc.report(
5040                null,
5041                Messages.get().container(Messages.ERR_READ_PROPS_FOR_RESOURCE_1, context.getSitePath(resource)),
5042                e);
5043        } finally {
5044            dbc.clear();
5045        }
5046        return result;
5047    }
5048
5049    /**
5050     * Reads the resources that were published in a publish task for a given publish history ID.<p>
5051     *
5052     * @param context the current request context
5053     * @param publishHistoryId unique ID to identify each publish task in the publish history
5054     *
5055     * @return a list of <code>{@link org.opencms.db.CmsPublishedResource}</code> objects
5056     *
5057     * @throws CmsException if something goes wrong
5058     */
5059    public List<CmsPublishedResource> readPublishedResources(CmsRequestContext context, CmsUUID publishHistoryId)
5060    throws CmsException {
5061
5062        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5063        List<CmsPublishedResource> result = null;
5064        try {
5065            result = m_driverManager.readPublishedResources(dbc, publishHistoryId);
5066        } catch (Exception e) {
5067            dbc.report(
5068                null,
5069                Messages.get().container(Messages.ERR_READ_PUBLISHED_RESOURCES_FOR_ID_1, publishHistoryId.toString()),
5070                e);
5071        } finally {
5072            dbc.clear();
5073        }
5074        return result;
5075    }
5076
5077    /**
5078     * Reads the historical resource entry for the given resource with the given version number.<p>
5079     *
5080     * @param context the current request context
5081     * @param resource the resource to be read the version for
5082     * @param version the version number to retrieve
5083     *
5084     * @return the resource that was read
5085     *
5086     * @throws CmsException if the resource could not be read for any reason
5087     *
5088     * @see CmsObject#readFile(CmsResource)
5089     * @see CmsObject#restoreResourceVersion(CmsUUID, int)
5090     * @see CmsObject#readResource(CmsUUID, int)
5091     */
5092    public I_CmsHistoryResource readResource(CmsRequestContext context, CmsResource resource, int version)
5093    throws CmsException {
5094
5095        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5096        I_CmsHistoryResource result = null;
5097        try {
5098            result = m_driverManager.readResource(dbc, resource, version);
5099        } catch (CmsException e) {
5100            dbc.report(
5101                null,
5102                Messages.get().container(
5103                    Messages.ERR_READING_RESOURCE_VERSION_2,
5104                    dbc.removeSiteRoot(resource.getRootPath()),
5105                    new Integer(version)),
5106                e);
5107        } finally {
5108            dbc.clear();
5109        }
5110        return result;
5111    }
5112
5113    /**
5114     * Reads a resource from the VFS,
5115     * using the specified resource filter.<p>
5116     *
5117     * A resource may be of type <code>{@link CmsFile}</code> or
5118     * <code>{@link CmsFolder}</code>. In case of
5119     * a file, the resource will not contain the binary file content. Since reading
5120     * the binary content is a cost-expensive database operation, it's recommended
5121     * to work with resources if possible, and only read the file content when absolutely
5122     * required. To "upgrade" a resource to a file,
5123     * use <code>{@link CmsObject#readFile(CmsResource)}</code>.<p>
5124     *
5125     * The specified filter controls what kind of resources should be "found"
5126     * during the read operation. This will depend on the application. For example,
5127     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
5128     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
5129     * will ignore the date release / date expired information of the resource.<p>
5130     *
5131     * @param context the current request context
5132     * @param structureID the ID of the structure which will be used)
5133     * @param filter the resource filter to use while reading
5134     *
5135     * @return the resource that was read
5136     *
5137     * @throws CmsException if the resource could not be read for any reason
5138     *
5139     * @see CmsObject#readResource(CmsUUID, CmsResourceFilter)
5140     * @see CmsObject#readResource(CmsUUID)
5141     * @see CmsObject#readFile(CmsResource)
5142     */
5143    public CmsResource readResource(CmsRequestContext context, CmsUUID structureID, CmsResourceFilter filter)
5144    throws CmsException {
5145
5146        CmsResource result = null;
5147        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5148        try {
5149            result = readResource(dbc, structureID, filter);
5150        } catch (Exception e) {
5151            dbc.report(null, Messages.get().container(Messages.ERR_READ_RESOURCE_FOR_ID_1, structureID), e);
5152        } finally {
5153            dbc.clear();
5154        }
5155        return result;
5156    }
5157
5158    /**
5159     * Reads a resource from the VFS,
5160     * using the specified resource filter.<p>
5161     *
5162     * A resource may be of type <code>{@link CmsFile}</code> or
5163     * <code>{@link CmsFolder}</code>. In case of
5164     * a file, the resource will not contain the binary file content. Since reading
5165     * the binary content is a cost-expensive database operation, it's recommended
5166     * to work with resources if possible, and only read the file content when absolutely
5167     * required. To "upgrade" a resource to a file,
5168     * use <code>{@link CmsObject#readFile(CmsResource)}</code>.<p>
5169     *
5170     * The specified filter controls what kind of resources should be "found"
5171     * during the read operation. This will depend on the application. For example,
5172     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
5173     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
5174     * will ignore the date release / date expired information of the resource.<p>
5175     *
5176     * @param context the current request context
5177     * @param resourcePath the name of the resource to read (full path)
5178     * @param filter the resource filter to use while reading
5179     *
5180     * @return the resource that was read
5181     *
5182     * @throws CmsException if the resource could not be read for any reason
5183     *
5184     * @see CmsObject#readResource(String, CmsResourceFilter)
5185     * @see CmsObject#readResource(String)
5186     * @see CmsObject#readFile(CmsResource)
5187     */
5188    public CmsResource readResource(CmsRequestContext context, String resourcePath, CmsResourceFilter filter)
5189    throws CmsException {
5190
5191        CmsResource result = null;
5192        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5193        try {
5194            result = readResource(dbc, resourcePath, filter);
5195        } catch (Exception e) {
5196            dbc.report(
5197                null,
5198                Messages.get().container(Messages.ERR_READ_RESOURCE_1, dbc.removeSiteRoot(resourcePath)),
5199                e);
5200        } finally {
5201            dbc.clear();
5202        }
5203        return result;
5204    }
5205
5206    /**
5207     * Reads all resources below the given path matching the filter criteria,
5208     * including the full tree below the path only in case the <code>readTree</code>
5209     * parameter is <code>true</code>.<p>
5210     *
5211     * @param context the current request context
5212     * @param parent the parent path to read the resources from
5213     * @param filter the filter
5214     * @param readTree <code>true</code> to read all subresources
5215     *
5216     * @return a list of <code>{@link CmsResource}</code> objects matching the filter criteria
5217     *
5218     * @throws CmsSecurityException if the user has insufficient permission for the given resource (read is required)
5219     * @throws CmsException if something goes wrong
5220     *
5221     */
5222    public List<CmsResource> readResources(
5223        CmsRequestContext context,
5224        CmsResource parent,
5225        CmsResourceFilter filter,
5226        boolean readTree)
5227    throws CmsException, CmsSecurityException {
5228
5229        List<CmsResource> result = null;
5230        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5231        try {
5232            // check the access permissions
5233            checkPermissions(dbc, parent, CmsPermissionSet.ACCESS_READ, true, CmsResourceFilter.ALL);
5234            result = m_driverManager.readResources(dbc, parent, filter, readTree);
5235        } catch (Exception e) {
5236            dbc.report(
5237                null,
5238                Messages.get().container(Messages.ERR_READ_RESOURCES_1, context.removeSiteRoot(parent.getRootPath())),
5239                e);
5240        } finally {
5241            dbc.clear();
5242        }
5243        return result;
5244    }
5245
5246    /**
5247     * Returns the resources that were visited by a user set in the filter.<p>
5248     *
5249     * @param context the request context
5250     * @param poolName the name of the database pool to use
5251     * @param filter the filter that is used to get the visited resources
5252     *
5253     * @return the resources that were visited by a user set in the filter
5254     *
5255     * @throws CmsException if something goes wrong
5256     */
5257    public List<CmsResource> readResourcesVisitedBy(
5258        CmsRequestContext context,
5259        String poolName,
5260        CmsVisitedByFilter filter)
5261    throws CmsException {
5262
5263        List<CmsResource> result = null;
5264        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5265        try {
5266            result = m_driverManager.readResourcesVisitedBy(dbc, poolName, filter);
5267        } catch (Exception e) {
5268            dbc.report(null, Messages.get().container(Messages.ERR_READ_VISITED_RESOURCES_1, filter.toString()), e);
5269        } finally {
5270            dbc.clear();
5271        }
5272        return result;
5273    }
5274
5275    /**
5276     * Reads all resources that have a value (containing the specified value) set
5277     * for the specified property (definition) in the given path.<p>
5278     *
5279     * If the <code>value</code> parameter is <code>null</code>, all resources having the
5280     * given property set are returned.<p>
5281     *
5282     * Both individual and shared properties of a resource are checked.<p>
5283     *
5284     * @param context the current request context
5285     * @param folder the folder to get the resources with the property from
5286     * @param propertyDefinition the name of the property (definition) to check for
5287     * @param value the string to search in the value of the property
5288     * @param filter the resource filter to apply to the result set
5289     *
5290     * @return a list of all <code>{@link CmsResource}</code> objects
5291     *          that have a value set for the specified property.
5292     *
5293     * @throws CmsException if something goes wrong
5294     */
5295    public List<CmsResource> readResourcesWithProperty(
5296        CmsRequestContext context,
5297        CmsResource folder,
5298        String propertyDefinition,
5299        String value,
5300        CmsResourceFilter filter)
5301    throws CmsException {
5302
5303        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5304        List<CmsResource> result = null;
5305        try {
5306            result = m_driverManager.readResourcesWithProperty(dbc, folder, propertyDefinition, value, filter);
5307        } catch (Exception e) {
5308            dbc.report(
5309                null,
5310                Messages.get().container(
5311                    Messages.ERR_READ_RESOURCES_FOR_PROP_VALUE_3,
5312                    context.removeSiteRoot(folder.getRootPath()),
5313                    propertyDefinition,
5314                    value),
5315                e);
5316        } finally {
5317            dbc.clear();
5318        }
5319        return result;
5320    }
5321
5322    /**
5323     * Returns a set of users that are responsible for a specific resource.<p>
5324     *
5325     * @param context the current request context
5326     * @param resource the resource to get the responsible users from
5327     *
5328     * @return the set of users that are responsible for a specific resource
5329     *
5330     * @throws CmsException if something goes wrong
5331     */
5332    public Set<I_CmsPrincipal> readResponsiblePrincipals(CmsRequestContext context, CmsResource resource)
5333    throws CmsException {
5334
5335        Set<I_CmsPrincipal> result = null;
5336        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5337        try {
5338            result = m_driverManager.readResponsiblePrincipals(dbc, resource);
5339        } catch (Exception e) {
5340            dbc.report(
5341                null,
5342                Messages.get().container(Messages.ERR_READ_RESPONSIBLE_USERS_1, resource.getRootPath()),
5343                e);
5344        } finally {
5345            dbc.clear();
5346        }
5347        return result;
5348    }
5349
5350    /**
5351     * Returns a set of users that are responsible for a specific resource.<p>
5352     *
5353     * @param context the current request context
5354     * @param resource the resource to get the responsible users from
5355     *
5356     * @return the set of users that are responsible for a specific resource
5357     *
5358     * @throws CmsException if something goes wrong
5359     */
5360    public Set<CmsUser> readResponsibleUsers(CmsRequestContext context, CmsResource resource) throws CmsException {
5361
5362        Set<CmsUser> result = null;
5363        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5364        try {
5365            result = m_driverManager.readResponsibleUsers(dbc, resource);
5366        } catch (Exception e) {
5367            dbc.report(
5368                null,
5369                Messages.get().container(Messages.ERR_READ_RESPONSIBLE_USERS_1, resource.getRootPath()),
5370                e);
5371        } finally {
5372            dbc.clear();
5373        }
5374        return result;
5375    }
5376
5377    /**
5378     * Returns a List of all siblings of the specified resource,
5379     * the specified resource being always part of the result set.<p>
5380     *
5381     * @param context the request context
5382     * @param resource the specified resource
5383     * @param filter a filter object
5384     *
5385     * @return a list of <code>{@link CmsResource}</code>s that
5386     *          are siblings to the specified resource,
5387     *          including the specified resource itself
5388     *
5389     * @throws CmsException if something goes wrong
5390     */
5391    public List<CmsResource> readSiblings(CmsRequestContext context, CmsResource resource, CmsResourceFilter filter)
5392    throws CmsException {
5393
5394        List<CmsResource> result = null;
5395        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5396        try {
5397            result = m_driverManager.readSiblings(dbc, resource, filter);
5398        } catch (Exception e) {
5399            dbc.report(null, Messages.get().container(Messages.ERR_READ_SIBLINGS_1, context.getSitePath(resource)), e);
5400        } finally {
5401            dbc.clear();
5402        }
5403        return result;
5404    }
5405
5406    /**
5407     * Returns the parameters of a resource in the table of all published template resources.<p>
5408     *
5409     * @param context the current request context
5410     * @param rfsName the rfs name of the resource
5411     *
5412     * @return the parameter string of the requested resource
5413     *
5414     * @throws CmsException if something goes wrong
5415     */
5416    public String readStaticExportPublishedResourceParameters(CmsRequestContext context, String rfsName)
5417    throws CmsException {
5418
5419        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5420        String result = null;
5421        try {
5422            result = m_driverManager.readStaticExportPublishedResourceParameters(dbc, rfsName);
5423        } catch (Exception e) {
5424            dbc.report(
5425                null,
5426                Messages.get().container(Messages.ERR_READ_STATEXP_PUBLISHED_RESOURCE_PARAMS_1, rfsName),
5427                e);
5428        } finally {
5429            dbc.clear();
5430        }
5431        return result;
5432    }
5433
5434    /**
5435     * Returns a list of all template resources which must be processed during a static export.<p>
5436     *
5437     * @param context the current request context
5438     * @param parameterResources flag for reading resources with parameters (1) or without (0)
5439     * @param timestamp for reading the data from the db
5440     *
5441     * @return a list of template resources as <code>{@link String}</code> objects
5442     *
5443     * @throws CmsException if something goes wrong
5444     */
5445    public List<String> readStaticExportResources(CmsRequestContext context, int parameterResources, long timestamp)
5446    throws CmsException {
5447
5448        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5449        List<String> result = null;
5450        try {
5451            result = m_driverManager.readStaticExportResources(dbc, parameterResources, timestamp);
5452        } catch (Exception e) {
5453            dbc.report(null, Messages.get().container(Messages.ERR_READ_STATEXP_RESOURCES_1, new Date(timestamp)), e);
5454        } finally {
5455            dbc.clear();
5456        }
5457        return result;
5458    }
5459
5460    /**
5461     * Returns the subscribed history resources that were deleted.<p>
5462     *
5463     * @param context the request context
5464     * @param poolName the name of the database pool to use
5465     * @param user the user that subscribed to the resource
5466     * @param groups the groups to check subscribed resources for
5467     * @param parent the parent resource (folder) of the deleted resources, if <code>null</code> all deleted resources will be returned
5468     * @param includeSubFolders indicates if the sub folders of the specified folder path should be considered, too
5469     * @param deletedFrom the time stamp from which the resources should have been deleted
5470     *
5471     * @return the subscribed history resources that were deleted
5472     *
5473     * @throws CmsException if something goes wrong
5474     */
5475    public List<I_CmsHistoryResource> readSubscribedDeletedResources(
5476        CmsRequestContext context,
5477        String poolName,
5478        CmsUser user,
5479        List<CmsGroup> groups,
5480        CmsResource parent,
5481        boolean includeSubFolders,
5482        long deletedFrom)
5483    throws CmsException {
5484
5485        List<I_CmsHistoryResource> result = null;
5486        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5487        try {
5488            result = m_driverManager.readSubscribedDeletedResources(
5489                dbc,
5490                poolName,
5491                user,
5492                groups,
5493                parent,
5494                includeSubFolders,
5495                deletedFrom);
5496        } catch (Exception e) {
5497            dbc.report(
5498                null,
5499                Messages.get().container(Messages.ERR_READ_SUBSCRIBED_DELETED_RESOURCES_1, user.getName()),
5500                e);
5501        } finally {
5502            dbc.clear();
5503        }
5504        return result;
5505    }
5506
5507    /**
5508     * Returns the resources that were subscribed by a user or group set in the filter.<p>
5509     *
5510     * @param context the request context
5511     * @param poolName the name of the database pool to use
5512     * @param filter the filter that is used to get the subscribed resources
5513     *
5514     * @return the resources that were subscribed by a user or group set in the filter
5515     *
5516     * @throws CmsException if something goes wrong
5517     */
5518    public List<CmsResource> readSubscribedResources(
5519        CmsRequestContext context,
5520        String poolName,
5521        CmsSubscriptionFilter filter)
5522    throws CmsException {
5523
5524        List<CmsResource> result = null;
5525        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5526        try {
5527            result = m_driverManager.readSubscribedResources(dbc, poolName, filter);
5528        } catch (Exception e) {
5529            dbc.report(null, Messages.get().container(Messages.ERR_READ_SUBSCRIBED_RESOURCES_1, filter.toString()), e);
5530        } finally {
5531            dbc.clear();
5532        }
5533        return result;
5534    }
5535
5536    /**
5537     * Reads the URL name mappings matching a given filter.<p>
5538     *
5539     * @param context the current request context
5540     * @param filter the filter to match
5541     *
5542     * @return the matching URL name mappings
5543     *
5544     * @throws CmsException if something goes wrong
5545     */
5546    public List<CmsUrlNameMappingEntry> readUrlNameMappings(CmsRequestContext context, CmsUrlNameMappingFilter filter)
5547    throws CmsException {
5548
5549        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5550        try {
5551            return m_driverManager.readUrlNameMappings(dbc, filter);
5552        } catch (Exception e) {
5553            CmsMessageContainer message = Messages.get().container(
5554                Messages.ERR_DB_OPERATION_1,
5555                e.getLocalizedMessage());
5556            dbc.report(null, message, e);
5557            return null; // will never be reached
5558        } finally {
5559            dbc.clear();
5560        }
5561    }
5562
5563    /**
5564     * Reads the newest URL names of a structure id for all locales.<p>
5565     *
5566     * @param context the current context
5567     * @param id a structure id
5568     *
5569     * @return the list of URL names for all
5570     * @throws CmsException if something goes wrong
5571     */
5572    public List<String> readUrlNamesForAllLocales(CmsRequestContext context, CmsUUID id) throws CmsException {
5573
5574        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5575        try {
5576            return m_driverManager.readUrlNamesForAllLocales(dbc, id);
5577        } catch (Exception e) {
5578            CmsMessageContainer message = Messages.get().container(
5579                Messages.ERR_READ_NEWEST_URLNAME_FOR_ID_1,
5580                id.toString());
5581            dbc.report(null, message, e);
5582            return null; // will never be reached
5583        } finally {
5584            dbc.clear();
5585        }
5586    }
5587
5588    /**
5589     * Returns a user object based on the id of a user.<p>
5590     *
5591     * @param context the current request context
5592     * @param id the id of the user to read
5593     *
5594     * @return the user read
5595     *
5596     * @throws CmsException if something goes wrong
5597     */
5598    public CmsUser readUser(CmsRequestContext context, CmsUUID id) throws CmsException {
5599
5600        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5601        CmsUser result = null;
5602        try {
5603            result = m_driverManager.readUser(dbc, id);
5604        } catch (Exception e) {
5605            dbc.report(null, Messages.get().container(Messages.ERR_READ_USER_FOR_ID_1, id.toString()), e);
5606        } finally {
5607            dbc.clear();
5608        }
5609        return result;
5610    }
5611
5612    /**
5613     * Returns a user object.<p>
5614     *
5615     * @param context the current request context
5616     * @param username the name of the user that is to be read
5617     *
5618     * @return user read form the cms
5619     *
5620     * @throws CmsException if operation was not successful
5621     */
5622    public CmsUser readUser(CmsRequestContext context, String username) throws CmsException {
5623
5624        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5625        CmsUser result = null;
5626        try {
5627            result = m_driverManager.readUser(dbc, CmsOrganizationalUnit.removeLeadingSeparator(username));
5628        } catch (Exception e) {
5629            dbc.report(null, Messages.get().container(Messages.ERR_READ_USER_FOR_NAME_1, username), e);
5630        } finally {
5631            dbc.clear();
5632        }
5633        return result;
5634    }
5635
5636    /**
5637     * Returns a user object if the password for the user is correct.<p>
5638     *
5639     * If the user/password pair is not valid a <code>{@link CmsException}</code> is thrown.<p>
5640     *
5641     * @param context the current request context
5642     * @param username the user name of the user that is to be read
5643     * @param password the password of the user that is to be read
5644     *
5645     * @return user read
5646     *
5647     * @throws CmsException if operation was not successful
5648     */
5649    public CmsUser readUser(CmsRequestContext context, String username, String password) throws CmsException {
5650
5651        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5652        CmsUser result = null;
5653        try {
5654            result = m_driverManager.readUser(dbc, CmsOrganizationalUnit.removeLeadingSeparator(username), password);
5655        } catch (Exception e) {
5656            dbc.report(null, Messages.get().container(Messages.ERR_READ_USER_FOR_NAME_1, username), e);
5657        } finally {
5658            dbc.clear();
5659        }
5660        return result;
5661    }
5662
5663    /**
5664     * Removes an access control entry for a given resource and principal.<p>
5665     *
5666     * @param context the current request context
5667     * @param resource the resource
5668     * @param principal the id of the principal to remove the the access control entry for
5669     *
5670     * @throws CmsException if something goes wrong
5671     * @throws CmsSecurityException if the user has insufficient permission for the given resource (control of access control is required).
5672     *
5673     */
5674    public void removeAccessControlEntry(CmsRequestContext context, CmsResource resource, CmsUUID principal)
5675    throws CmsException, CmsSecurityException {
5676
5677        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5678        try {
5679            checkOfflineProject(dbc);
5680            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_CONTROL, true, CmsResourceFilter.ALL);
5681            m_driverManager.removeAccessControlEntry(dbc, resource, principal);
5682        } catch (Exception e) {
5683            dbc.report(
5684                null,
5685                Messages.get().container(
5686                    Messages.ERR_REMOVE_ACL_ENTRY_2,
5687                    context.getSitePath(resource),
5688                    principal.toString()),
5689                e);
5690        } finally {
5691            dbc.clear();
5692        }
5693    }
5694
5695    /**
5696     * Removes a resource from the given organizational unit.<p>
5697     *
5698     * @param context the current request context
5699     * @param orgUnit the organizational unit to remove the resource from
5700     * @param resource the resource that is to be removed from the organizational unit
5701     *
5702     * @throws CmsException if something goes wrong
5703     *
5704     * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String)
5705     * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String)
5706     */
5707    public void removeResourceFromOrgUnit(
5708        CmsRequestContext context,
5709        CmsOrganizationalUnit orgUnit,
5710        CmsResource resource)
5711    throws CmsException {
5712
5713        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5714        try {
5715            checkRole(dbc, CmsRole.ADMINISTRATOR.forOrgUnit(orgUnit.getName()));
5716            checkOfflineProject(dbc);
5717            m_driverManager.removeResourceFromOrgUnit(dbc, orgUnit, resource);
5718        } catch (Exception e) {
5719            dbc.report(
5720                null,
5721                Messages.get().container(
5722                    Messages.ERR_REMOVE_RESOURCE_FROM_ORGUNIT_2,
5723                    orgUnit.getName(),
5724                    dbc.removeSiteRoot(resource.getRootPath())),
5725                e);
5726        } finally {
5727            dbc.clear();
5728        }
5729    }
5730
5731    /**
5732     * Removes a resource from the current project of the user.<p>
5733     *
5734     * @param context the current request context
5735     * @param resource the resource to apply this operation to
5736     *
5737     * @throws CmsException if something goes wrong
5738     * @throws CmsRoleViolationException if the current user does not have management access to the project
5739     *
5740     * @see org.opencms.file.types.I_CmsResourceType#copyResourceToProject(CmsObject, CmsSecurityManager, CmsResource)
5741     */
5742    public void removeResourceFromProject(CmsRequestContext context, CmsResource resource)
5743    throws CmsException, CmsRoleViolationException {
5744
5745        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5746        try {
5747            checkOfflineProject(dbc);
5748            checkManagerOfProjectRole(dbc, context.getCurrentProject());
5749
5750            m_driverManager.removeResourceFromProject(dbc, resource);
5751        } catch (Exception e) {
5752            dbc.report(
5753                null,
5754                Messages.get().container(
5755                    Messages.ERR_COPY_RESOURCE_TO_PROJECT_2,
5756                    context.getSitePath(resource),
5757                    context.getCurrentProject().getName()),
5758                e);
5759        } finally {
5760            dbc.clear();
5761        }
5762    }
5763
5764    /**
5765     * Removes the given resource to the given user's publish list.<p>
5766     *
5767     * @param context the request context
5768     * @param structureIds the collection of structure IDs to remove
5769     *
5770     * @throws CmsException if something goes wrong
5771     */
5772    public void removeResourceFromUsersPubList(CmsRequestContext context, Collection<CmsUUID> structureIds)
5773    throws CmsException {
5774
5775        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5776        try {
5777            m_driverManager.removeResourceFromUsersPubList(dbc, context.getCurrentUser().getId(), structureIds);
5778        } catch (Exception e) {
5779            dbc.report(
5780                null,
5781                Messages.get().container(
5782                    Messages.ERR_REMOVE_RESOURCE_FROM_PUBLIST_2,
5783                    context.getCurrentUser().getName(),
5784                    structureIds),
5785                e);
5786
5787        } finally {
5788            dbc.clear();
5789        }
5790    }
5791
5792    /**
5793     * Removes a user from a group.<p>
5794     *
5795     * @param context the current request context
5796     * @param username the name of the user that is to be removed from the group
5797     * @param groupname the name of the group
5798     * @param readRoles if to read roles or groups
5799     *
5800     * @throws CmsException if operation was not successful
5801     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
5802     *
5803     */
5804    public void removeUserFromGroup(CmsRequestContext context, String username, String groupname, boolean readRoles)
5805    throws CmsException, CmsRoleViolationException {
5806
5807        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5808        try {
5809            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(groupname));
5810            checkRoleForUserModification(dbc, username, role);
5811            m_driverManager.removeUserFromGroup(
5812                dbc,
5813                CmsOrganizationalUnit.removeLeadingSeparator(username),
5814                CmsOrganizationalUnit.removeLeadingSeparator(groupname),
5815                readRoles);
5816        } catch (Exception e) {
5817            dbc.report(null, Messages.get().container(Messages.ERR_REMOVE_USER_FROM_GROUP_2, username, groupname), e);
5818        } finally {
5819            dbc.clear();
5820        }
5821    }
5822
5823    /**
5824     * Replaces the content, type and properties of a resource.<p>
5825     *
5826     * @param context the current request context
5827     * @param resource the name of the resource to apply this operation to
5828     * @param type the new type of the resource
5829     * @param content the new content of the resource
5830     * @param properties the new properties of the resource
5831     *
5832     * @throws CmsException if something goes wrong
5833     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
5834     *
5835     * @see CmsObject#replaceResource(String, int, byte[], List)
5836     * @see org.opencms.file.types.I_CmsResourceType#replaceResource(CmsObject, CmsSecurityManager, CmsResource, int, byte[], List)
5837     */
5838    @SuppressWarnings("javadoc")
5839    public void replaceResource(
5840        CmsRequestContext context,
5841        CmsResource resource,
5842        int type,
5843        byte[] content,
5844        List<CmsProperty> properties)
5845    throws CmsException, CmsSecurityException {
5846
5847        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5848        try {
5849            checkOfflineProject(dbc);
5850            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
5851            if (CmsResourceTypeJsp.isJspTypeId(type)) {
5852                // security check preventing the creation of a jsp file without permissions
5853                checkRoleForResource(dbc, CmsRole.VFS_MANAGER, resource);
5854            }
5855            m_driverManager.replaceResource(dbc, resource, type, content, properties);
5856        } catch (Exception e) {
5857            dbc.report(
5858                null,
5859                Messages.get().container(Messages.ERR_REPLACE_RESOURCE_1, context.getSitePath(resource)),
5860                e);
5861        } finally {
5862            dbc.clear();
5863        }
5864    }
5865
5866    /**
5867     * Resets the password for a specified user.<p>
5868     *
5869     * @param context the current request context
5870     * @param username the name of the user
5871     * @param oldPassword the old password
5872     * @param secondFactor the additional information for 2FA
5873     * @param newPassword the new password
5874     *
5875     * @throws CmsException if the user data could not be read from the database
5876     * @throws CmsSecurityException if the specified user name and old password could not be verified
5877     */
5878    public void resetPassword(
5879        CmsRequestContext context,
5880        String username,
5881        String oldPassword,
5882        CmsSecondFactorInfo secondFactor,
5883        String newPassword)
5884    throws CmsException, CmsSecurityException {
5885
5886        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5887        try {
5888            m_driverManager.resetPassword(
5889                dbc,
5890                CmsOrganizationalUnit.removeLeadingSeparator(username),
5891                oldPassword,
5892                secondFactor,
5893                newPassword);
5894        } catch (Exception e) {
5895            dbc.report(null, Messages.get().container(Messages.ERR_RESET_PASSWORD_1, username), e);
5896        } finally {
5897            dbc.clear();
5898        }
5899    }
5900
5901    /**
5902     * Returns the original path of given resource, that is the online path for the resource.<p>
5903     *
5904     * If it differs from the offline path, the resource has been moved.<p>
5905     *
5906     * @param context the current request context
5907     * @param resource the resource to get the path for
5908     *
5909     * @return the online path
5910     *
5911     * @throws CmsException if something goes wrong
5912     *
5913     * @see org.opencms.workplace.commons.CmsUndoChanges#resourceOriginalPath(CmsObject, String)
5914     */
5915    public String resourceOriginalPath(CmsRequestContext context, CmsResource resource) throws CmsException {
5916
5917        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5918        String result = null;
5919        try {
5920            checkOfflineProject(dbc);
5921            result = m_driverManager.getVfsDriver(
5922                dbc).readResource(dbc, CmsProject.ONLINE_PROJECT_ID, resource.getStructureId(), true).getRootPath();
5923        } catch (Exception e) {
5924            dbc.report(
5925                null,
5926                Messages.get().container(
5927                    Messages.ERR_TEST_MOVED_RESOURCE_1,
5928                    dbc.removeSiteRoot(resource.getRootPath())),
5929                e);
5930        } finally {
5931            dbc.clear();
5932        }
5933        return result;
5934    }
5935
5936    /**
5937     * Restores a deleted resource identified by its structure id from the historical archive.<p>
5938     *
5939     * @param context the current request context
5940     * @param structureId the structure id of the resource to restore
5941     *
5942     * @throws CmsException if something goes wrong
5943     *
5944     * @see CmsObject#restoreDeletedResource(CmsUUID)
5945     */
5946    public void restoreDeletedResource(CmsRequestContext context, CmsUUID structureId) throws CmsException {
5947
5948        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5949        try {
5950            checkOfflineProject(dbc);
5951            // write permissions on parent folder are checked later
5952            m_driverManager.restoreDeletedResource(dbc, structureId);
5953        } catch (Exception e) {
5954            dbc.report(null, Messages.get().container(Messages.ERR_RESTORE_DELETED_RESOURCE_1, structureId), e);
5955        } finally {
5956            dbc.clear();
5957        }
5958    }
5959
5960    /**
5961     * Restores a resource in the current project with the given version from the historical archive.<p>
5962     *
5963     * @param context the current request context
5964     * @param resource the resource to restore from the archive
5965     * @param version the version number to restore
5966     *
5967     * @throws CmsException if something goes wrong
5968     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
5969     *
5970     * @see CmsObject#restoreResourceVersion(CmsUUID, int)
5971     * @see org.opencms.file.types.I_CmsResourceType#restoreResource(CmsObject, CmsSecurityManager, CmsResource, int)
5972     */
5973    public void restoreResource(CmsRequestContext context, CmsResource resource, int version)
5974    throws CmsException, CmsSecurityException {
5975
5976        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5977        try {
5978            checkOfflineProject(dbc);
5979            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
5980            m_driverManager.restoreResource(dbc, resource, version);
5981        } catch (Exception e) {
5982            dbc.report(
5983                null,
5984                Messages.get().container(
5985                    Messages.ERR_RESTORE_RESOURCE_2,
5986                    context.getSitePath(resource),
5987                    new Integer(version)),
5988                e);
5989        } finally {
5990            dbc.clear();
5991        }
5992    }
5993
5994    /**
5995     * Saves the aliases for a given resource.<p>
5996     *
5997     * This method completely replaces any existing aliases for the same structure id.
5998     *
5999     * @param context the request context
6000     * @param resource the resource for which the aliases should be written
6001     * @param aliases the list of aliases to write, where all aliases must have the same structure id as the resource
6002     *
6003     * @throws CmsException if something goes wrong
6004     */
6005    public void saveAliases(CmsRequestContext context, CmsResource resource, List<CmsAlias> aliases)
6006    throws CmsException {
6007
6008        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6009        try {
6010            if ((aliases.size() > 0) && !(resource.getStructureId().equals(aliases.get(0).getStructureId()))) {
6011                throw new IllegalArgumentException("Resource does not match aliases!");
6012            }
6013            checkPermissions(context, resource, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL);
6014            m_driverManager.saveAliases(dbc, context.getCurrentProject(), resource.getStructureId(), aliases);
6015            Map<String, Object> eventData = new HashMap<String, Object>();
6016            eventData.put(I_CmsEventListener.KEY_RESOURCE, resource);
6017            eventData.put(I_CmsEventListener.KEY_CHANGE, new Integer(CmsDriverManager.CHANGED_RESOURCE));
6018            OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, eventData));
6019        } catch (Exception e) {
6020            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
6021        } finally {
6022            dbc.clear();
6023        }
6024    }
6025
6026    /**
6027     * Replaces the rewrite aliases for a given site root.<p>
6028     *
6029     * @param requestContext the current request context
6030     * @param siteRoot the site root for which the rewrite aliases should be replaced
6031     * @param newAliases the new list of aliases for the given site root
6032     *
6033     * @throws CmsException if something goes wrong
6034     */
6035    public void saveRewriteAliases(CmsRequestContext requestContext, String siteRoot, List<CmsRewriteAlias> newAliases)
6036    throws CmsException {
6037
6038        CmsDbContext dbc = m_dbContextFactory.getDbContext(requestContext);
6039        try {
6040            //            checkOfflineProject(dbc);
6041            //            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
6042            m_driverManager.saveRewriteAliases(dbc, siteRoot, newAliases);
6043        } catch (Exception e) {
6044            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
6045        } finally {
6046            dbc.clear();
6047        }
6048    }
6049
6050    /**
6051     * Searches users by search criteria.<p>
6052     *
6053     * @param requestContext the request context
6054     * @param searchParams the search criteria object
6055     *
6056     * @return a list of users
6057     * @throws CmsException if something goes wrong
6058     */
6059    public List<CmsUser> searchUsers(CmsRequestContext requestContext, CmsUserSearchParameters searchParams)
6060    throws CmsException {
6061
6062        CmsDbContext dbc = m_dbContextFactory.getDbContext(requestContext);
6063        try {
6064            return m_driverManager.searchUsers(dbc, searchParams);
6065        } catch (Exception e) {
6066            dbc.report(null, Messages.get().container(Messages.ERR_SEARCH_USERS_0), e);
6067            return null;
6068        } finally {
6069            dbc.clear();
6070        }
6071    }
6072
6073    /**
6074     * Changes the "expire" date of a resource.<p>
6075     *
6076     * @param context the current request context
6077     * @param resource the resource to touch
6078     * @param dateExpired the new expire date of the changed resource
6079     *
6080     * @throws CmsException if something goes wrong
6081     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
6082     *
6083     * @see CmsObject#setDateExpired(String, long, boolean)
6084     * @see org.opencms.file.types.I_CmsResourceType#setDateExpired(CmsObject, CmsSecurityManager, CmsResource, long, boolean)
6085     */
6086    public void setDateExpired(CmsRequestContext context, CmsResource resource, long dateExpired)
6087    throws CmsException, CmsSecurityException {
6088
6089        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6090        try {
6091            checkOfflineProject(dbc);
6092            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.IGNORE_EXPIRATION);
6093            m_driverManager.setDateExpired(dbc, resource, dateExpired);
6094        } catch (Exception e) {
6095            dbc.report(
6096                null,
6097                Messages.get().container(
6098                    Messages.ERR_SET_DATE_EXPIRED_2,
6099                    new Object[] {new Date(dateExpired), context.getSitePath(resource)}),
6100                e);
6101        } finally {
6102            dbc.clear();
6103        }
6104    }
6105
6106    /**
6107     * Changes the "last modified" time stamp of a resource.<p>
6108     *
6109     * @param context the current request context
6110     * @param resource the resource to touch
6111     * @param dateLastModified the new time stamp of the changed resource
6112     *
6113     * @throws CmsException if something goes wrong
6114     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
6115     *
6116     * @see CmsObject#setDateLastModified(String, long, boolean)
6117     * @see org.opencms.file.types.I_CmsResourceType#setDateLastModified(CmsObject, CmsSecurityManager, CmsResource, long, boolean)
6118     */
6119    public void setDateLastModified(CmsRequestContext context, CmsResource resource, long dateLastModified)
6120    throws CmsException, CmsSecurityException {
6121
6122        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6123        try {
6124            checkOfflineProject(dbc);
6125            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.IGNORE_EXPIRATION);
6126            m_driverManager.setDateLastModified(dbc, resource, dateLastModified);
6127        } catch (Exception e) {
6128            dbc.report(
6129                null,
6130                Messages.get().container(
6131                    Messages.ERR_SET_DATE_LAST_MODIFIED_2,
6132                    new Object[] {new Date(dateLastModified), context.getSitePath(resource)}),
6133                e);
6134        } finally {
6135            dbc.clear();
6136        }
6137    }
6138
6139    /**
6140     * Changes the "release" date of a resource.<p>
6141     *
6142     * @param context the current request context
6143     * @param resource the resource to touch
6144     * @param dateReleased the new release date of the changed resource
6145     *
6146     * @throws CmsException if something goes wrong
6147     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
6148     *
6149     * @see CmsObject#setDateReleased(String, long, boolean)
6150     * @see org.opencms.file.types.I_CmsResourceType#setDateReleased(CmsObject, CmsSecurityManager, CmsResource, long, boolean)
6151     */
6152    public void setDateReleased(CmsRequestContext context, CmsResource resource, long dateReleased)
6153    throws CmsException, CmsSecurityException {
6154
6155        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6156        try {
6157            checkOfflineProject(dbc);
6158            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.IGNORE_EXPIRATION);
6159            m_driverManager.setDateReleased(dbc, resource, dateReleased);
6160        } catch (Exception e) {
6161            dbc.report(
6162                null,
6163                Messages.get().container(
6164                    Messages.ERR_SET_DATE_RELEASED_2,
6165                    new Object[] {new Date(dateReleased), context.getSitePath(resource)}),
6166                e);
6167        } finally {
6168            dbc.clear();
6169        }
6170    }
6171
6172    /**
6173     * Sets a new parent-group for an already existing group.<p>
6174     *
6175     * @param context the current request context
6176     * @param groupName the name of the group that should be written
6177     * @param parentGroupName the name of the parent group to set,
6178     *                      or <code>null</code> if the parent
6179     *                      group should be deleted.
6180     *
6181     * @throws CmsException if operation was not successful
6182     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
6183     *
6184     */
6185    public void setParentGroup(CmsRequestContext context, String groupName, String parentGroupName)
6186    throws CmsException, CmsRoleViolationException {
6187
6188        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6189
6190        try {
6191            checkRole(dbc, CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(groupName)));
6192            m_driverManager.setParentGroup(
6193                dbc,
6194                CmsOrganizationalUnit.removeLeadingSeparator(groupName),
6195                CmsOrganizationalUnit.removeLeadingSeparator(parentGroupName));
6196        } catch (Exception e) {
6197            dbc.report(null, Messages.get().container(Messages.ERR_SET_PARENT_GROUP_2, parentGroupName, groupName), e);
6198        } finally {
6199            dbc.clear();
6200        }
6201    }
6202
6203    /**
6204     * Sets the password for a user.<p>
6205     *
6206     * @param context the current request context
6207     * @param username the name of the user
6208     * @param newPassword the new password
6209     *
6210     * @throws CmsException if operation was not successful
6211     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
6212     */
6213    public void setPassword(CmsRequestContext context, String username, String newPassword)
6214    throws CmsException, CmsRoleViolationException {
6215
6216        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6217        try {
6218            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(username));
6219            checkRoleForUserModification(dbc, username, role);
6220            m_driverManager.setPassword(dbc, CmsOrganizationalUnit.removeLeadingSeparator(username), newPassword);
6221        } catch (Exception e) {
6222            dbc.report(null, Messages.get().container(Messages.ERR_SET_PASSWORD_1, username), e);
6223        } finally {
6224            dbc.clear();
6225        }
6226    }
6227
6228    /**
6229     * Marks a subscribed resource as deleted.<p>
6230     *
6231     * @param context the request context
6232     * @param poolName the name of the database pool to use
6233     * @param resource the subscribed resource to mark as deleted
6234     *
6235     * @throws CmsException if something goes wrong
6236     */
6237    public void setSubscribedResourceAsDeleted(CmsRequestContext context, String poolName, CmsResource resource)
6238    throws CmsException {
6239
6240        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6241        try {
6242            m_driverManager.setSubscribedResourceAsDeleted(dbc, poolName, resource);
6243        } catch (Exception e) {
6244
6245            dbc.report(
6246                null,
6247                Messages.get().container(
6248                    Messages.ERR_SET_SUBSCRIBED_RESOURCE_AS_DELETED_1,
6249                    context.getSitePath(resource)),
6250                e);
6251
6252        } finally {
6253            dbc.clear();
6254        }
6255    }
6256
6257    /**
6258     * Moves an user to the given organizational unit.<p>
6259     *
6260     * @param context the current request context
6261     * @param orgUnit the organizational unit to add the principal to
6262     * @param user the user that is to be move to the organizational unit
6263     *
6264     * @throws CmsException if something goes wrong
6265     *
6266     * @see org.opencms.security.CmsOrgUnitManager#setUsersOrganizationalUnit(CmsObject, String, String)
6267     */
6268    public void setUsersOrganizationalUnit(CmsRequestContext context, CmsOrganizationalUnit orgUnit, CmsUser user)
6269    throws CmsException {
6270
6271        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6272        try {
6273            checkRole(dbc, CmsRole.ADMINISTRATOR.forOrgUnit(orgUnit.getName()));
6274            checkOfflineProject(dbc);
6275            m_driverManager.setUsersOrganizationalUnit(dbc, orgUnit, user);
6276        } catch (Exception e) {
6277            dbc.report(
6278                null,
6279                Messages.get().container(Messages.ERR_SET_USERS_ORGUNIT_2, orgUnit.getName(), user.getName()),
6280                e);
6281        } finally {
6282            dbc.clear();
6283        }
6284    }
6285
6286    /**
6287     * Subscribes the user or group to the resource.<p>
6288     *
6289     * @param context the request context
6290     * @param poolName the name of the database pool to use
6291     * @param principal the principal that subscribes to the resource
6292     * @param resource the resource to subscribe to
6293     *
6294     * @throws CmsException if something goes wrong
6295     */
6296    public void subscribeResourceFor(
6297        CmsRequestContext context,
6298        String poolName,
6299        CmsPrincipal principal,
6300        CmsResource resource)
6301    throws CmsException {
6302
6303        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6304        try {
6305            m_driverManager.subscribeResourceFor(dbc, poolName, principal, resource);
6306        } catch (Exception e) {
6307            if (principal instanceof CmsUser) {
6308                dbc.report(
6309                    null,
6310                    Messages.get().container(
6311                        Messages.ERR_SUBSCRIBE_RESOURCE_FOR_USER_2,
6312                        context.getSitePath(resource),
6313                        principal.getName()),
6314                    e);
6315            } else {
6316                dbc.report(
6317                    null,
6318                    Messages.get().container(
6319                        Messages.ERR_SUBSCRIBE_RESOURCE_FOR_GROUP_2,
6320                        context.getSitePath(resource),
6321                        principal.getName()),
6322                    e);
6323            }
6324        } finally {
6325            dbc.clear();
6326        }
6327    }
6328
6329    /**
6330     * Undelete the resource by resetting it's state.<p>
6331     *
6332     * @param context the current request context
6333     * @param resource the name of the resource to apply this operation to
6334     *
6335     * @throws CmsException if something goes wrong
6336     *
6337     * @see CmsObject#undeleteResource(String, boolean)
6338     * @see org.opencms.file.types.I_CmsResourceType#undelete(CmsObject, CmsSecurityManager, CmsResource, boolean)
6339     */
6340    public void undelete(CmsRequestContext context, CmsResource resource) throws CmsException {
6341
6342        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6343        try {
6344            checkOfflineProject(dbc);
6345            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
6346            checkSystemLocks(dbc, resource);
6347
6348            m_driverManager.undelete(dbc, resource);
6349        } catch (Exception e) {
6350            dbc.report(
6351                null,
6352                Messages.get().container(Messages.ERR_UNDELETE_FOR_RESOURCE_1, context.getSitePath(resource)),
6353                e);
6354        } finally {
6355            dbc.clear();
6356        }
6357    }
6358
6359    /**
6360     * Undos all changes in the resource by restoring the version from the
6361     * online project to the current offline project.<p>
6362     *
6363     * @param context the current request context
6364     * @param resource the name of the resource to apply this operation to
6365     * @param mode the undo mode, one of the <code>{@link CmsResource}#UNDO_XXX</code> constants
6366     *
6367     * @throws CmsException if something goes wrong
6368     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
6369     *
6370     * @see CmsObject#undoChanges(String, CmsResource.CmsResourceUndoMode)
6371     * @see org.opencms.file.types.I_CmsResourceType#undoChanges(CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceUndoMode)
6372     */
6373    public void undoChanges(CmsRequestContext context, CmsResource resource, CmsResource.CmsResourceUndoMode mode)
6374    throws CmsException, CmsSecurityException {
6375
6376        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6377        try {
6378            checkOfflineProject(dbc);
6379            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
6380            checkSystemLocks(dbc, resource);
6381
6382            m_driverManager.undoChanges(dbc, resource, mode);
6383        } catch (Exception e) {
6384            dbc.report(
6385                null,
6386                Messages.get().container(Messages.ERR_UNDO_CHANGES_FOR_RESOURCE_1, context.getSitePath(resource)),
6387                e);
6388        } finally {
6389            dbc.clear();
6390        }
6391    }
6392
6393    /**
6394     * Unlocks all resources in this project.<p>
6395     *
6396     * @param context the current request context
6397     * @param projectId the id of the project to be published
6398     *
6399     * @throws CmsException if something goes wrong
6400     * @throws CmsRoleViolationException if the current user does not own the required permissions
6401     */
6402    public void unlockProject(CmsRequestContext context, CmsUUID projectId)
6403    throws CmsException, CmsRoleViolationException {
6404
6405        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6406        CmsProject project = m_driverManager.readProject(dbc, projectId);
6407
6408        try {
6409            checkManagerOfProjectRole(dbc, project);
6410            m_driverManager.unlockProject(project);
6411        } catch (Exception e) {
6412            dbc.report(
6413                null,
6414                Messages.get().container(Messages.ERR_UNLOCK_PROJECT_2, projectId, dbc.currentUser().getName()),
6415                e);
6416        } finally {
6417            dbc.clear();
6418        }
6419    }
6420
6421    /**
6422     * Unlocks a resource.<p>
6423     *
6424     * @param context the current request context
6425     * @param resource the resource to unlock
6426     *
6427     * @throws CmsException if something goes wrong
6428     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
6429     *
6430     * @see CmsObject#unlockResource(String)
6431     * @see org.opencms.file.types.I_CmsResourceType#unlockResource(CmsObject, CmsSecurityManager, CmsResource)
6432     */
6433    public void unlockResource(CmsRequestContext context, CmsResource resource)
6434    throws CmsException, CmsSecurityException {
6435
6436        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6437        try {
6438            checkOfflineProject(dbc);
6439            checkPermissions(
6440                dbc,
6441                resource,
6442                CmsPermissionSet.ACCESS_WRITE,
6443                LockCheck.shallowOnly,
6444                CmsResourceFilter.ALL);
6445            m_driverManager.unlockResource(dbc, resource, false, false);
6446        } catch (CmsException e) {
6447            dbc.report(
6448                null,
6449                Messages.get().container(
6450                    Messages.ERR_UNLOCK_RESOURCE_3,
6451                    context.getSitePath(resource),
6452                    dbc.currentUser().getName(),
6453                    e.getLocalizedMessage(dbc.getRequestContext().getLocale())),
6454                e);
6455        } finally {
6456            dbc.clear();
6457        }
6458    }
6459
6460    /**
6461     * Unsubscribes all deleted resources that were deleted before the specified time stamp.<p>
6462     *
6463     * @param context the request context
6464     * @param poolName the name of the database pool to use
6465     * @param deletedTo the time stamp to which the resources have been deleted
6466     *
6467     * @throws CmsException if something goes wrong
6468     */
6469    public void unsubscribeAllDeletedResources(CmsRequestContext context, String poolName, long deletedTo)
6470    throws CmsException {
6471
6472        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6473        try {
6474            m_driverManager.unsubscribeAllDeletedResources(dbc, poolName, deletedTo);
6475        } catch (Exception e) {
6476
6477            dbc.report(null, Messages.get().container(Messages.ERR_UNSUBSCRIBE_ALL_DELETED_RESOURCES_USER_0), e);
6478
6479        } finally {
6480            dbc.clear();
6481        }
6482    }
6483
6484    /**
6485     * Unsubscribes the user or group from all resources.<p>
6486     *
6487     * @param context the request context
6488     * @param poolName the name of the database pool to use
6489     * @param principal the principal that unsubscribes from all resources
6490     *
6491     * @throws CmsException if something goes wrong
6492     */
6493    public void unsubscribeAllResourcesFor(CmsRequestContext context, String poolName, CmsPrincipal principal)
6494    throws CmsException {
6495
6496        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6497        try {
6498            m_driverManager.unsubscribeAllResourcesFor(dbc, poolName, principal);
6499        } catch (Exception e) {
6500            if (principal instanceof CmsUser) {
6501                dbc.report(
6502                    null,
6503                    Messages.get().container(Messages.ERR_UNSUBSCRIBE_ALL_RESOURCES_USER_1, principal.getName()),
6504                    e);
6505            } else {
6506                dbc.report(
6507                    null,
6508                    Messages.get().container(Messages.ERR_UNSUBSCRIBE_ALL_RESOURCES_GROUP_1, principal.getName()),
6509                    e);
6510            }
6511        } finally {
6512            dbc.clear();
6513        }
6514    }
6515
6516    /**
6517     * Unsubscribes the principal from the resource.<p>
6518     *
6519     * @param context the request context
6520     * @param poolName the name of the database pool to use
6521     * @param principal the principal that unsubscribes from the resource
6522     * @param resource the resource to unsubscribe from
6523     *
6524     * @throws CmsException if something goes wrong
6525     */
6526    public void unsubscribeResourceFor(
6527        CmsRequestContext context,
6528        String poolName,
6529        CmsPrincipal principal,
6530        CmsResource resource)
6531    throws CmsException {
6532
6533        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6534        try {
6535            m_driverManager.unsubscribeResourceFor(dbc, poolName, principal, resource);
6536        } catch (Exception e) {
6537            dbc.report(
6538                null,
6539                Messages.get().container(
6540                    Messages.ERR_UNSUBSCRIBE_RESOURCE_FOR_GROUP_2,
6541                    context.getSitePath(resource),
6542                    principal.getName()),
6543                e);
6544        } finally {
6545            dbc.clear();
6546        }
6547    }
6548
6549    /**
6550     * Unsubscribes all groups and users from the resource.<p>
6551     *
6552     * @param context the request context
6553     * @param poolName the name of the database pool to use
6554     * @param resource the resource to unsubscribe all groups and users from
6555     *
6556     * @throws CmsException if something goes wrong
6557     */
6558    public void unsubscribeResourceForAll(CmsRequestContext context, String poolName, CmsResource resource)
6559    throws CmsException {
6560
6561        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6562        try {
6563            m_driverManager.unsubscribeResourceForAll(dbc, poolName, resource);
6564        } catch (Exception e) {
6565            dbc.report(
6566                null,
6567                Messages.get().container(Messages.ERR_UNSUBSCRIBE_RESOURCE_ALL_1, context.getSitePath(resource)),
6568                e);
6569        } finally {
6570            dbc.clear();
6571        }
6572    }
6573
6574    /**
6575     * Updates the last login date on the given user to the current time.<p>
6576     *
6577     * @param context the current request context
6578     * @param user the user to be updated
6579     *
6580     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER} for the current project
6581     * @throws CmsException if operation was not successful
6582     */
6583    public void updateLastLoginDate(CmsRequestContext context, CmsUser user)
6584    throws CmsException, CmsRoleViolationException {
6585
6586        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6587        try {
6588            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(user.getName()));
6589            checkRoleForUserModification(dbc, user.getName(), role);
6590            m_driverManager.updateLastLoginDate(dbc, user);
6591        } catch (Exception e) {
6592            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_USER_1, user.getName()), e);
6593        } finally {
6594            dbc.clear();
6595        }
6596    }
6597
6598    /**
6599     * Logs everything that has not been written to DB jet.<p>
6600     *
6601     * @throws CmsException if something goes wrong
6602     */
6603    public void updateLog() throws CmsException {
6604
6605        if (m_dbContextFactory == null) {
6606            // already shutdown
6607            return;
6608        }
6609        CmsDbContext dbc = m_dbContextFactory.getDbContext();
6610        try {
6611            m_driverManager.updateLog(dbc);
6612        } finally {
6613            dbc.clear();
6614        }
6615    }
6616
6617    /**
6618     * Updates/Creates the relations for the given resource.<p>
6619     *
6620     * @param context the current user context
6621     * @param resource the resource to update the relations for
6622     * @param relations the relations to update
6623     *
6624     * @throws CmsException if something goes wrong
6625     *
6626     * @see CmsDriverManager#updateRelationsForResource(CmsDbContext, CmsResource, List)
6627     */
6628    public void updateRelationsForResource(CmsRequestContext context, CmsResource resource, List<CmsLink> relations)
6629    throws CmsException {
6630
6631        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6632        try {
6633            m_driverManager.updateRelationsForResource(dbc, resource, relations);
6634        } catch (Exception e) {
6635            dbc.report(
6636                null,
6637                Messages.get().container(Messages.ERR_UPDATE_RELATIONS_1, dbc.removeSiteRoot(resource.getRootPath())),
6638                e);
6639        } finally {
6640            dbc.clear();
6641        }
6642    }
6643
6644    /**
6645     * Tests if a user is member of the given group.<p>
6646     *
6647     * @param context the current request context
6648     * @param username the name of the user to check
6649     * @param groupname the name of the group to check
6650     *
6651     * @return <code>true</code>, if the user is in the group; or <code>false</code> otherwise
6652     *
6653     * @throws CmsException if operation was not successful
6654     */
6655    public boolean userInGroup(CmsRequestContext context, String username, String groupname) throws CmsException {
6656
6657        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6658        boolean result = false;
6659        try {
6660            result = m_driverManager.userInGroup(
6661                dbc,
6662                CmsOrganizationalUnit.removeLeadingSeparator(username),
6663                CmsOrganizationalUnit.removeLeadingSeparator(groupname),
6664                false);
6665        } catch (Exception e) {
6666            dbc.report(null, Messages.get().container(Messages.ERR_USER_IN_GROUP_2, username, groupname), e);
6667        } finally {
6668            dbc.clear();
6669        }
6670        return result;
6671    }
6672
6673    /**
6674     * Checks if a new password follows the rules for
6675     * new passwords, which are defined by a Class implementing the
6676     * <code>{@link org.opencms.security.I_CmsPasswordHandler}</code>
6677     * interface and configured in the opencms.properties file.<p>
6678     *
6679     * If this method throws no exception the password is valid.<p>
6680     *
6681     * @param password the new password that has to be checked
6682     *
6683     * @throws CmsSecurityException if the password is not valid
6684     */
6685    public void validatePassword(String password) throws CmsSecurityException {
6686
6687        m_driverManager.validatePassword(password);
6688    }
6689
6690    /**
6691     * Validates the relations for the given resources.<p>
6692     *
6693     * @param context the current request context
6694     * @param publishList the resources to validate during publishing
6695     * @param report a report to write the messages to
6696     *
6697     * @return a map with lists of invalid links
6698     *          (<code>{@link org.opencms.relations.CmsRelation}}</code> objects)
6699     *          keyed by root paths
6700     *
6701     * @throws Exception if something goes wrong
6702     */
6703    public Map<String, List<CmsRelation>> validateRelations(
6704        CmsRequestContext context,
6705        CmsPublishList publishList,
6706        I_CmsReport report)
6707    throws Exception {
6708
6709        Map<String, List<CmsRelation>> result = null;
6710        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6711        try {
6712            result = m_driverManager.validateRelations(dbc, publishList, report);
6713        } catch (Exception e) {
6714            dbc.report(null, Messages.get().container(Messages.ERR_VALIDATE_RELATIONS_0), e);
6715        } finally {
6716            dbc.clear();
6717        }
6718        return result;
6719    }
6720
6721    /**
6722     * Writes an access control entries to a given resource.<p>
6723     *
6724     * @param context the current request context
6725     * @param resource the resource
6726     * @param ace the entry to write
6727     *
6728     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_CONTROL} required)
6729     * @throws CmsException if something goes wrong
6730     */
6731    public void writeAccessControlEntry(CmsRequestContext context, CmsResource resource, CmsAccessControlEntry ace)
6732    throws CmsException, CmsSecurityException {
6733
6734        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6735        try {
6736            checkOfflineProject(dbc);
6737            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_CONTROL, true, CmsResourceFilter.ALL);
6738            if (ace.getPrincipal().equals(CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID)) {
6739                // only vfs managers can set the overwrite all ACE
6740                checkRoleForResource(dbc, CmsRole.VFS_MANAGER, resource);
6741            }
6742            m_driverManager.writeAccessControlEntry(dbc, resource, ace);
6743        } catch (Exception e) {
6744            dbc.report(
6745                null,
6746                Messages.get().container(Messages.ERR_WRITE_ACL_ENTRY_1, context.getSitePath(resource)),
6747                e);
6748        } finally {
6749            dbc.clear();
6750        }
6751    }
6752
6753    /**
6754     * Writes a resource to the OpenCms VFS, including it's content.<p>
6755     *
6756     * Applies only to resources of type <code>{@link CmsFile}</code>
6757     * i.e. resources that have a binary content attached.<p>
6758     *
6759     * Certain resource types might apply content validation or transformation rules
6760     * before the resource is actually written to the VFS. The returned result
6761     * might therefore be a modified version from the provided original.<p>
6762     *
6763     * @param context the current request context
6764     * @param resource the resource to apply this operation to
6765     *
6766     * @return the written resource (may have been modified)
6767     *
6768     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_WRITE} required)
6769     * @throws CmsException if something goes wrong
6770     *
6771     * @see CmsObject#writeFile(CmsFile)
6772     * @see org.opencms.file.types.I_CmsResourceType#writeFile(CmsObject, CmsSecurityManager, CmsFile)
6773     */
6774    public CmsFile writeFile(CmsRequestContext context, CmsFile resource) throws CmsException, CmsSecurityException {
6775
6776        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6777        CmsFile result = null;
6778        try {
6779            checkOfflineProject(dbc);
6780            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
6781            result = m_driverManager.writeFile(dbc, resource);
6782        } catch (Exception e) {
6783            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_FILE_1, context.getSitePath(resource)), e);
6784        } finally {
6785            dbc.clear();
6786        }
6787        return result;
6788    }
6789
6790    /**
6791     * Writes an already existing group.<p>
6792     *
6793     * The group id has to be a valid OpenCms group id.<br>
6794     *
6795     * The group with the given id will be completely overridden
6796     * by the given data.<p>
6797     *
6798     * @param context the current request context
6799     * @param group the group that should be written
6800     *
6801     * @throws CmsRoleViolationException if the current user does not own the role {@link CmsRole#ACCOUNT_MANAGER} for the current project
6802     * @throws CmsException if operation was not successful
6803     */
6804    public void writeGroup(CmsRequestContext context, CmsGroup group) throws CmsException, CmsRoleViolationException {
6805
6806        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6807        try {
6808            checkRole(dbc, CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(group.getName())));
6809            m_driverManager.writeGroup(dbc, group);
6810        } catch (Exception e) {
6811            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_GROUP_1, group.getName()), e);
6812        } finally {
6813            dbc.clear();
6814        }
6815    }
6816
6817    /**
6818     * Creates a historical entry of the current project.<p>
6819     *
6820     * @param context the current request context
6821     * @param publishTag the correlative publish tag
6822     * @param publishDate the date of publishing
6823     *
6824     * @throws CmsException if operation was not successful
6825     */
6826    public void writeHistoryProject(CmsRequestContext context, int publishTag, long publishDate) throws CmsException {
6827
6828        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6829        try {
6830            m_driverManager.writeHistoryProject(dbc, publishTag, publishDate);
6831        } catch (Exception e) {
6832            dbc.report(
6833                null,
6834                Messages.get().container(
6835                    Messages.ERR_HISTORY_PROJECT_4,
6836                    new Object[] {
6837                        new Integer(publishTag),
6838                        dbc.currentProject().getName(),
6839                        dbc.currentProject().getUuid(),
6840                        new Long(publishDate)}),
6841                e);
6842        } finally {
6843            dbc.clear();
6844        }
6845    }
6846
6847    /**
6848     * Writes the locks that are currently stored in-memory to the database to allow restoring them in
6849     * later startups.<p>
6850     *
6851     * This overwrites the locks previously stored in the underlying database table.<p>
6852     *
6853     * @throws CmsException if something goes wrong
6854     */
6855    public void writeLocks() throws CmsException {
6856
6857        if (m_dbContextFactory == null) {
6858            // already shutdown
6859            return;
6860        }
6861        CmsDbContext dbc = m_dbContextFactory.getDbContext();
6862        try {
6863            m_driverManager.writeLocks(dbc);
6864        } finally {
6865            dbc.clear();
6866        }
6867    }
6868
6869    /**
6870     * Writes an already existing organizational unit.<p>
6871     *
6872     * The organizational unit id has to be a valid OpenCms organizational unit id.<p>
6873     *
6874     * The organizational unit with the given id will be completely overridden
6875     * by the given data.<p>
6876     *
6877     * @param context the current request context
6878     * @param organizationalUnit the organizational unit that should be written
6879     *
6880     * @throws CmsException if operation was not successful
6881     *
6882     * @see org.opencms.security.CmsOrgUnitManager#writeOrganizationalUnit(CmsObject, CmsOrganizationalUnit)
6883     */
6884    public void writeOrganizationalUnit(CmsRequestContext context, CmsOrganizationalUnit organizationalUnit)
6885    throws CmsException {
6886
6887        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6888        try {
6889            checkRole(dbc, CmsRole.ADMINISTRATOR.forOrgUnit(organizationalUnit.getName()));
6890            checkOfflineProject(dbc);
6891            m_driverManager.writeOrganizationalUnit(dbc, organizationalUnit);
6892        } catch (Exception e) {
6893            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_ORGUNIT_1, organizationalUnit.getName()), e);
6894        } finally {
6895            dbc.clear();
6896        }
6897    }
6898
6899    /**
6900     * Writes an already existing project.<p>
6901     *
6902     * The project id has to be a valid OpenCms project id.<br>
6903     *
6904     * The project with the given id will be completely overridden
6905     * by the given data.<p>
6906     *
6907     * @param project the project that should be written
6908     * @param context the current request context
6909     *
6910     * @throws CmsRoleViolationException if the current user does not own the required permissions
6911     * @throws CmsException if operation was not successful
6912     */
6913    public void writeProject(CmsRequestContext context, CmsProject project)
6914    throws CmsRoleViolationException, CmsException {
6915
6916        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6917        try {
6918            checkManagerOfProjectRole(dbc, project);
6919            m_driverManager.writeProject(dbc, project);
6920        } catch (Exception e) {
6921            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_PROJECT_1, project.getName()), e);
6922        } finally {
6923            dbc.clear();
6924        }
6925    }
6926
6927    /**
6928     * Writes a property for a specified resource.<p>
6929     *
6930     * @param context the current request context
6931     * @param resource the resource to write the property for
6932     * @param property the property to write
6933     *
6934     * @throws CmsException if something goes wrong
6935     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_WRITE} required)
6936     *
6937     * @see CmsObject#writePropertyObject(String, CmsProperty)
6938     * @see org.opencms.file.types.I_CmsResourceType#writePropertyObject(CmsObject, CmsSecurityManager, CmsResource, CmsProperty)
6939     */
6940    public void writePropertyObject(CmsRequestContext context, CmsResource resource, CmsProperty property)
6941    throws CmsException, CmsSecurityException {
6942
6943        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6944        try {
6945            checkOfflineProject(dbc);
6946            checkPermissions(
6947                dbc,
6948                resource,
6949                CmsPermissionSet.ACCESS_WRITE,
6950                LockCheck.shallowOnly,
6951                CmsResourceFilter.IGNORE_EXPIRATION);
6952            m_driverManager.writePropertyObject(dbc, resource, property);
6953        } catch (Exception e) {
6954            dbc.report(
6955                null,
6956                Messages.get().container(Messages.ERR_WRITE_PROP_2, property.getName(), context.getSitePath(resource)),
6957                e);
6958        } finally {
6959            dbc.clear();
6960        }
6961    }
6962
6963    /**
6964     * Writes a list of properties for a specified resource.<p>
6965     *
6966     * Code calling this method has to ensure that the no properties
6967     * <code>a, b</code> are contained in the specified list so that <code>a.equals(b)</code>,
6968     * otherwise an exception is thrown.<p>
6969     *
6970     * @param context the current request context
6971     * @param resource the resource to write the properties for
6972     * @param properties the list of properties to write
6973     *
6974     * @throws CmsException if something goes wrong
6975     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_WRITE} required)
6976     *
6977     * @see CmsObject#writePropertyObjects(String, List)
6978     * @see org.opencms.file.types.I_CmsResourceType#writePropertyObjects(CmsObject, CmsSecurityManager, CmsResource, List)
6979     */
6980    public void writePropertyObjects(CmsRequestContext context, CmsResource resource, List<CmsProperty> properties)
6981    throws CmsException, CmsSecurityException {
6982
6983        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6984        try {
6985            checkOfflineProject(dbc);
6986            checkPermissions(
6987                dbc,
6988                resource,
6989                CmsPermissionSet.ACCESS_WRITE,
6990                LockCheck.shallowOnly,
6991                CmsResourceFilter.IGNORE_EXPIRATION);
6992            // write the properties
6993            m_driverManager.writePropertyObjects(dbc, resource, properties, true);
6994        } catch (Exception e) {
6995            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_PROPS_1, context.getSitePath(resource)), e);
6996        } finally {
6997            dbc.clear();
6998        }
6999    }
7000
7001    /**
7002     * Writes a resource to the OpenCms VFS.<p>
7003     *
7004     * @param context the current request context
7005     * @param resource the resource to write
7006     *
7007     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_WRITE} required)
7008     * @throws CmsException if something goes wrong
7009     */
7010    public void writeResource(CmsRequestContext context, CmsResource resource)
7011    throws CmsException, CmsSecurityException {
7012
7013        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
7014        try {
7015            checkOfflineProject(dbc);
7016            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
7017            m_driverManager.writeResource(dbc, resource);
7018        } catch (Exception e) {
7019            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_RESOURCE_1, context.getSitePath(resource)), e);
7020        } finally {
7021            dbc.clear();
7022        }
7023    }
7024
7025    /**
7026     * Writes the 'projectlastmodified' field of a resource record.<p>
7027     *
7028     * @param context the current database context
7029     * @param resource the resource which should be modified
7030     * @param project the project whose project id should be written into the resource record
7031     *
7032     * @throws CmsException if something goes wrong
7033     */
7034    public void writeResourceProjectLastModified(CmsRequestContext context, CmsResource resource, CmsProject project)
7035    throws CmsException {
7036
7037        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
7038        try {
7039            checkOfflineProject(dbc);
7040            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
7041            m_driverManager.writeProjectLastModified(dbc, resource, project.getUuid());
7042        } catch (Exception e) {
7043            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_RESOURCE_1, context.getSitePath(resource)), e);
7044        } finally {
7045            dbc.clear();
7046        }
7047    }
7048
7049    /**
7050     * Inserts an entry in the published resource table.<p>
7051     *
7052     * This is done during static export.<p>
7053     *
7054     * @param context the current request context
7055     * @param resourceName The name of the resource to be added to the static export
7056     * @param linkType the type of resource exported (0= non-parameter, 1=parameter)
7057     * @param linkParameter the parameters added to the resource
7058     * @param timestamp a time stamp for writing the data into the db
7059     *
7060     * @throws CmsException if something goes wrong
7061     */
7062    public void writeStaticExportPublishedResource(
7063        CmsRequestContext context,
7064        String resourceName,
7065        int linkType,
7066        String linkParameter,
7067        long timestamp)
7068    throws CmsException {
7069
7070        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
7071        try {
7072            m_driverManager.writeStaticExportPublishedResource(dbc, resourceName, linkType, linkParameter, timestamp);
7073        } catch (Exception e) {
7074            dbc.report(
7075                null,
7076                Messages.get().container(
7077                    Messages.ERR_WRITE_STATEXP_PUBLISHED_RESOURCES_3,
7078                    resourceName,
7079                    linkParameter,
7080                    new Date(timestamp)),
7081                e);
7082        } finally {
7083            dbc.clear();
7084        }
7085    }
7086
7087    /**
7088     * Writes a new URL name mapping for a given resource.<p>
7089     *
7090     * The first name from the given sequence which is not already mapped to another resource will be used for
7091     * the URL name mapping.<p>
7092     *
7093     * @param context the request context
7094     * @param nameSeq the sequence of URL name candidates
7095     * @param structureId the structure id which should be mapped to the name
7096     * @param locale the locale for the mapping
7097     * @param replaceOnPublish mappings for which this is set will replace all other mappings for the same resource on publishing
7098     *
7099     * @return the name which was actually mapped to the structure id
7100     *
7101     * @throws CmsException if something goes wrong
7102     */
7103    public String writeUrlNameMapping(
7104        CmsRequestContext context,
7105        Iterator<String> nameSeq,
7106        CmsUUID structureId,
7107        String locale,
7108        boolean replaceOnPublish)
7109    throws CmsException {
7110
7111        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
7112        try {
7113            return m_driverManager.writeUrlNameMapping(dbc, nameSeq, structureId, locale, replaceOnPublish);
7114        } catch (Exception e) {
7115            CmsMessageContainer message = Messages.get().container(
7116                Messages.ERR_ADD_URLNAME_MAPPING_2,
7117                nameSeq.toString(),
7118                structureId.toString());
7119            dbc.report(null, message, e);
7120            return null;
7121        } finally {
7122            dbc.clear();
7123        }
7124    }
7125
7126    /**
7127     * Updates the user information. <p>
7128     *
7129     * The user id has to be a valid OpenCms user id.<br>
7130     *
7131     * The user with the given id will be completely overridden
7132     * by the given data.<p>
7133     *
7134     * @param context the current request context
7135     * @param user the user to be updated
7136     *
7137     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER} for the current project
7138     * @throws CmsException if operation was not successful
7139     */
7140    public void writeUser(CmsRequestContext context, CmsUser user) throws CmsException, CmsRoleViolationException {
7141
7142        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
7143        try {
7144            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(user.getName()));
7145            checkRoleForUserModification(dbc, user.getName(), role);
7146            m_driverManager.writeUser(dbc, user);
7147        } catch (Exception e) {
7148            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_USER_1, user.getName()), e);
7149        } finally {
7150            dbc.clear();
7151        }
7152    }
7153
7154    /**
7155     * Performs a blocking permission check on a resource.<p>
7156     *
7157     * If the required permissions are not satisfied by the permissions the user has on the resource,
7158     * an exception is thrown.<p>
7159     *
7160     * @param dbc the current database context
7161     * @param resource the resource on which permissions are required
7162     * @param requiredPermissions the set of permissions required to access the resource
7163     * @param checkLock if true, the lock status of the resource is also checked
7164     * @param filter the filter for the resource
7165     *
7166     * @throws CmsException in case of any i/o error
7167     * @throws CmsSecurityException if the required permissions are not satisfied
7168     *
7169     * @see #hasPermissions(CmsRequestContext, CmsResource, CmsPermissionSet, boolean, CmsResourceFilter)
7170     */
7171    protected void checkPermissions(
7172        CmsDbContext dbc,
7173        CmsResource resource,
7174        CmsPermissionSet requiredPermissions,
7175        boolean checkLock,
7176        CmsResourceFilter filter)
7177    throws CmsException, CmsSecurityException {
7178
7179        // get the permissions
7180        I_CmsPermissionHandler.CmsPermissionCheckResult permissions = hasPermissions(
7181            dbc,
7182            resource,
7183            requiredPermissions,
7184            checkLock ? LockCheck.yes : LockCheck.no,
7185            filter);
7186        if (!permissions.isAllowed()) {
7187            checkPermissions(dbc.getRequestContext(), resource, requiredPermissions, permissions);
7188        }
7189    }
7190
7191    /**
7192     * Performs a blocking permission check on a resource.<p>
7193     *
7194     * If the required permissions are not satisfied by the permissions the user has on the resource,
7195     * an exception is thrown.<p>
7196     *
7197     * @param dbc the current database context
7198     * @param resource the resource on which permissions are required
7199     * @param requiredPermissions the set of permissions required to access the resource
7200     * @param checkLock if true, the lock status of the resource is also checked
7201     * @param filter the filter for the resource
7202     *
7203     * @throws CmsException in case of any i/o error
7204     * @throws CmsSecurityException if the required permissions are not satisfied
7205     *
7206     * @see #hasPermissions(CmsRequestContext, CmsResource, CmsPermissionSet, boolean, CmsResourceFilter)
7207     */
7208    protected void checkPermissions(
7209        CmsDbContext dbc,
7210        CmsResource resource,
7211        CmsPermissionSet requiredPermissions,
7212        LockCheck checkLock,
7213        CmsResourceFilter filter)
7214    throws CmsException, CmsSecurityException {
7215
7216        // get the permissions
7217        I_CmsPermissionHandler.CmsPermissionCheckResult permissions = hasPermissions(
7218            dbc,
7219            resource,
7220            requiredPermissions,
7221            checkLock,
7222            filter);
7223        if (!permissions.isAllowed()) {
7224            checkPermissions(dbc.getRequestContext(), resource, requiredPermissions, permissions);
7225        }
7226    }
7227
7228    /**
7229     * Applies the permission check result of a previous call
7230     * to {@link #hasPermissions(CmsRequestContext, CmsResource, CmsPermissionSet, boolean, CmsResourceFilter)}.<p>
7231     *
7232     * @param context the current request context
7233     * @param resource the resource on which permissions are required
7234     * @param requiredPermissions the set of permissions required to access the resource
7235     * @param permissions the permissions to check
7236     *
7237     * @throws CmsSecurityException if the required permissions are not satisfied
7238     * @throws CmsLockException if the lock status is not as required
7239     * @throws CmsVfsResourceNotFoundException if the required resource has been filtered
7240     */
7241    protected void checkPermissions(
7242        CmsRequestContext context,
7243        CmsResource resource,
7244        CmsPermissionSet requiredPermissions,
7245        I_CmsPermissionHandler.CmsPermissionCheckResult permissions)
7246    throws CmsSecurityException, CmsLockException, CmsVfsResourceNotFoundException {
7247
7248        if (permissions == I_CmsPermissionHandler.PERM_FILTERED) {
7249            throw new CmsVfsResourceNotFoundException(
7250                Messages.get().container(Messages.ERR_PERM_FILTERED_1, context.getSitePath(resource)));
7251        }
7252        if (permissions == I_CmsPermissionHandler.PERM_DENIED) {
7253            throw new CmsPermissionViolationException(
7254                Messages.get().container(
7255                    Messages.ERR_PERM_DENIED_2,
7256                    context.getSitePath(resource),
7257                    requiredPermissions.getPermissionString()));
7258        }
7259        if (permissions == I_CmsPermissionHandler.PERM_NOTLOCKED) {
7260            throw new CmsLockException(
7261                Messages.get().container(
7262                    Messages.ERR_PERM_NOTLOCKED_2,
7263                    context.getSitePath(resource),
7264                    context.getCurrentUser().getName()));
7265        }
7266    }
7267
7268    /**
7269     * Checks that the current user has enough permissions to modify the given user.<p>
7270     *
7271     * @param dbc the database context
7272     * @param username the name of the user to modify
7273     * @param role the needed role
7274     *
7275     * @throws CmsDataAccessException if something goes wrong accessing the database
7276     * @throws CmsRoleViolationException if the user has not the needed permissions
7277     */
7278    protected void checkRoleForUserModification(CmsDbContext dbc, String username, CmsRole role)
7279    throws CmsDataAccessException, CmsRoleViolationException {
7280
7281        CmsUser userToModify = m_driverManager.readUser(dbc, CmsOrganizationalUnit.removeLeadingSeparator(username));
7282        if (dbc.currentUser().equals(userToModify)) {
7283            // a user is allowed to write his own data
7284            return;
7285        }
7286        if (hasRole(dbc, dbc.currentUser(), CmsRole.ROOT_ADMIN)) {
7287            // a user with the ROOT_ADMIN role may change any other user
7288            return;
7289        }
7290        if (hasRole(dbc, userToModify, CmsRole.ADMINISTRATOR)) {
7291            // check the user that is going to do the modification is administrator
7292            checkRole(dbc, CmsRole.ADMINISTRATOR);
7293        } else {
7294            // check the user that is going to do the modification has the given role
7295            checkRole(dbc, role);
7296        }
7297
7298    }
7299
7300    /**
7301     * Checks if the given resource contains a resource that has a system lock.<p>
7302     *
7303     * @param dbc the current database context
7304     * @param resource the resource to check
7305     *
7306     * @throws CmsException in case there is a system lock contained in the given resource
7307     */
7308    protected void checkSystemLocks(CmsDbContext dbc, CmsResource resource) throws CmsException {
7309
7310        if (m_lockManager.hasSystemLocks(dbc, resource)) {
7311            throw new CmsLockException(
7312                Messages.get().container(
7313                    Messages.ERR_RESOURCE_SYSTEM_LOCKED_1,
7314                    dbc.removeSiteRoot(resource.getRootPath())));
7315        }
7316    }
7317
7318    /**
7319     * Internal recursive method for deleting a resource.<p>
7320     *
7321     * @param dbc the db context
7322     * @param resource the name of the resource to delete (full path)
7323     * @param siblingMode indicates how to handle siblings of the deleted resource
7324     *
7325     * @throws CmsException if something goes wrong
7326     */
7327    protected void deleteResource(CmsDbContext dbc, CmsResource resource, CmsResource.CmsResourceDeleteMode siblingMode)
7328    throws CmsException {
7329
7330        if (resource.isFolder()) {
7331            // collect all resources in the folder (but exclude deleted ones)
7332            List<CmsResource> resources = m_driverManager.readChildResources(
7333                dbc,
7334                resource,
7335                CmsResourceFilter.IGNORE_EXPIRATION,
7336                true,
7337                true,
7338                false);
7339
7340            Set<CmsUUID> deletedResources = new HashSet<CmsUUID>();
7341            // now walk through all sub-resources in the folder
7342            for (int i = 0; i < resources.size(); i++) {
7343                CmsResource childResource = resources.get(i);
7344                if ((siblingMode == CmsResource.DELETE_REMOVE_SIBLINGS)
7345                    && deletedResources.contains(childResource.getResourceId())) {
7346                    // sibling mode is "delete all siblings" and another sibling of the current child resource has already
7347                    // been deleted- do nothing and continue with the next child resource.
7348                    continue;
7349                }
7350                if (childResource.isFolder()) {
7351                    // recurse into this method for subfolders
7352                    deleteResource(dbc, childResource, siblingMode);
7353                } else {
7354                    // handle child resources
7355                    m_driverManager.deleteResource(dbc, childResource, siblingMode);
7356                }
7357                deletedResources.add(childResource.getResourceId());
7358            }
7359            deletedResources.clear();
7360        }
7361        // handle the resource itself
7362        m_driverManager.deleteResource(dbc, resource, siblingMode);
7363    }
7364
7365    /**
7366     * Deletes a user, where all permissions and resources attributes of the user
7367     * were transfered to a replacement user, if given.<p>
7368     *
7369     * @param context the current request context
7370     * @param user the user to be deleted
7371     * @param replacement the user to be transfered, can be <code>null</code>
7372     *
7373     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
7374     * @throws CmsSecurityException in case the user is a default user
7375     * @throws CmsException if something goes wrong
7376     */
7377    protected void deleteUser(CmsRequestContext context, CmsUser user, CmsUser replacement)
7378    throws CmsException, CmsSecurityException, CmsRoleViolationException {
7379
7380        if (OpenCms.getDefaultUsers().isDefaultUser(user.getName())) {
7381            throw new CmsSecurityException(
7382                org.opencms.security.Messages.get().container(
7383                    org.opencms.security.Messages.ERR_CANT_DELETE_DEFAULT_USER_1,
7384                    user.getName()));
7385        }
7386        if (context.getCurrentUser().equals(user)) {
7387            throw new CmsSecurityException(Messages.get().container(Messages.ERR_USER_CANT_DELETE_ITSELF_USER_0));
7388        }
7389
7390        CmsDbContext dbc = null;
7391        try {
7392            dbc = getDbContextForDeletePrincipal(context);
7393            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(user.getName()));
7394            checkRoleForUserModification(dbc, user.getName(), role);
7395            m_driverManager.deleteUser(
7396                dbc,
7397                dbc.getRequestContext().getCurrentProject(),
7398                user.getName(),
7399                null == replacement ? null : replacement.getName());
7400        } catch (Exception e) {
7401            CmsDbContext dbcForException = m_dbContextFactory.getDbContext(context);
7402            dbcForException.report(null, Messages.get().container(Messages.ERR_DELETE_USER_1, user.getName()), e);
7403            dbcForException.clear();
7404        } finally {
7405            if (null != dbc) {
7406                dbc.clear();
7407            }
7408        }
7409    }
7410
7411    /**
7412     * Returns all resources of organizational units for which the current user has
7413     * the given role role.<p>
7414     *
7415     * @param dbc the current database context
7416     * @param role the role to check
7417     *
7418     * @return a list of {@link org.opencms.file.CmsResource} objects
7419     *
7420     * @throws CmsException if something goes wrong
7421     */
7422    protected List<CmsResource> getManageableResources(CmsDbContext dbc, CmsRole role) throws CmsException {
7423
7424        CmsOrganizationalUnit ou = m_driverManager.readOrganizationalUnit(dbc, role.getOuFqn());
7425        if (hasRole(dbc, dbc.currentUser(), role)) {
7426            return m_driverManager.getResourcesForOrganizationalUnit(dbc, ou);
7427        }
7428        List<CmsResource> resources = new ArrayList<CmsResource>();
7429        Iterator<CmsOrganizationalUnit> it = m_driverManager.getOrganizationalUnits(dbc, ou, false).iterator();
7430        while (it.hasNext()) {
7431            CmsOrganizationalUnit orgUnit = it.next();
7432            resources.addAll(getManageableResources(dbc, role.forOrgUnit(orgUnit.getName())));
7433        }
7434        return resources;
7435    }
7436
7437    /**
7438     * Returns the organizational unit for the parent of the given fully qualified name.<p>
7439     *
7440     * @param fqn the fully qualified name to get the parent organizational unit for
7441     *
7442     * @return the parent organizational unit for the fully qualified name
7443     */
7444    protected String getParentOrganizationalUnit(String fqn) {
7445
7446        String ouFqn = CmsOrganizationalUnit.getParentFqn(CmsOrganizationalUnit.removeLeadingSeparator(fqn));
7447        if (ouFqn == null) {
7448            ouFqn = "";
7449        }
7450        return ouFqn;
7451    }
7452
7453    /**
7454     * Performs a non-blocking permission check on a resource.<p>
7455     *
7456     * This test will not throw an exception in case the required permissions are not
7457     * available for the requested operation. Instead, it will return one of the
7458     * following values:<ul>
7459     * <li><code>{@link I_CmsPermissionHandler#PERM_ALLOWED}</code></li>
7460     * <li><code>{@link I_CmsPermissionHandler#PERM_FILTERED}</code></li>
7461     * <li><code>{@link I_CmsPermissionHandler#PERM_DENIED}</code></li></ul><p>
7462     *
7463     * @param dbc the current database context
7464     * @param resource the resource on which permissions are required
7465     * @param requiredPermissions the set of permissions required for the operation
7466     * @param checkLock if true, a lock for the current user is required for
7467     *      all write operations, if false it's ok to write as long as the resource
7468     *      is not locked by another user
7469     * @param filter the resource filter to use
7470     *
7471     * @return <code>{@link I_CmsPermissionHandler#PERM_ALLOWED}</code> if the user has sufficient permissions on the resource
7472     *      for the requested operation
7473     *
7474     * @throws CmsException in case of i/o errors (NOT because of insufficient permissions)
7475     */
7476    protected I_CmsPermissionHandler.CmsPermissionCheckResult hasPermissions(
7477        CmsDbContext dbc,
7478        CmsResource resource,
7479        CmsPermissionSet requiredPermissions,
7480        LockCheck checkLock,
7481        CmsResourceFilter filter)
7482    throws CmsException {
7483
7484        return m_permissionHandler.hasPermissions(dbc, resource, requiredPermissions, checkLock, filter);
7485    }
7486
7487    /**
7488     * Returns <code>true</code> if at least one of the given group names is equal to a group name
7489     * of the given role in the given organizational unit.<p>
7490     *
7491     * This checks the given list against the group of the given role as well as against the role group
7492     * of all parent roles.<p>
7493     *
7494     * If the organizational unit is <code>null</code>, this method will check if the
7495     * given user has the given role for at least one organizational unit.<p>
7496     *
7497     * @param role the role to check
7498     * @param roles the groups to match the role groups against
7499     *
7500     * @return <code>true</code> if at last one of the given group names is equal to a group name
7501     *      of this role
7502     */
7503    protected boolean hasRole(CmsRole role, List<CmsGroup> roles) {
7504
7505        // iterates the role groups the user is in
7506        for (CmsGroup group : roles) {
7507            String groupName = group.getName();
7508            // iterate the role hierarchy
7509            for (String distictGroupName : role.getDistinctGroupNames()) {
7510                if (distictGroupName.startsWith(CmsOrganizationalUnit.SEPARATOR)) {
7511                    // this is a ou independent role
7512                    // we need an exact match, and we ignore the ou parameter
7513                    if (groupName.equals(distictGroupName.substring(1))) {
7514                        return true;
7515                    }
7516                } else {
7517                    // first check if the user has the role at all
7518                    if (groupName.endsWith(CmsOrganizationalUnit.SEPARATOR + distictGroupName)
7519                        || groupName.equals(distictGroupName)) {
7520                        // this is a ou dependent role
7521                        if (role.getOuFqn() == null) {
7522                            // ou parameter is null, so the user needs to have the role in at least one ou does not matter which
7523                            return true;
7524                        } else {
7525                            // the user needs to have the role in the given ou or in a parent ou
7526                            // now check that the ou matches
7527                            String groupFqn = CmsOrganizationalUnit.getParentFqn(groupName);
7528                            if (role.getOuFqn().startsWith(groupFqn)) {
7529                                return true;
7530                            }
7531                        }
7532                    }
7533                }
7534            }
7535        }
7536        return false;
7537    }
7538
7539    /**
7540     * Internal recursive method to move a resource.<p>
7541     *
7542     * @param dbc the db context
7543     * @param source the source resource
7544     * @param destination the destination path
7545     * @param allMovedResources a set used to collect all moved resources
7546     *
7547     * @throws CmsException if something goes wrong
7548     */
7549    protected void moveResource(
7550        CmsDbContext dbc,
7551        CmsResource source,
7552        String destination,
7553        Set<CmsResource> allMovedResources)
7554    throws CmsException {
7555
7556        List<CmsResource> resources = null;
7557
7558        if (source.isFolder()) {
7559            if (!CmsResource.isFolder(destination)) {
7560                // ensure folder name end's with a /
7561                destination = destination.concat("/");
7562            }
7563            // collect all resources in the folder without checking permissions
7564            resources = m_driverManager.readChildResources(dbc, source, CmsResourceFilter.ALL, true, true, false);
7565        }
7566
7567        // target permissions will be checked later
7568        m_driverManager.moveResource(dbc, source, destination, false);
7569
7570        // make sure lock is set
7571        CmsResource destinationResource = m_driverManager.readResource(dbc, destination, CmsResourceFilter.ALL);
7572        try {
7573            // the destination must always get a new lock
7574            m_driverManager.lockResource(dbc, destinationResource, CmsLockType.EXCLUSIVE);
7575        } catch (Exception e) {
7576            // could happen with with shared locks on single files
7577            if (LOG.isWarnEnabled()) {
7578                LOG.warn(e.getLocalizedMessage(), e);
7579            }
7580        }
7581
7582        if (resources != null) {
7583            // Ensure consistent order that is not database-dependent, since readChildResources doesn't specify an ordering.
7584            // this is necessary to make test cases more useful.
7585            Collections.sort(resources, (r1, r2) -> r1.getRootPath().compareTo(r2.getRootPath()));
7586
7587            // now walk through all sub-resources in the folder
7588            for (int i = 0; i < resources.size(); i++) {
7589                CmsResource childResource = resources.get(i);
7590                String childDestination = destination.concat(childResource.getName());
7591                // recurse with child resource
7592                moveResource(dbc, childResource, childDestination, allMovedResources);
7593            }
7594        }
7595
7596        List<CmsResource> movedResources = m_driverManager.readChildResources(
7597            dbc,
7598            destinationResource,
7599            CmsResourceFilter.ALL,
7600            true,
7601            true,
7602            false);
7603        allMovedResources.add(destinationResource);
7604        allMovedResources.addAll(movedResources);
7605
7606    }
7607
7608    /**
7609     * Reads a folder from the VFS, using the specified resource filter.<p>
7610     *
7611     * @param dbc the current database context
7612     * @param resourcename the name of the folder to read (full path)
7613     * @param filter the resource filter to use while reading
7614     *
7615     * @return the folder that was read
7616     *
7617     * @throws CmsException if something goes wrong
7618     */
7619    protected CmsFolder readFolder(CmsDbContext dbc, String resourcename, CmsResourceFilter filter)
7620    throws CmsException {
7621
7622        CmsResource resource = readResource(dbc, resourcename, filter);
7623        return m_driverManager.convertResourceToFolder(resource);
7624    }
7625
7626    /**
7627     * Reads a resource from the OpenCms VFS, using the specified resource filter.<p>
7628     *
7629     * @param dbc the current database context
7630     * @param structureID the ID of the structure to read
7631     * @param filter the resource filter to use while reading
7632     *
7633     * @return the resource that was read
7634     *
7635     * @throws CmsException if something goes wrong
7636     *
7637     * @see CmsObject#readResource(CmsUUID, CmsResourceFilter)
7638     * @see CmsObject#readResource(CmsUUID)
7639     * @see CmsObject#readFile(CmsResource)
7640     */
7641    protected CmsResource readResource(CmsDbContext dbc, CmsUUID structureID, CmsResourceFilter filter)
7642    throws CmsException {
7643
7644        // read the resource from the VFS
7645        CmsResource resource = m_driverManager.readResource(dbc, structureID, filter);
7646
7647        // check if the user has read access to the resource
7648        checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, true, filter);
7649
7650        // access was granted - return the resource
7651        return resource;
7652    }
7653
7654    /**
7655     * Reads a resource from the OpenCms VFS, using the specified resource filter.<p>
7656     *
7657     * @param dbc the current database context
7658     * @param resourcePath the name of the resource to read (full path)
7659     * @param filter the resource filter to use while reading
7660     *
7661     * @return the resource that was read
7662     *
7663     * @throws CmsException if something goes wrong
7664     *
7665     * @see CmsObject#readResource(String, CmsResourceFilter)
7666     * @see CmsObject#readResource(String)
7667     * @see CmsObject#readFile(CmsResource)
7668     */
7669    protected CmsResource readResource(CmsDbContext dbc, String resourcePath, CmsResourceFilter filter)
7670    throws CmsException {
7671
7672        // read the resource from the VFS
7673        CmsResource resource = m_driverManager.readResource(dbc, resourcePath, filter);
7674
7675        // check if the user has read access to the resource
7676        checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, true, filter);
7677
7678        // access was granted - return the resource
7679        return resource;
7680    }
7681
7682    /**
7683     * Determines a project where the deletion of a principal can be executed and sets it in the returned db context.<p>
7684     *
7685     * @param context the current request context
7686     *
7687     * @return the db context to use when deleting the principal.
7688     *
7689     * @throws CmsDataAccessException if determining a project that is suitable to delete the prinicipal fails.
7690     */
7691    private CmsDbContext getDbContextForDeletePrincipal(CmsRequestContext context) throws CmsDataAccessException {
7692
7693        CmsProject currentProject = context.getCurrentProject();
7694        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
7695        CmsUUID projectId = dbc.getProjectId();
7696        // principal modifications are allowed if the current project is not the online project
7697        if (currentProject.isOnlineProject()) {
7698            // this is needed because
7699            // I_CmsUserDriver#removeAccessControlEntriesForPrincipal(CmsDbContext, CmsProject, CmsProject, CmsUUID)
7700            // expects an offline project, if not, data will become inconsistent
7701
7702            // if the current project is the online project, check if there is a valid offline project at all
7703            List<CmsProject> projects = m_driverManager.getProjectDriver(dbc).readProjects(dbc, "");
7704            for (CmsProject project : projects) {
7705                if (!project.isOnlineProject()) {
7706                    try {
7707                        dbc.setProjectId(project.getUuid());
7708                        if (null != m_driverManager.readResource(dbc, "/", CmsResourceFilter.ALL)) {
7709                            // shallow clone the context with project adjusted
7710                            context = new CmsRequestContext(
7711                                context.getCurrentUser(),
7712                                project,
7713                                context.getUri(),
7714                                context.getRequestMatcher(),
7715                                context.getSiteRoot(),
7716                                context.isSecureRequest(),
7717                                context.getLocale(),
7718                                context.getEncoding(),
7719                                context.getRemoteAddress(),
7720                                context.getRequestTime(),
7721                                context.getDirectoryTranslator(),
7722                                context.getFileTranslator(),
7723                                context.getOuFqn(),
7724                                context.isForceAbsoluteLinks());
7725                            dbc = m_dbContextFactory.getDbContext(context);
7726                            projectId = dbc.getProjectId();
7727                            break;
7728                        }
7729                    } catch (Exception e) {
7730                        // ignore
7731                    }
7732                }
7733            }
7734        }
7735        dbc.setProjectId(projectId);
7736        return dbc;
7737    }
7738
7739}