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