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