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 = role.getGroupName() + "," + role.getOuFqn();
3073        Boolean result = OpenCms.getMemoryMonitor().getGroupListCache().getHasRole(user.getId(), 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().getGroupListCache().setHasRole(user, key, result);
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
3170        // ***
3171        // NOTE: We do intentionally *not* use the new group list cache here, as we have no good way to limit it at the moment, and this might generate a large amount of entries
3172        // ***
3173        String key = user.getId().toString() + role.getGroupName() + resource.getRootPath();
3174        Boolean result = OpenCms.getMemoryMonitor().getCachedRole(key);
3175        if (result != null) {
3176            return result.booleanValue();
3177        }
3178
3179        // read all roles of the current user
3180        List<CmsGroup> roles;
3181        try {
3182            roles = new ArrayList<CmsGroup>(
3183                m_driverManager.getGroupsOfUser(
3184                    dbc,
3185                    user.getName(),
3186                    "",
3187                    true,
3188                    true,
3189                    true,
3190                    dbc.getRequestContext().getRemoteAddress()));
3191        } catch (CmsException e) {
3192            if (LOG.isErrorEnabled()) {
3193                LOG.error(e.getLocalizedMessage(), e);
3194            }
3195            // any exception: return false
3196            return false;
3197        }
3198
3199        // first check the user has the role at all
3200        if (!hasRole(role.forOrgUnit(null), roles)) {
3201            result = Boolean.FALSE;
3202        }
3203
3204        // then check if one applies to the given resource
3205        Iterator<CmsGroup> it = roles.iterator();
3206        while ((result == null) && it.hasNext()) {
3207            CmsGroup group = it.next();
3208            CmsRole givenRole = CmsRole.valueOf(group);
3209            if (hasRole(role.forOrgUnit(null), Collections.singletonList(group))) {
3210                // we have the same role, now check the resource if needed
3211                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(givenRole.getOuFqn())) {
3212                    try {
3213                        CmsOrganizationalUnit orgUnit = m_driverManager.readOrganizationalUnit(
3214                            dbc,
3215                            givenRole.getOuFqn());
3216                        Iterator<CmsResource> itResources = m_driverManager.getResourcesForOrganizationalUnit(
3217                            dbc,
3218                            orgUnit).iterator();
3219                        while (itResources.hasNext()) {
3220                            CmsResource givenResource = itResources.next();
3221                            if (resource.getRootPath().startsWith(givenResource.getRootPath())) {
3222                                result = Boolean.TRUE;
3223                                break;
3224                            }
3225                        }
3226                    } catch (CmsException e) {
3227                        if (LOG.isErrorEnabled()) {
3228                            LOG.error(e.getLocalizedMessage(), e);
3229                        }
3230                        // ignore
3231                    }
3232                } else {
3233                    result = Boolean.TRUE;
3234                }
3235            }
3236        }
3237
3238        if (result == null) {
3239            result = Boolean.FALSE;
3240        }
3241        OpenCms.getMemoryMonitor().cacheRole(key, result.booleanValue());
3242        return result.booleanValue();
3243    }
3244
3245    /**
3246     * Checks if the given user has the given role for the given resource.<p>
3247     *
3248     * @param context the current request context
3249     * @param user the user to check
3250     * @param role the role to check
3251     * @param resource the resource to check the role for
3252     *
3253     * @return <code>true</code> if the given user has the given role for the given resource
3254     */
3255    public boolean hasRoleForResource(CmsRequestContext context, CmsUser user, CmsRole role, CmsResource resource) {
3256
3257        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3258        boolean result;
3259        try {
3260            result = hasRoleForResource(dbc, user, role, resource);
3261        } finally {
3262            dbc.clear();
3263        }
3264        return result;
3265    }
3266
3267    /**
3268     * Writes a list of access control entries as new access control entries of a given resource.<p>
3269     *
3270     * Already existing access control entries of this resource are removed before.<p>
3271     *
3272     * Access is granted, if:<p>
3273     * <ul>
3274     * <li>the current user has control permission on the resource</li>
3275     * </ul><p>
3276     *
3277     * @param context the current request context
3278     * @param resource the resource
3279     * @param acEntries a list of <code>{@link CmsAccessControlEntry}</code> objects
3280     *
3281     * @throws CmsException if something goes wrong
3282     * @throws CmsSecurityException if the required permissions are not satisfied
3283     */
3284    public void importAccessControlEntries(
3285        CmsRequestContext context,
3286        CmsResource resource,
3287        List<CmsAccessControlEntry> acEntries)
3288    throws CmsException, CmsSecurityException {
3289
3290        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3291        try {
3292            checkOfflineProject(dbc);
3293            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_CONTROL, true, CmsResourceFilter.ALL);
3294            m_driverManager.importAccessControlEntries(dbc, resource, acEntries);
3295        } catch (Exception e) {
3296            dbc.report(
3297                null,
3298                Messages.get().container(Messages.ERR_IMPORT_ACL_ENTRIES_1, context.getSitePath(resource)),
3299                e);
3300        } finally {
3301            dbc.clear();
3302        }
3303    }
3304
3305    /**
3306     * Creates a new resource with the provided content and properties.<p>
3307     *
3308     * The <code>content</code> parameter may be null if the resource id already exists.
3309     * If so, the created resource will be made a sibling of the existing resource,
3310     * the existing content will remain unchanged.
3311     * This is used during file import for import of siblings as the
3312     * <code>manifest.xml</code> only contains one binary copy per file.
3313     * If the resource id exists but the <code>content</code> is not null,
3314     * the created resource will be made a sibling of the existing resource,
3315     * and both will share the new content.<p>
3316     *
3317     * @param context the current request context
3318     * @param resourcePath the name of the resource to create (full path)
3319     * @param resource the new resource to create
3320     * @param content the content for the new resource
3321     * @param properties the properties for the new resource
3322     * @param importCase if <code>true</code>, signals that this operation is done while importing resource,
3323     *                   causing different lock behavior and potential "lost and found" usage
3324     *
3325     * @return the created resource
3326     *
3327     * @throws CmsException if something goes wrong
3328     */
3329    public CmsResource importResource(
3330        CmsRequestContext context,
3331        String resourcePath,
3332        CmsResource resource,
3333        byte[] content,
3334        List<CmsProperty> properties,
3335        boolean importCase)
3336    throws CmsException {
3337
3338        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3339        CmsResource newResource = null;
3340        try {
3341            checkOfflineProject(dbc);
3342            newResource = m_driverManager.createResource(dbc, resourcePath, resource, content, properties, importCase);
3343        } catch (Exception e) {
3344            dbc.report(
3345                null,
3346                Messages.get().container(Messages.ERR_IMPORT_RESOURCE_2, context.getSitePath(resource), resourcePath),
3347                e);
3348        } finally {
3349            dbc.clear();
3350        }
3351        return newResource;
3352    }
3353
3354    /**
3355     * Imports a rewrite alias.<p>
3356     *
3357     * @param requestContext the current request context
3358     * @param siteRoot the site root
3359     * @param source the rewrite alias source
3360     * @param target the rewrite alias target
3361     * @param mode the alias mode
3362     * @return the import result
3363     *
3364     * @throws CmsException if something goes wrong
3365     */
3366    public CmsAliasImportResult importRewriteAlias(
3367        CmsRequestContext requestContext,
3368        String siteRoot,
3369        String source,
3370        String target,
3371        CmsAliasMode mode)
3372    throws CmsException {
3373
3374        CmsDbContext dbc = m_dbContextFactory.getDbContext(requestContext);
3375        try {
3376            return m_driverManager.importRewriteAlias(dbc, siteRoot, source, target, mode);
3377        } catch (Exception e) {
3378            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
3379            return null;
3380        } finally {
3381            dbc.clear();
3382        }
3383    }
3384
3385    /**
3386     * Creates a new user by import.<p>
3387     *
3388     * @param context the current request context
3389     * @param id the id of the user
3390     * @param name the new name for the user
3391     * @param password the new password for the user
3392     * @param firstname the first name of the user
3393     * @param lastname the last name of the user
3394     * @param email the email of the user
3395     * @param flags the flags for a user (for example <code>{@link I_CmsPrincipal#FLAG_ENABLED}</code>)
3396     * @param dateCreated the creation date
3397     * @param additionalInfos the additional user infos
3398     *
3399     * @return the imported user
3400     *
3401     * @throws CmsException if something goes wrong
3402     * @throws CmsRoleViolationException if the  role {@link CmsRole#ACCOUNT_MANAGER} is not owned by the current user.
3403     */
3404    public CmsUser importUser(
3405        CmsRequestContext context,
3406        String id,
3407        String name,
3408        String password,
3409        String firstname,
3410        String lastname,
3411        String email,
3412        int flags,
3413        long dateCreated,
3414        Map<String, Object> additionalInfos)
3415    throws CmsException, CmsRoleViolationException {
3416
3417        CmsUser newUser = null;
3418
3419        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3420
3421        try {
3422            checkRole(dbc, CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(name)));
3423            newUser = m_driverManager.importUser(
3424                dbc,
3425                id,
3426                CmsOrganizationalUnit.removeLeadingSeparator(name),
3427                password,
3428                firstname,
3429                lastname,
3430                email,
3431                flags,
3432                dateCreated,
3433                additionalInfos);
3434
3435        } catch (Exception e) {
3436            dbc.report(
3437                null,
3438                Messages.get().container(
3439                    Messages.ERR_IMPORT_USER_7,
3440                    new Object[] {
3441                        name,
3442                        firstname,
3443                        lastname,
3444                        email,
3445                        new Integer(flags),
3446                        new Date(dateCreated),
3447                        additionalInfos}),
3448                e);
3449        } finally {
3450            dbc.clear();
3451        }
3452
3453        return newUser;
3454    }
3455
3456    /**
3457     * Increments a counter and returns its old value.<p>
3458     *
3459     * @param context the request context
3460     * @param name the name of the counter
3461     *
3462     * @return the value of the counter before incrementing
3463     *
3464     * @throws CmsException if something goes wrong
3465     */
3466    public int incrementCounter(CmsRequestContext context, String name) throws CmsException {
3467
3468        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3469        try {
3470            return m_driverManager.incrementCounter(dbc, name);
3471        } catch (Exception e) {
3472            dbc.report(null, Messages.get().container(Messages.ERR_INCREMENT_COUNTER_1, name), e);
3473            return -1; // will never be reached
3474        } finally {
3475            dbc.clear();
3476        }
3477    }
3478
3479    /**
3480     * Initializes this security manager with a given runtime info factory.<p>
3481     *
3482     * @param configurationManager the configurationManager
3483     * @param dbContextFactory the initialized OpenCms runtime info factory
3484     * @param publishEngine the publish engine
3485     *
3486     * @throws CmsInitException if the initialization fails
3487     */
3488    public void init(
3489        CmsConfigurationManager configurationManager,
3490        I_CmsDbContextFactory dbContextFactory,
3491        CmsPublishEngine publishEngine)
3492    throws CmsInitException {
3493
3494        if (dbContextFactory == null) {
3495            throw new CmsInitException(
3496                org.opencms.main.Messages.get().container(org.opencms.main.Messages.ERR_CRITICAL_NO_DB_CONTEXT_0));
3497        }
3498
3499        m_dbContextFactory = dbContextFactory;
3500
3501        CmsSystemConfiguration systemConfiguration = (CmsSystemConfiguration)configurationManager.getConfiguration(
3502            CmsSystemConfiguration.class);
3503
3504        // create the driver manager
3505        m_driverManager = CmsDriverManager.newInstance(configurationManager, this, dbContextFactory, publishEngine);
3506
3507        try {
3508            // invoke the init method of the driver manager
3509            m_driverManager.init(configurationManager, dbContextFactory);
3510            if (CmsLog.INIT.isInfoEnabled()) {
3511                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DRIVER_MANAGER_START_PHASE4_OK_0));
3512            }
3513        } catch (Exception exc) {
3514            CmsMessageContainer message = Messages.get().container(Messages.LOG_ERR_DRIVER_MANAGER_START_0);
3515            if (LOG.isFatalEnabled()) {
3516                LOG.fatal(message.key(), exc);
3517            }
3518            throw new CmsInitException(message, exc);
3519        }
3520
3521        // create a new lock manager
3522        m_lockManager = m_driverManager.getLockManager();
3523
3524        // initialize the permission handler
3525        String permHandlerClassName = systemConfiguration.getPermissionHandler();
3526        if (permHandlerClassName == null) {
3527            // use default implementation
3528            m_permissionHandler = new CmsDefaultPermissionHandler();
3529        } else {
3530            // use configured permission handler
3531            try {
3532                m_permissionHandler = (I_CmsPermissionHandler)Class.forName(permHandlerClassName).newInstance();
3533            } catch (Exception e) {
3534                throw new CmsInitException(
3535                    org.opencms.main.Messages.get().container(
3536                        org.opencms.main.Messages.ERR_CRITICAL_CLASS_CREATION_1,
3537                        permHandlerClassName),
3538                    e);
3539            }
3540        }
3541
3542        m_permissionHandler.init(m_driverManager, systemConfiguration);
3543
3544        if (CmsLog.INIT.isInfoEnabled()) {
3545            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SECURITY_MANAGER_INIT_0));
3546        }
3547    }
3548
3549    /**
3550     * Initializes the default groups for an organizational unit.<p>
3551     *
3552     * @param context the request context
3553     * @param ou the organizational unit
3554     */
3555    public void initializeOrgUnit(CmsRequestContext context, CmsOrganizationalUnit ou) {
3556
3557        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3558        m_driverManager.initOrgUnit(dbc, ou);
3559
3560    }
3561
3562    /**
3563     * Checks if the specified resource is inside the current project.<p>
3564     *
3565     * The project "view" is determined by a set of path prefixes.
3566     * If the resource starts with any one of this prefixes, it is considered to
3567     * be "inside" the project.<p>
3568     *
3569     * @param context the current request context
3570     * @param resourcename the specified resource name (full path)
3571     *
3572     * @return <code>true</code>, if the specified resource is inside the current project
3573     */
3574    public boolean isInsideCurrentProject(CmsRequestContext context, String resourcename) {
3575
3576        boolean result = false;
3577        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3578        try {
3579            result = m_driverManager.isInsideCurrentProject(dbc, resourcename);
3580        } finally {
3581            dbc.clear();
3582        }
3583        return result;
3584    }
3585
3586    /**
3587     * Checks if the current user has management access to the current project.<p>
3588     *
3589     * @param context the current request context
3590     *
3591     * @return <code>true</code>, if the user has management access to the current project
3592     */
3593    public boolean isManagerOfProject(CmsRequestContext context) {
3594
3595        try {
3596            return getAllManageableProjects(
3597                context,
3598                readOrganizationalUnit(context, context.getCurrentProject().getOuFqn()),
3599                false).contains(context.getCurrentProject());
3600        } catch (CmsException e) {
3601            // should never happen
3602            if (LOG.isErrorEnabled()) {
3603                LOG.error(e.getLocalizedMessage(), e);
3604            }
3605            return false;
3606        }
3607    }
3608
3609    /**
3610     * Checks whether the subscription driver is available.<p>
3611     *
3612     * @return true if the subscription driver is available
3613     */
3614    public boolean isSubscriptionDriverAvailable() {
3615
3616        return m_driverManager.isSubscriptionDriverAvailable();
3617    }
3618
3619    /**
3620     * Locks a resource.<p>
3621     *
3622     * The <code>type</code> parameter controls what kind of lock is used.<br>
3623     * Possible values for this parameter are: <br>
3624     * <ul>
3625     * <li><code>{@link org.opencms.lock.CmsLockType#EXCLUSIVE}</code></li>
3626     * <li><code>{@link org.opencms.lock.CmsLockType#TEMPORARY}</code></li>
3627     * <li><code>{@link org.opencms.lock.CmsLockType#PUBLISH}</code></li>
3628     * </ul><p>
3629     *
3630     * @param context the current request context
3631     * @param resource the resource to lock
3632     * @param type type of the lock
3633     *
3634     * @throws CmsException if something goes wrong
3635     *
3636     * @see CmsObject#lockResource(String)
3637     * @see CmsObject#lockResourceTemporary(String)
3638     * @see org.opencms.file.types.I_CmsResourceType#lockResource(CmsObject, CmsSecurityManager, CmsResource, CmsLockType)
3639     */
3640    public void lockResource(CmsRequestContext context, CmsResource resource, CmsLockType type) throws CmsException {
3641
3642        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3643        try {
3644            checkOfflineProject(dbc);
3645            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL);
3646            m_driverManager.lockResource(dbc, resource, type);
3647        } catch (Exception e) {
3648            CmsMessageContainer messageContainer;
3649            if (e instanceof CmsLockException) {
3650                messageContainer = ((CmsLockException)e).getMessageContainer();
3651            } else {
3652                messageContainer = Messages.get().container(
3653                    Messages.ERR_LOCK_RESOURCE_2,
3654                    context.getSitePath(resource),
3655                    type.toString());
3656            }
3657            dbc.report(null, messageContainer, e);
3658        } finally {
3659            dbc.clear();
3660        }
3661    }
3662
3663    /**
3664     * Attempts to authenticate a user into OpenCms with the given password.<p>
3665     *
3666     * @param context the current request context
3667     * @param username the name of the user to be logged in
3668     * @param password the password of the user
3669     * @param remoteAddress the ip address of the request
3670     *
3671     * @return the logged in user
3672     *
3673     * @throws CmsException if the login was not successful
3674     */
3675    public CmsUser loginUser(CmsRequestContext context, String username, String password, String remoteAddress)
3676    throws CmsException {
3677
3678        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3679        CmsUser result = null;
3680        try {
3681            result = m_driverManager.loginUser(
3682                dbc,
3683                CmsOrganizationalUnit.removeLeadingSeparator(username),
3684                password,
3685                remoteAddress);
3686        } finally {
3687            dbc.clear();
3688        }
3689        return result;
3690    }
3691
3692    /**
3693     * Lookup and read the user or group with the given UUID.<p>
3694     *
3695     * @param context the current request context
3696     * @param principalId the UUID of the principal to lookup
3697     *
3698     * @return the principal (group or user) if found, otherwise <code>null</code>
3699     */
3700    public I_CmsPrincipal lookupPrincipal(CmsRequestContext context, CmsUUID principalId) {
3701
3702        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3703        I_CmsPrincipal result = null;
3704        try {
3705            result = m_driverManager.lookupPrincipal(dbc, principalId);
3706        } finally {
3707            dbc.clear();
3708        }
3709        return result;
3710    }
3711
3712    /**
3713     * Lookup and read the user or group with the given name.<p>
3714     *
3715     * @param context the current request context
3716     * @param principalName the name of the principal to lookup
3717     *
3718     * @return the principal (group or user) if found, otherwise <code>null</code>
3719     */
3720    public I_CmsPrincipal lookupPrincipal(CmsRequestContext context, String principalName) {
3721
3722        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3723        I_CmsPrincipal result = null;
3724        try {
3725            result = m_driverManager.lookupPrincipal(dbc, CmsOrganizationalUnit.removeLeadingSeparator(principalName));
3726        } finally {
3727            dbc.clear();
3728        }
3729        return result;
3730    }
3731
3732    /**
3733     * Mark the given resource as visited by the user.<p>
3734     *
3735     * @param context the request context
3736     * @param poolName the name of the database pool to use
3737     * @param resource the resource to mark as visited
3738     * @param user the user that visited the resource
3739     *
3740     * @throws CmsException if something goes wrong
3741     */
3742    public void markResourceAsVisitedBy(CmsRequestContext context, String poolName, CmsResource resource, CmsUser user)
3743    throws CmsException {
3744
3745        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3746        try {
3747            m_driverManager.markResourceAsVisitedBy(dbc, poolName, resource, user);
3748        } catch (Exception e) {
3749            dbc.report(
3750                null,
3751                Messages.get().container(
3752                    Messages.ERR_MARK_RESOURCE_AS_VISITED_2,
3753                    context.getSitePath(resource),
3754                    user.getName()),
3755                e);
3756        } finally {
3757            dbc.clear();
3758        }
3759    }
3760
3761    /**
3762     * Returns a new publish list that contains all resources of both given publish lists.<p>
3763     *
3764     * @param context the current request context
3765     * @param pubList1 the first publish list
3766     * @param pubList2 the second publish list
3767     *
3768     * @return a new publish list that contains all resources of both given publish lists
3769     *
3770     * @throws CmsException if something goes wrong
3771     *
3772     * @see org.opencms.publish.CmsPublishManager#mergePublishLists(CmsObject, CmsPublishList, CmsPublishList)
3773     */
3774    public CmsPublishList mergePublishLists(CmsRequestContext context, CmsPublishList pubList1, CmsPublishList pubList2)
3775    throws CmsException {
3776
3777        CmsPublishList ret = null;
3778        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3779        try {
3780            // get all resources from the first list
3781            Set<CmsResource> publishResources = new HashSet<CmsResource>(pubList1.getAllResources());
3782            // get all resources from the second list
3783            publishResources.addAll(pubList2.getAllResources());
3784
3785            // create merged publish list
3786            ret = new CmsPublishList(
3787                pubList1.getDirectPublishResources(),
3788                pubList1.isPublishSiblings(),
3789                pubList1.isPublishSubResources());
3790            ret.addAll(publishResources, false); // ignore files that should not be published
3791            if (pubList1.isUserPublishList()) {
3792                ret.setUserPublishList(true);
3793            }
3794            ret.initialize(); // ensure sort order
3795
3796            checkPublishPermissions(dbc, ret);
3797        } catch (Exception e) {
3798            dbc.report(null, Messages.get().container(Messages.ERR_MERGING_PUBLISH_LISTS_0), e);
3799        } finally {
3800            dbc.clear();
3801        }
3802        return ret;
3803    }
3804
3805    /**
3806     * Moves a resource.<p>
3807     *
3808     * You must ensure that the destination path is an absolute, valid and
3809     * existing VFS path. Relative paths from the source are currently not supported.<p>
3810     *
3811     * The moved resource will always be locked to the current user
3812     * after the move operation.<p>
3813     *
3814     * In case the target resource already exists, it is overwritten with the
3815     * source resource.<p>
3816     *
3817     * @param context the current request context
3818     * @param source the resource to copy
3819     * @param destination the name of the copy destination with complete path
3820     *
3821     * @throws CmsException if something goes wrong
3822     * @throws CmsSecurityException if resource could not be copied
3823     *
3824     * @see CmsObject#moveResource(String, String)
3825     * @see org.opencms.file.types.I_CmsResourceType#moveResource(CmsObject, CmsSecurityManager, CmsResource, String)
3826     */
3827    public void moveResource(CmsRequestContext context, CmsResource source, String destination)
3828    throws CmsException, CmsSecurityException {
3829
3830        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3831        try {
3832            checkOfflineProject(dbc);
3833            // checking if the destination folder exists and is not marked as deleted
3834            readResource(context, CmsResource.getParentFolder(destination), CmsResourceFilter.IGNORE_EXPIRATION);
3835            checkPermissions(dbc, source, CmsPermissionSet.ACCESS_READ, true, CmsResourceFilter.ALL);
3836            checkPermissions(dbc, source, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
3837
3838            checkSystemLocks(dbc, source);
3839
3840            // check write permissions for subresources in case of moving a folder
3841            if (source.isFolder()) {
3842                dbc.getRequestContext().setAttribute(I_CmsVfsDriver.REQ_ATTR_CHECK_PERMISSIONS, Boolean.TRUE);
3843                try {
3844                    m_driverManager.getVfsDriver(
3845                        dbc).moveResource(dbc, dbc.currentProject().getUuid(), source, destination);
3846                } catch (CmsDataAccessException e) {
3847                    // unwrap the permission violation exception
3848                    if (e.getCause() instanceof CmsPermissionViolationException) {
3849                        throw (CmsPermissionViolationException)e.getCause();
3850                    } else {
3851                        throw e;
3852                    }
3853                }
3854                dbc.getRequestContext().removeAttribute(I_CmsVfsDriver.REQ_ATTR_CHECK_PERMISSIONS);
3855            }
3856            Set<CmsResource> allMovedResources = new HashSet<>();
3857            moveResource(dbc, source, destination, allMovedResources);
3858            if (!dbc.currentProject().isOnlineProject()) {
3859                for (CmsResource movedResource : allMovedResources) {
3860                    m_driverManager.repairCategories(
3861                        dbc,
3862                        dbc.getRequestContext().getCurrentProject().getUuid(),
3863                        movedResource);
3864                }
3865            }
3866
3867        } catch (Exception e) {
3868            dbc.report(
3869                null,
3870                Messages.get().container(
3871                    Messages.ERR_MOVE_RESOURCE_2,
3872                    dbc.removeSiteRoot(source.getRootPath()),
3873                    dbc.removeSiteRoot(destination)),
3874                e);
3875        } finally {
3876            dbc.clear();
3877        }
3878    }
3879
3880    /**
3881     * Moves a resource to the "lost and found" folder.<p>
3882     *
3883     * The method can also be used to check get the name of a resource
3884     * in the "lost and found" folder only without actually moving the
3885     * the resource. To do this, the <code>returnNameOnly</code> flag
3886     * must be set to <code>true</code>.<p>
3887     *
3888     * In general, it is the same name as the given resource has, the only exception is
3889     * if a resource in the "lost and found" folder with the same name already exists.
3890     * In such case, a counter is added to the resource name.<p>
3891     *
3892     * @param context the current request context
3893     * @param resource the resource to apply this operation to
3894     * @param returnNameOnly if <code>true</code>, only the name of the resource in the "lost and found"
3895     *        folder is returned, the move operation is not really performed
3896     *
3897     * @return the name of the resource inside the "lost and found" folder
3898     *
3899     * @throws CmsException if something goes wrong
3900     *
3901     * @see CmsObject#moveToLostAndFound(String)
3902     * @see CmsObject#getLostAndFoundName(String)
3903     */
3904    public String moveToLostAndFound(CmsRequestContext context, CmsResource resource, boolean returnNameOnly)
3905    throws CmsException {
3906
3907        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3908        String result = null;
3909        try {
3910            checkOfflineProject(dbc);
3911            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, true, CmsResourceFilter.ALL);
3912            if (!returnNameOnly) {
3913                checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
3914            }
3915            result = m_driverManager.moveToLostAndFound(dbc, resource, returnNameOnly);
3916        } catch (Exception e) {
3917            dbc.report(
3918                null,
3919                Messages.get().container(
3920                    Messages.ERR_MOVE_TO_LOST_AND_FOUND_1,
3921                    dbc.removeSiteRoot(resource.getRootPath())),
3922                e);
3923        } finally {
3924            dbc.clear();
3925        }
3926        return result;
3927    }
3928
3929    /**
3930     * Publishes the resources of a specified publish list.<p>
3931     *
3932     * @param cms the current request context
3933     * @param publishList a publish list
3934     * @param report an instance of <code>{@link I_CmsReport}</code> to print messages
3935     *
3936     * @return the publish history id of the published project
3937     *
3938     * @throws CmsException if something goes wrong
3939     *
3940     * @see #fillPublishList(CmsRequestContext, CmsPublishList)
3941     */
3942    public CmsUUID publishProject(CmsObject cms, CmsPublishList publishList, I_CmsReport report) throws CmsException {
3943
3944        CmsRequestContext context = cms.getRequestContext();
3945        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3946        try {
3947            // check if the current user has the required publish permissions
3948            checkPublishPermissions(dbc, publishList);
3949            m_driverManager.publishProject(cms, dbc, publishList, report);
3950        } finally {
3951            dbc.clear();
3952        }
3953        return publishList.getPublishHistoryId();
3954    }
3955
3956    /**
3957     * Reads the alias with a given path in a given site.<p>
3958     *
3959     * @param context the current request context
3960     * @param siteRoot the site root
3961     * @param path the site relative alias path
3962     * @return the alias for the path, or null if no such alias exists
3963     *
3964     * @throws CmsException if something goes wrong
3965     */
3966    public CmsAlias readAliasByPath(CmsRequestContext context, String siteRoot, String path) throws CmsException {
3967
3968        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3969        try {
3970            CmsAlias alias = m_driverManager.readAliasByPath(dbc, context.getCurrentProject(), siteRoot, path);
3971            return alias;
3972        } catch (Exception e) {
3973            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
3974            return null; // will never be executed
3975        } finally {
3976            dbc.clear();
3977        }
3978    }
3979
3980    /**
3981     * Reads the aliases for a resource with a given structure id.<p>
3982     *
3983     * @param context the current request context
3984     * @param structureId the structure id for which the aliases should be read
3985     *
3986     * @return the aliases for the structure id
3987     *
3988     * @throws CmsException if something goes wrong
3989     */
3990    public List<CmsAlias> readAliasesById(CmsRequestContext context, CmsUUID structureId) throws CmsException {
3991
3992        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
3993        try {
3994            List<CmsAlias> aliases = m_driverManager.readAliasesByStructureId(
3995                dbc,
3996                context.getCurrentProject(),
3997                structureId);
3998            return aliases;
3999        } catch (Exception e) {
4000            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
4001            return null; // will never be executed
4002        } finally {
4003            dbc.clear();
4004        }
4005
4006    }
4007
4008    /**
4009     * Reads all historical versions of a resource.<p>
4010     *
4011     * The reading excludes the file content, if the resource is a file.<p>
4012     *
4013     * @param context the current request context
4014     * @param resource the resource to be read
4015     *
4016     * @return a list of historical versions, as <code>{@link I_CmsHistoryResource}</code> objects
4017     *
4018     * @throws CmsException if something goes wrong
4019     */
4020    public List<I_CmsHistoryResource> readAllAvailableVersions(CmsRequestContext context, CmsResource resource)
4021    throws CmsException {
4022
4023        List<I_CmsHistoryResource> result = null;
4024        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4025        try {
4026            result = m_driverManager.readAllAvailableVersions(dbc, resource);
4027        } catch (Exception e) {
4028            dbc.report(
4029                null,
4030                Messages.get().container(Messages.ERR_READ_ALL_HISTORY_FILE_HEADERS_1, context.getSitePath(resource)),
4031                e);
4032        } finally {
4033            dbc.clear();
4034        }
4035        return result;
4036    }
4037
4038    /**
4039     * Reads all property definitions for the given mapping type.<p>
4040     *
4041     * @param context the current request context
4042     *
4043     * @return a list with the <code>{@link CmsPropertyDefinition}</code> objects (may be empty)
4044     *
4045     * @throws CmsException if something goes wrong
4046     */
4047    public List<CmsPropertyDefinition> readAllPropertyDefinitions(CmsRequestContext context) throws CmsException {
4048
4049        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4050        List<CmsPropertyDefinition> result = null;
4051        try {
4052            result = m_driverManager.readAllPropertyDefinitions(dbc);
4053        } catch (Exception e) {
4054            dbc.report(null, Messages.get().container(Messages.ERR_READ_ALL_PROPDEF_0), e);
4055        } finally {
4056            dbc.clear();
4057        }
4058        return result;
4059    }
4060
4061    /**
4062     * Returns all resources subscribed by the given user or group.<p>
4063     *
4064     * @param context the request context
4065     * @param poolName the name of the database pool to use
4066     * @param principal the principal to read the subscribed resources
4067     *
4068     * @return all resources subscribed by the given user or group
4069     *
4070     * @throws CmsException if something goes wrong
4071     */
4072    public List<CmsResource> readAllSubscribedResources(
4073        CmsRequestContext context,
4074        String poolName,
4075        CmsPrincipal principal)
4076    throws CmsException {
4077
4078        List<CmsResource> result = null;
4079        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4080        try {
4081            result = m_driverManager.readAllSubscribedResources(dbc, poolName, principal);
4082        } catch (Exception e) {
4083            if (principal instanceof CmsUser) {
4084                dbc.report(
4085                    null,
4086                    Messages.get().container(Messages.ERR_READ_SUBSCRIBED_RESOURCES_ALL_USER_1, principal.getName()),
4087                    e);
4088            } else {
4089                dbc.report(
4090                    null,
4091                    Messages.get().container(Messages.ERR_READ_SUBSCRIBED_RESOURCES_ALL_GROUP_1, principal.getName()),
4092                    e);
4093            }
4094        } finally {
4095            dbc.clear();
4096        }
4097        return result;
4098    }
4099
4100    /**
4101     * Reads all URL name mapping entries for a given structure id.<p>
4102     *
4103     * @param context the request context
4104     * @param id the structure id
4105     *
4106     * @return the list of URL names for the given structure id
4107     * @throws CmsException if something goes wrong
4108     */
4109    public List<String> readAllUrlNameMappingEntries(CmsRequestContext context, CmsUUID id) throws CmsException {
4110
4111        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4112        try {
4113            List<CmsUrlNameMappingEntry> entries = m_driverManager.readUrlNameMappingEntries(
4114                dbc,
4115                context.getCurrentProject().isOnlineProject(),
4116                CmsUrlNameMappingFilter.ALL.filterStructureId(id));
4117            List<String> result = new ArrayList<String>();
4118            for (CmsUrlNameMappingEntry entry : entries) {
4119                result.add(entry.getName());
4120            }
4121            return result;
4122        } catch (Exception e) {
4123            CmsMessageContainer message = Messages.get().container(
4124                Messages.ERR_READ_NEWEST_URLNAME_FOR_ID_1,
4125                id.toString());
4126            dbc.report(null, message, e);
4127            return null;
4128        } finally {
4129            dbc.clear();
4130        }
4131
4132    }
4133
4134    /**
4135     * Returns the first ancestor folder matching the filter criteria.<p>
4136     *
4137     * If no folder matching the filter criteria is found, null is returned.<p>
4138     *
4139     * @param context the context of the current request
4140     * @param resource the resource to start
4141     * @param filter the resource filter to match while reading the ancestors
4142     *
4143     * @return the first ancestor folder matching the filter criteria or <code>null</code> if no folder was found
4144     *
4145     * @throws CmsException if something goes wrong
4146     */
4147    public CmsFolder readAncestor(CmsRequestContext context, CmsResource resource, CmsResourceFilter filter)
4148    throws CmsException {
4149
4150        // get the full folder path of the resource to start from
4151        String path = CmsResource.getFolderPath(resource.getRootPath());
4152        do {
4153            // check if the current folder matches the given filter
4154            if (existsResource(context, path, filter)) {
4155                // folder matches, return it
4156                return readFolder(context, path, filter);
4157            } else {
4158                // folder does not match filter criteria, go up one folder
4159                path = CmsResource.getParentFolder(path);
4160            }
4161
4162            if (CmsStringUtil.isEmpty(path) || !path.startsWith(context.getSiteRoot())) {
4163                // site root or root folder reached and no matching folder found
4164                return null;
4165            }
4166        } while (true);
4167    }
4168
4169    /**
4170     * Reads the newest URL name which is mapped to the given structure id.<p>
4171     *
4172     * If the structure id is not mapped to any name, null will be returned.<p>
4173     *
4174     * @param context the request context
4175     * @param id the structure id for which the newest mapped name should be returned
4176     * @param locale the locale for the mapping
4177     * @param defaultLocales the default locales to use if there is no URL name mapping for the requested locale
4178     *
4179     * @return an URL name or null
4180     *
4181     * @throws CmsException if something goes wrong
4182     */
4183    public String readBestUrlName(CmsRequestContext context, CmsUUID id, Locale locale, List<Locale> defaultLocales)
4184    throws CmsException {
4185
4186        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4187        try {
4188            return m_driverManager.readBestUrlName(dbc, id, locale, defaultLocales);
4189        } catch (Exception e) {
4190            CmsMessageContainer message = Messages.get().container(
4191                Messages.ERR_READ_NEWEST_URLNAME_FOR_ID_1,
4192                id.toString());
4193            dbc.report(null, message, e);
4194            return null; // will never be reached
4195        } finally {
4196            dbc.clear();
4197        }
4198    }
4199
4200    /**
4201     * Returns the child resources of a resource, that is the resources
4202     * contained in a folder.<p>
4203     *
4204     * With the parameters <code>getFolders</code> and <code>getFiles</code>
4205     * you can control what type of resources you want in the result list:
4206     * files, folders, or both.<p>
4207     *
4208     * This method is mainly used by the workplace explorer.<p>
4209     *
4210     * @param context the current request context
4211     * @param resource the resource to return the child resources for
4212     * @param filter the resource filter to use
4213     * @param getFolders if true the child folders are included in the result
4214     * @param getFiles if true the child files are included in the result
4215     *
4216     * @return a list of all child resources
4217     *
4218     * @throws CmsException if something goes wrong
4219     * @throws CmsSecurityException if the user has insufficient permission for the given resource (read is required)
4220     *
4221     */
4222    public List<CmsResource> readChildResources(
4223        CmsRequestContext context,
4224        CmsResource resource,
4225        CmsResourceFilter filter,
4226        boolean getFolders,
4227        boolean getFiles)
4228    throws CmsException, CmsSecurityException {
4229
4230        List<CmsResource> result = null;
4231        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4232        try {
4233            // check the access permissions
4234            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, true, CmsResourceFilter.ALL);
4235            result = m_driverManager.readChildResources(dbc, resource, filter, getFolders, getFiles, true);
4236        } catch (Exception e) {
4237            dbc.report(
4238                null,
4239                Messages.get().container(Messages.ERR_READ_CHILD_RESOURCES_1, context.getSitePath(resource)),
4240                e);
4241        } finally {
4242            dbc.clear();
4243        }
4244        return result;
4245    }
4246
4247    /**
4248     * Returns the default file for the given folder.<p>
4249     *
4250     * If the given resource is a file, then this file is returned.<p>
4251     *
4252     * Otherwise, in case of a folder:<br>
4253     * <ol>
4254     *   <li>the {@link CmsPropertyDefinition#PROPERTY_DEFAULT_FILE} is checked, and
4255     *   <li>if still no file could be found, the configured default files in the
4256     *       <code>opencms-vfs.xml</code> configuration are iterated until a match is
4257     *       found, and
4258     *   <li>if still no file could be found, <code>null</code> is returned
4259     * </ol><p>
4260     *
4261     * @param context the request context
4262     * @param resource the folder to get the default file for
4263     * @param resourceFilter the resource filter
4264     *
4265     * @return the default file for the given folder
4266     *
4267     * @throws CmsSecurityException if the user has no permissions to read the resulting file
4268     *
4269     * @see CmsObject#readDefaultFile(String)
4270     */
4271    public CmsResource readDefaultFile(
4272        CmsRequestContext context,
4273        CmsResource resource,
4274        CmsResourceFilter resourceFilter)
4275    throws CmsSecurityException {
4276
4277        CmsResource result = null;
4278        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4279        try {
4280            CmsResource tempResult = m_driverManager.readDefaultFile(dbc, resource, resourceFilter);
4281            if (tempResult != null) {
4282                // check if the user has read access to the resource
4283                checkPermissions(dbc, tempResult, CmsPermissionSet.ACCESS_READ, true, resourceFilter);
4284                result = tempResult;
4285            }
4286        } catch (CmsSecurityException se) {
4287            // permissions deny access to the resource
4288            throw se;
4289        } catch (CmsException e) {
4290            // ignore all other exceptions
4291            LOG.debug(e.getLocalizedMessage(), e);
4292        } finally {
4293            dbc.clear();
4294        }
4295        return result;
4296    }
4297
4298    /**
4299     * Reads all deleted (historical) resources below the given path,
4300     * including the full tree below the path, if required.<p>
4301     *
4302     * @param context the current request context
4303     * @param resource the parent resource to read the resources from
4304     * @param readTree <code>true</code> to read all subresources
4305     *
4306     * @return a list of <code>{@link I_CmsHistoryResource}</code> objects
4307     *
4308     * @throws CmsException if something goes wrong
4309     *
4310     * @see CmsObject#readResource(CmsUUID, int)
4311     * @see CmsObject#readResources(String, CmsResourceFilter, boolean)
4312     * @see CmsObject#readDeletedResources(String, boolean)
4313     */
4314    public List<I_CmsHistoryResource> readDeletedResources(
4315        CmsRequestContext context,
4316        CmsResource resource,
4317        boolean readTree)
4318    throws CmsException {
4319
4320        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4321        List<I_CmsHistoryResource> result = null;
4322        try {
4323            boolean isVfsManager = hasRoleForResource(dbc, dbc.currentUser(), CmsRole.VFS_MANAGER, resource);
4324            result = m_driverManager.readDeletedResources(dbc, resource, readTree, isVfsManager);
4325        } catch (CmsException e) {
4326            dbc.report(
4327                null,
4328                Messages.get().container(
4329                    Messages.ERR_READING_DELETED_RESOURCES_1,
4330                    dbc.removeSiteRoot(resource.getRootPath())),
4331                e);
4332        } finally {
4333            dbc.clear();
4334        }
4335        return result;
4336    }
4337
4338    /**
4339     * Reads a file resource (including it's binary content) from the VFS.<p>
4340     *
4341     * In case you do not need the file content,
4342     * use <code>{@link #readResource(CmsRequestContext, String, CmsResourceFilter)}</code> instead.<p>
4343     *
4344     * @param context the current request context
4345     * @param resource the resource to be read
4346     *
4347     * @return the file read from the VFS
4348     *
4349     * @throws CmsException if something goes wrong
4350     */
4351    public CmsFile readFile(CmsRequestContext context, CmsResource resource) throws CmsException {
4352
4353        CmsFile result = null;
4354        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4355        try {
4356            result = m_driverManager.readFile(dbc, resource);
4357        } catch (Exception e) {
4358            if (resource instanceof I_CmsHistoryResource) {
4359                dbc.report(
4360                    null,
4361                    Messages.get().container(
4362                        Messages.ERR_READ_FILE_HISTORY_2,
4363                        context.getSitePath(resource),
4364                        new Integer(resource.getVersion())),
4365                    e);
4366            } else {
4367                dbc.report(null, Messages.get().container(Messages.ERR_READ_FILE_1, context.getSitePath(resource)), e);
4368            }
4369        } finally {
4370            dbc.clear();
4371        }
4372        return result;
4373    }
4374
4375    /**
4376     * Reads a folder resource from the VFS,
4377     * using the specified resource filter.<p>
4378     *
4379     * The specified filter controls what kind of resources should be "found"
4380     * during the read operation. This will depend on the application. For example,
4381     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
4382     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
4383     * will ignore the date release / date expired information of the resource.<p>
4384     *
4385     * @param context the current request context
4386     * @param resourcename the name of the folder to read (full path)
4387     * @param filter the resource filter to use while reading
4388     *
4389     * @return the folder that was read
4390     *
4391     * @throws CmsException if something goes wrong
4392     */
4393    public CmsFolder readFolder(CmsRequestContext context, String resourcename, CmsResourceFilter filter)
4394    throws CmsException {
4395
4396        CmsFolder result = null;
4397        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4398        try {
4399            result = readFolder(dbc, resourcename, filter);
4400        } catch (Exception e) {
4401            dbc.report(null, Messages.get().container(Messages.ERR_READ_FOLDER_2, resourcename, filter), e);
4402        } finally {
4403            dbc.clear();
4404        }
4405        return result;
4406    }
4407
4408    /**
4409     * Reads the group of a project.<p>
4410     *
4411     * @param context the current request context
4412     * @param project the project to read from
4413     *
4414     * @return the group of a resource
4415     */
4416    public CmsGroup readGroup(CmsRequestContext context, CmsProject project) {
4417
4418        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4419        CmsGroup result = null;
4420        try {
4421            result = m_driverManager.readGroup(dbc, project);
4422        } finally {
4423            dbc.clear();
4424        }
4425        return result;
4426    }
4427
4428    /**
4429     * Reads a group based on its id.<p>
4430     *
4431     * @param context the current request context
4432     * @param groupId the id of the group that is to be read
4433     *
4434     * @return the requested group
4435     *
4436     * @throws CmsException if operation was not successful
4437     */
4438    public CmsGroup readGroup(CmsRequestContext context, CmsUUID groupId) throws CmsException {
4439
4440        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4441        CmsGroup result = null;
4442        try {
4443            result = m_driverManager.readGroup(dbc, groupId);
4444        } catch (Exception e) {
4445            dbc.report(null, Messages.get().container(Messages.ERR_READ_GROUP_FOR_ID_1, groupId.toString()), e);
4446        } finally {
4447            dbc.clear();
4448        }
4449        return result;
4450    }
4451
4452    /**
4453     * Reads a group based on its name.<p>
4454     *
4455     * @param context the current request context
4456     * @param groupname the name of the group that is to be read
4457     *
4458     * @return the requested group
4459     *
4460     * @throws CmsException if operation was not successful
4461     */
4462    public CmsGroup readGroup(CmsRequestContext context, String groupname) throws CmsException {
4463
4464        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4465        CmsGroup result = null;
4466        try {
4467            result = m_driverManager.readGroup(dbc, CmsOrganizationalUnit.removeLeadingSeparator(groupname));
4468        } catch (Exception e) {
4469            dbc.report(null, Messages.get().container(Messages.ERR_READ_GROUP_FOR_NAME_1, groupname), e);
4470        } finally {
4471            dbc.clear();
4472        }
4473        return result;
4474    }
4475
4476    /**
4477     * Reads a principal (an user or group) from the historical archive based on its ID.<p>
4478     *
4479     * @param context the current request context
4480     * @param principalId the id of the principal to read
4481     *
4482     * @return the historical principal entry with the given id
4483     *
4484     * @throws CmsException if something goes wrong, ie. {@link CmsDbEntryNotFoundException}
4485     *
4486     * @see CmsObject#readUser(CmsUUID)
4487     * @see CmsObject#readGroup(CmsUUID)
4488     * @see CmsObject#readHistoryPrincipal(CmsUUID)
4489     */
4490    public CmsHistoryPrincipal readHistoricalPrincipal(CmsRequestContext context, CmsUUID principalId)
4491    throws CmsException {
4492
4493        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4494        CmsHistoryPrincipal result = null;
4495        try {
4496            result = m_driverManager.readHistoricalPrincipal(dbc, principalId);
4497        } catch (Exception e) {
4498            dbc.report(null, Messages.get().container(Messages.ERR_READ_HISTORY_PRINCIPAL_1, principalId), e);
4499        } finally {
4500            dbc.clear();
4501        }
4502        return result;
4503    }
4504
4505    /**
4506     * Returns the latest historical project entry with the given id.<p>
4507     *
4508     * @param context the current request context
4509     * @param projectId the project id
4510     *
4511     * @return the requested historical project entry
4512     *
4513     * @throws CmsException if something goes wrong
4514     */
4515    public CmsHistoryProject readHistoryProject(CmsRequestContext context, CmsUUID projectId) throws CmsException {
4516
4517        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4518        CmsHistoryProject result = null;
4519        try {
4520            result = m_driverManager.readHistoryProject(dbc, projectId);
4521        } catch (Exception e) {
4522            dbc.report(
4523                null,
4524                Messages.get().container(
4525                    Messages.ERR_READ_HISTORY_PROJECT_2,
4526                    projectId,
4527                    dbc.currentProject().getName()),
4528                e);
4529        } finally {
4530            dbc.clear();
4531        }
4532        return result;
4533    }
4534
4535    /**
4536     * Returns a historical project entry.<p>
4537     *
4538     * @param context the current request context
4539     * @param publishTag the publish tag of the project
4540     *
4541     * @return the requested historical project entry
4542     *
4543     * @throws CmsException if something goes wrong
4544     */
4545    public CmsHistoryProject readHistoryProject(CmsRequestContext context, int publishTag) throws CmsException {
4546
4547        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4548        CmsHistoryProject result = null;
4549        try {
4550            result = m_driverManager.readHistoryProject(dbc, publishTag);
4551        } catch (Exception e) {
4552            dbc.report(
4553                null,
4554                Messages.get().container(
4555                    Messages.ERR_READ_HISTORY_PROJECT_2,
4556                    new Integer(publishTag),
4557                    dbc.currentProject().getName()),
4558                e);
4559        } finally {
4560            dbc.clear();
4561        }
4562        return result;
4563    }
4564
4565    /**
4566     * Reads the list of all <code>{@link CmsProperty}</code> objects that belong to the given historical resource.<p>
4567     *
4568     * @param context the current request context
4569     * @param resource the historical resource entry to read the properties for
4570     *
4571     * @return the list of <code>{@link CmsProperty}</code> objects
4572     *
4573     * @throws CmsException if something goes wrong
4574     */
4575    public List<CmsProperty> readHistoryPropertyObjects(CmsRequestContext context, I_CmsHistoryResource resource)
4576    throws CmsException {
4577
4578        List<CmsProperty> result = null;
4579        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4580        try {
4581            result = m_driverManager.readHistoryPropertyObjects(dbc, resource);
4582        } catch (Exception e) {
4583            dbc.report(
4584                null,
4585                Messages.get().container(
4586                    Messages.ERR_READ_PROPS_FOR_RESOURCE_1,
4587                    context.getSitePath((CmsResource)resource)),
4588                e);
4589        } finally {
4590            dbc.clear();
4591        }
4592        return result;
4593    }
4594
4595    /**
4596     * Reads the structure id which is mapped to the given URL name, or null if the name is not
4597     * mapped to any structure IDs.<p>
4598     *
4599     * @param context the request context
4600     * @param name an URL name
4601     *
4602     * @return the structure ID which is mapped to the given name
4603     *
4604     * @throws CmsException if something goes wrong
4605     */
4606    public CmsUUID readIdForUrlName(CmsRequestContext context, String name) throws CmsException {
4607
4608        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4609        try {
4610            return m_driverManager.readIdForUrlName(dbc, name);
4611        } catch (Exception e) {
4612            CmsMessageContainer message = Messages.get().container(Messages.ERR_READ_ID_FOR_URLNAME_1, name);
4613            dbc.report(null, message, e);
4614            return null; // will never be reached
4615        } finally {
4616            dbc.clear();
4617        }
4618
4619    }
4620
4621    /**
4622     * Reads the locks that were saved to the database in the previous run of OpenCms.<p>
4623     *
4624     * @throws CmsException if something goes wrong
4625     */
4626    public void readLocks() throws CmsException {
4627
4628        CmsDbContext dbc = m_dbContextFactory.getDbContext();
4629        try {
4630            m_driverManager.readLocks(dbc);
4631        } finally {
4632            dbc.clear();
4633        }
4634    }
4635
4636    /**
4637     * Reads the manager group of a project.<p>
4638     *
4639     * @param context the current request context
4640     * @param project the project to read from
4641     *
4642     * @return the group of a resource
4643     */
4644    public CmsGroup readManagerGroup(CmsRequestContext context, CmsProject project) {
4645
4646        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4647        CmsGroup result = null;
4648        try {
4649            result = m_driverManager.readManagerGroup(dbc, project);
4650        } finally {
4651            dbc.clear();
4652        }
4653        return result;
4654    }
4655
4656    /**
4657     * Reads an organizational Unit based on its fully qualified name.<p>
4658     *
4659     * @param context the current request context
4660     * @param ouFqn the fully qualified name of the organizational Unit to be read
4661     *
4662     * @return the organizational Unit that with the provided fully qualified name
4663     *
4664     * @throws CmsException if something goes wrong
4665     */
4666    public CmsOrganizationalUnit readOrganizationalUnit(CmsRequestContext context, String ouFqn) throws CmsException {
4667
4668        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4669        CmsOrganizationalUnit result = null;
4670        try {
4671            result = m_driverManager.readOrganizationalUnit(dbc, CmsOrganizationalUnit.removeLeadingSeparator(ouFqn));
4672        } catch (Exception e) {
4673            dbc.report(null, Messages.get().container(Messages.ERR_READ_ORGUNIT_1, ouFqn), e);
4674        } finally {
4675            dbc.clear();
4676        }
4677        return result;
4678    }
4679
4680    /**
4681     * Reads the owner of a project from the OpenCms.<p>
4682     *
4683     * @param context the current request context
4684     * @param project the project to get the owner from
4685     *
4686     * @return the owner of a resource
4687     *
4688     * @throws CmsException if something goes wrong
4689     */
4690    public CmsUser readOwner(CmsRequestContext context, CmsProject project) throws CmsException {
4691
4692        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4693        CmsUser result = null;
4694        try {
4695            result = m_driverManager.readOwner(dbc, project);
4696        } catch (Exception e) {
4697            dbc.report(
4698                null,
4699                Messages.get().container(Messages.ERR_READ_OWNER_FOR_PROJECT_2, project.getName(), project.getUuid()),
4700                e);
4701        } finally {
4702            dbc.clear();
4703        }
4704        return result;
4705    }
4706
4707    /**
4708     * Returns the parent folder to the given structure id.<p>
4709     *
4710     * @param context the current request context
4711     * @param structureId the child structure id
4712     *
4713     * @return the parent folder <code>{@link CmsResource}</code>
4714     *
4715     * @throws CmsException if something goes wrong
4716     */
4717    public CmsResource readParentFolder(CmsRequestContext context, CmsUUID structureId) throws CmsException {
4718
4719        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4720        CmsResource result = null;
4721        try {
4722            result = m_driverManager.readParentFolder(dbc, structureId);
4723        } catch (Exception e) {
4724            dbc.report(
4725                null,
4726                Messages.get().container(
4727                    Messages.ERR_READ_PARENT_FOLDER_2,
4728                    dbc.currentProject().getName(),
4729                    structureId),
4730                e);
4731        } finally {
4732            dbc.clear();
4733        }
4734        return result;
4735    }
4736
4737    /**
4738     * Builds a list of resources for a given path.<p>
4739     *
4740     * @param context the current request context
4741     * @param path the requested path
4742     * @param filter a filter object (only "includeDeleted" information is used!)
4743     *
4744     * @return list of <code>{@link CmsResource}</code>s
4745     *
4746     * @throws CmsException if something goes wrong
4747     */
4748    public List<CmsResource> readPath(CmsRequestContext context, String path, CmsResourceFilter filter)
4749    throws CmsException {
4750
4751        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4752        List<CmsResource> result = null;
4753        try {
4754            result = m_driverManager.readPath(dbc, path, filter);
4755        } catch (Exception e) {
4756            dbc.report(
4757                null,
4758                Messages.get().container(Messages.ERR_READ_PATH_2, dbc.currentProject().getName(), path),
4759                e);
4760        } finally {
4761            dbc.clear();
4762        }
4763        return result;
4764    }
4765
4766    /**
4767     * Reads a project given the projects id.<p>
4768     *
4769     * @param id the id of the project
4770     *
4771     * @return the project read
4772     *
4773     * @throws CmsException if something goes wrong
4774     */
4775    public CmsProject readProject(CmsUUID id) throws CmsException {
4776
4777        CmsDbContext dbc = m_dbContextFactory.getDbContext();
4778        CmsProject result = null;
4779        try {
4780            result = m_driverManager.readProject(dbc, id);
4781        } catch (Exception e) {
4782            dbc.report(null, Messages.get().container(Messages.ERR_READ_PROJECT_FOR_ID_1, id), e);
4783        } finally {
4784            dbc.clear();
4785        }
4786        return result;
4787    }
4788
4789    /**
4790     * Reads a project.<p>
4791     *
4792     * Important: Since a project name can be used multiple times, this is NOT the most efficient
4793     * way to read the project. This is only a convenience for front end developing.
4794     * Reading a project by name will return the first project with that name.
4795     * All core classes must use the id version {@link #readProject(CmsUUID)} to ensure the right project is read.<p>
4796     *
4797     * @param name the name of the project
4798     *
4799     * @return the project read
4800     *
4801     * @throws CmsException if something goes wrong
4802     */
4803    public CmsProject readProject(String name) throws CmsException {
4804
4805        CmsDbContext dbc = m_dbContextFactory.getDbContext();
4806        CmsProject result = null;
4807        try {
4808            result = m_driverManager.readProject(dbc, CmsOrganizationalUnit.removeLeadingSeparator(name));
4809        } catch (Exception e) {
4810            dbc.report(null, Messages.get().container(Messages.ERR_READ_PROJECT_FOR_NAME_1, name), e);
4811        } finally {
4812            dbc.clear();
4813        }
4814        return result;
4815    }
4816
4817    /**
4818     * Returns the list of all resource names that define the "view" of the given project.<p>
4819     *
4820     * @param context the current request context
4821     * @param project the project to get the project resources for
4822     *
4823     * @return the list of all resources, as <code>{@link String}</code> objects
4824     *              that define the "view" of the given project
4825     *
4826     * @throws CmsException if something goes wrong
4827     */
4828    public List<String> readProjectResources(CmsRequestContext context, CmsProject project) throws CmsException {
4829
4830        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4831        List<String> result = null;
4832        try {
4833            result = m_driverManager.readProjectResources(dbc, project);
4834        } catch (Exception e) {
4835            dbc.report(
4836                null,
4837                Messages.get().container(Messages.ERR_READ_PROJECT_RESOURCES_2, project.getName(), project.getUuid()),
4838                e);
4839        } finally {
4840            dbc.clear();
4841        }
4842        return result;
4843    }
4844
4845    /**
4846     * Reads all resources of a project that match a given state from the VFS.<p>
4847     *
4848     * Possible values for the <code>state</code> parameter are:<br>
4849     * <ul>
4850     * <li><code>{@link CmsResource#STATE_CHANGED}</code>: Read all "changed" resources in the project</li>
4851     * <li><code>{@link CmsResource#STATE_NEW}</code>: Read all "new" resources in the project</li>
4852     * <li><code>{@link CmsResource#STATE_DELETED}</code>: Read all "deleted" resources in the project</li>
4853     * <li><code>{@link CmsResource#STATE_KEEP}</code>: Read all resources either "changed", "new" or "deleted" in the project</li>
4854     * </ul><p>
4855     *
4856     * @param context the current request context
4857     * @param projectId the id of the project to read the file resources for
4858     * @param state the resource state to match
4859     *
4860     * @return a list of <code>{@link CmsResource}</code> objects matching the filter criteria
4861     *
4862     * @throws CmsException if something goes wrong
4863     *
4864     * @see CmsObject#readProjectView(CmsUUID, CmsResourceState)
4865     */
4866    public List<CmsResource> readProjectView(CmsRequestContext context, CmsUUID projectId, CmsResourceState state)
4867    throws CmsException {
4868
4869        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4870        List<CmsResource> result = null;
4871        try {
4872            result = m_driverManager.readProjectView(dbc, projectId, state);
4873        } catch (Exception e) {
4874            dbc.report(null, Messages.get().container(Messages.ERR_READ_PROJECT_VIEW_1, projectId), e);
4875        } finally {
4876            dbc.clear();
4877        }
4878        return result;
4879    }
4880
4881    /**
4882     * Reads a property definition.<p>
4883     *
4884     * If no property definition with the given name is found,
4885     * <code>null</code> is returned.<p>
4886     *
4887     * @param context the current request context
4888     * @param name the name of the property definition to read
4889     *
4890     * @return the property definition that was read
4891     *
4892     * @throws CmsException a CmsDbEntryNotFoundException is thrown if the property definition does not exist
4893     */
4894    public CmsPropertyDefinition readPropertyDefinition(CmsRequestContext context, String name) throws CmsException {
4895
4896        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4897        CmsPropertyDefinition result = null;
4898        try {
4899            result = m_driverManager.readPropertyDefinition(dbc, name);
4900        } catch (Exception e) {
4901            dbc.report(null, Messages.get().container(Messages.ERR_READ_PROPDEF_1, name), e);
4902        } finally {
4903            dbc.clear();
4904        }
4905        return result;
4906    }
4907
4908    /**
4909     * Reads a property object from a resource specified by a property name.<p>
4910     *
4911     * Returns <code>{@link CmsProperty#getNullProperty()}</code> if the property is not found.<p>
4912     *
4913     * @param context the context of the current request
4914     * @param resource the resource where the property is mapped to
4915     * @param key the property key name
4916     * @param search if <code>true</code>, the property is searched on all parent folders of the resource.
4917     *      if it's not found attached directly to the resource.
4918     *
4919     * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found
4920     *
4921     * @throws CmsException if something goes wrong
4922     */
4923    public CmsProperty readPropertyObject(CmsRequestContext context, CmsResource resource, String key, boolean search)
4924    throws CmsException {
4925
4926        return readPropertyObject(context, resource, key, search, null);
4927    }
4928
4929    /**
4930     * Reads a property object from a resource specified by a property name.<p>
4931     *
4932     * Returns <code>{@link CmsProperty#getNullProperty()}</code> if the property is not found.<p>
4933     *
4934     * @param context the context of the current request
4935     * @param resource the resource where the property is mapped to
4936     * @param key the property key name
4937     * @param search if <code>true</code>, the property is searched on all parent folders of the resource.
4938     *      if it's not found attached directly to the resource.
4939     * @param locale the locale for which the property should be read.
4940     *
4941     * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found
4942     *
4943     * @throws CmsException if something goes wrong
4944     */
4945    public CmsProperty readPropertyObject(
4946        CmsRequestContext context,
4947        CmsResource resource,
4948        String key,
4949        boolean search,
4950        Locale locale)
4951    throws CmsException {
4952
4953        CmsProperty result = null;
4954        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4955        try {
4956            if (null == locale) {
4957                result = m_driverManager.readPropertyObject(dbc, resource, key, search);
4958            } else {
4959                result = m_driverManager.readPropertyObject(dbc, resource, key, search, locale);
4960            }
4961        } catch (Exception e) {
4962            dbc.report(
4963                null,
4964                Messages.get().container(Messages.ERR_READ_PROP_FOR_RESOURCE_2, key, context.getSitePath(resource)),
4965                e);
4966        } finally {
4967            dbc.clear();
4968        }
4969        return result;
4970    }
4971
4972    /**
4973     * Reads all property objects from a resource.<p>
4974     *
4975     * Returns an empty list if no properties are found.<p>
4976     *
4977     * If the <code>search</code> parameter is <code>true</code>, the properties of all
4978     * parent folders of the resource are also read. The results are merged with the
4979     * properties directly attached to the resource. While merging, a property
4980     * on a parent folder that has already been found will be ignored.
4981     * So e.g. if a resource has a property "Title" attached, and it's parent folder
4982     * has the same property attached but with a different value, the result list will
4983     * contain only the property with the value from the resource, not form the parent folder(s).<p>
4984     *
4985     * @param context the context of the current request
4986     * @param resource the resource where the property is mapped to
4987     * @param search <code>true</code>, if the properties should be searched on all parent folders  if not found on the resource
4988     *
4989     * @return a list of <code>{@link CmsProperty}</code> objects
4990     *
4991     * @throws CmsException if something goes wrong
4992     */
4993    public List<CmsProperty> readPropertyObjects(CmsRequestContext context, CmsResource resource, boolean search)
4994    throws CmsException {
4995
4996        List<CmsProperty> result = null;
4997        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
4998        try {
4999            result = m_driverManager.readPropertyObjects(dbc, resource, search);
5000        } catch (Exception e) {
5001            dbc.report(
5002                null,
5003                Messages.get().container(Messages.ERR_READ_PROPS_FOR_RESOURCE_1, context.getSitePath(resource)),
5004                e);
5005        } finally {
5006            dbc.clear();
5007        }
5008        return result;
5009    }
5010
5011    /**
5012     * Reads the resources that were published in a publish task for a given publish history ID.<p>
5013     *
5014     * @param context the current request context
5015     * @param publishHistoryId unique ID to identify each publish task in the publish history
5016     *
5017     * @return a list of <code>{@link org.opencms.db.CmsPublishedResource}</code> objects
5018     *
5019     * @throws CmsException if something goes wrong
5020     */
5021    public List<CmsPublishedResource> readPublishedResources(CmsRequestContext context, CmsUUID publishHistoryId)
5022    throws CmsException {
5023
5024        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5025        List<CmsPublishedResource> result = null;
5026        try {
5027            result = m_driverManager.readPublishedResources(dbc, publishHistoryId);
5028        } catch (Exception e) {
5029            dbc.report(
5030                null,
5031                Messages.get().container(Messages.ERR_READ_PUBLISHED_RESOURCES_FOR_ID_1, publishHistoryId.toString()),
5032                e);
5033        } finally {
5034            dbc.clear();
5035        }
5036        return result;
5037    }
5038
5039    /**
5040     * Reads the historical resource entry for the given resource with the given version number.<p>
5041     *
5042     * @param context the current request context
5043     * @param resource the resource to be read the version for
5044     * @param version the version number to retrieve
5045     *
5046     * @return the resource that was read
5047     *
5048     * @throws CmsException if the resource could not be read for any reason
5049     *
5050     * @see CmsObject#readFile(CmsResource)
5051     * @see CmsObject#restoreResourceVersion(CmsUUID, int)
5052     * @see CmsObject#readResource(CmsUUID, int)
5053     */
5054    public I_CmsHistoryResource readResource(CmsRequestContext context, CmsResource resource, int version)
5055    throws CmsException {
5056
5057        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5058        I_CmsHistoryResource result = null;
5059        try {
5060            result = m_driverManager.readResource(dbc, resource, version);
5061        } catch (CmsException e) {
5062            dbc.report(
5063                null,
5064                Messages.get().container(
5065                    Messages.ERR_READING_RESOURCE_VERSION_2,
5066                    dbc.removeSiteRoot(resource.getRootPath()),
5067                    new Integer(version)),
5068                e);
5069        } finally {
5070            dbc.clear();
5071        }
5072        return result;
5073    }
5074
5075    /**
5076     * Reads a resource from the VFS,
5077     * using the specified resource filter.<p>
5078     *
5079     * A resource may be of type <code>{@link CmsFile}</code> or
5080     * <code>{@link CmsFolder}</code>. In case of
5081     * a file, the resource will not contain the binary file content. Since reading
5082     * the binary content is a cost-expensive database operation, it's recommended
5083     * to work with resources if possible, and only read the file content when absolutely
5084     * required. To "upgrade" a resource to a file,
5085     * use <code>{@link CmsObject#readFile(CmsResource)}</code>.<p>
5086     *
5087     * The specified filter controls what kind of resources should be "found"
5088     * during the read operation. This will depend on the application. For example,
5089     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
5090     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
5091     * will ignore the date release / date expired information of the resource.<p>
5092     *
5093     * @param context the current request context
5094     * @param structureID the ID of the structure which will be used)
5095     * @param filter the resource filter to use while reading
5096     *
5097     * @return the resource that was read
5098     *
5099     * @throws CmsException if the resource could not be read for any reason
5100     *
5101     * @see CmsObject#readResource(CmsUUID, CmsResourceFilter)
5102     * @see CmsObject#readResource(CmsUUID)
5103     * @see CmsObject#readFile(CmsResource)
5104     */
5105    public CmsResource readResource(CmsRequestContext context, CmsUUID structureID, CmsResourceFilter filter)
5106    throws CmsException {
5107
5108        CmsResource result = null;
5109        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5110        try {
5111            result = readResource(dbc, structureID, filter);
5112        } catch (Exception e) {
5113            dbc.report(null, Messages.get().container(Messages.ERR_READ_RESOURCE_FOR_ID_1, structureID), e);
5114        } finally {
5115            dbc.clear();
5116        }
5117        return result;
5118    }
5119
5120    /**
5121     * Reads a resource from the VFS,
5122     * using the specified resource filter.<p>
5123     *
5124     * A resource may be of type <code>{@link CmsFile}</code> or
5125     * <code>{@link CmsFolder}</code>. In case of
5126     * a file, the resource will not contain the binary file content. Since reading
5127     * the binary content is a cost-expensive database operation, it's recommended
5128     * to work with resources if possible, and only read the file content when absolutely
5129     * required. To "upgrade" a resource to a file,
5130     * use <code>{@link CmsObject#readFile(CmsResource)}</code>.<p>
5131     *
5132     * The specified filter controls what kind of resources should be "found"
5133     * during the read operation. This will depend on the application. For example,
5134     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
5135     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
5136     * will ignore the date release / date expired information of the resource.<p>
5137     *
5138     * @param context the current request context
5139     * @param resourcePath the name of the resource to read (full path)
5140     * @param filter the resource filter to use while reading
5141     *
5142     * @return the resource that was read
5143     *
5144     * @throws CmsException if the resource could not be read for any reason
5145     *
5146     * @see CmsObject#readResource(String, CmsResourceFilter)
5147     * @see CmsObject#readResource(String)
5148     * @see CmsObject#readFile(CmsResource)
5149     */
5150    public CmsResource readResource(CmsRequestContext context, String resourcePath, CmsResourceFilter filter)
5151    throws CmsException {
5152
5153        CmsResource result = null;
5154        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5155        try {
5156            result = readResource(dbc, resourcePath, filter);
5157        } catch (Exception e) {
5158            dbc.report(
5159                null,
5160                Messages.get().container(Messages.ERR_READ_RESOURCE_1, dbc.removeSiteRoot(resourcePath)),
5161                e);
5162        } finally {
5163            dbc.clear();
5164        }
5165        return result;
5166    }
5167
5168    /**
5169     * Reads all resources below the given path matching the filter criteria,
5170     * including the full tree below the path only in case the <code>readTree</code>
5171     * parameter is <code>true</code>.<p>
5172     *
5173     * @param context the current request context
5174     * @param parent the parent path to read the resources from
5175     * @param filter the filter
5176     * @param readTree <code>true</code> to read all subresources
5177     *
5178     * @return a list of <code>{@link CmsResource}</code> objects matching the filter criteria
5179     *
5180     * @throws CmsSecurityException if the user has insufficient permission for the given resource (read is required)
5181     * @throws CmsException if something goes wrong
5182     *
5183     */
5184    public List<CmsResource> readResources(
5185        CmsRequestContext context,
5186        CmsResource parent,
5187        CmsResourceFilter filter,
5188        boolean readTree)
5189    throws CmsException, CmsSecurityException {
5190
5191        List<CmsResource> result = null;
5192        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5193        try {
5194            // check the access permissions
5195            checkPermissions(dbc, parent, CmsPermissionSet.ACCESS_READ, true, CmsResourceFilter.ALL);
5196            result = m_driverManager.readResources(dbc, parent, filter, readTree);
5197        } catch (Exception e) {
5198            dbc.report(
5199                null,
5200                Messages.get().container(Messages.ERR_READ_RESOURCES_1, context.removeSiteRoot(parent.getRootPath())),
5201                e);
5202        } finally {
5203            dbc.clear();
5204        }
5205        return result;
5206    }
5207
5208    /**
5209     * Returns the resources that were visited by a user set in the filter.<p>
5210     *
5211     * @param context the request context
5212     * @param poolName the name of the database pool to use
5213     * @param filter the filter that is used to get the visited resources
5214     *
5215     * @return the resources that were visited by a user set in the filter
5216     *
5217     * @throws CmsException if something goes wrong
5218     */
5219    public List<CmsResource> readResourcesVisitedBy(
5220        CmsRequestContext context,
5221        String poolName,
5222        CmsVisitedByFilter filter)
5223    throws CmsException {
5224
5225        List<CmsResource> result = null;
5226        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5227        try {
5228            result = m_driverManager.readResourcesVisitedBy(dbc, poolName, filter);
5229        } catch (Exception e) {
5230            dbc.report(null, Messages.get().container(Messages.ERR_READ_VISITED_RESOURCES_1, filter.toString()), e);
5231        } finally {
5232            dbc.clear();
5233        }
5234        return result;
5235    }
5236
5237    /**
5238     * Reads all resources that have a value (containing the specified value) set
5239     * for the specified property (definition) in the given path.<p>
5240     *
5241     * If the <code>value</code> parameter is <code>null</code>, all resources having the
5242     * given property set are returned.<p>
5243     *
5244     * Both individual and shared properties of a resource are checked.<p>
5245     *
5246     * @param context the current request context
5247     * @param folder the folder to get the resources with the property from
5248     * @param propertyDefinition the name of the property (definition) to check for
5249     * @param value the string to search in the value of the property
5250     * @param filter the resource filter to apply to the result set
5251     *
5252     * @return a list of all <code>{@link CmsResource}</code> objects
5253     *          that have a value set for the specified property.
5254     *
5255     * @throws CmsException if something goes wrong
5256     */
5257    public List<CmsResource> readResourcesWithProperty(
5258        CmsRequestContext context,
5259        CmsResource folder,
5260        String propertyDefinition,
5261        String value,
5262        CmsResourceFilter filter)
5263    throws CmsException {
5264
5265        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5266        List<CmsResource> result = null;
5267        try {
5268            result = m_driverManager.readResourcesWithProperty(dbc, folder, propertyDefinition, value, filter);
5269        } catch (Exception e) {
5270            dbc.report(
5271                null,
5272                Messages.get().container(
5273                    Messages.ERR_READ_RESOURCES_FOR_PROP_VALUE_3,
5274                    context.removeSiteRoot(folder.getRootPath()),
5275                    propertyDefinition,
5276                    value),
5277                e);
5278        } finally {
5279            dbc.clear();
5280        }
5281        return result;
5282    }
5283
5284    /**
5285     * Returns a set of users that are responsible for a specific resource.<p>
5286     *
5287     * @param context the current request context
5288     * @param resource the resource to get the responsible users from
5289     *
5290     * @return the set of users that are responsible for a specific resource
5291     *
5292     * @throws CmsException if something goes wrong
5293     */
5294    public Set<I_CmsPrincipal> readResponsiblePrincipals(CmsRequestContext context, CmsResource resource)
5295    throws CmsException {
5296
5297        Set<I_CmsPrincipal> result = null;
5298        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5299        try {
5300            result = m_driverManager.readResponsiblePrincipals(dbc, resource);
5301        } catch (Exception e) {
5302            dbc.report(
5303                null,
5304                Messages.get().container(Messages.ERR_READ_RESPONSIBLE_USERS_1, resource.getRootPath()),
5305                e);
5306        } finally {
5307            dbc.clear();
5308        }
5309        return result;
5310    }
5311
5312    /**
5313     * Returns a set of users that are responsible for a specific resource.<p>
5314     *
5315     * @param context the current request context
5316     * @param resource the resource to get the responsible users from
5317     *
5318     * @return the set of users that are responsible for a specific resource
5319     *
5320     * @throws CmsException if something goes wrong
5321     */
5322    public Set<CmsUser> readResponsibleUsers(CmsRequestContext context, CmsResource resource) throws CmsException {
5323
5324        Set<CmsUser> result = null;
5325        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5326        try {
5327            result = m_driverManager.readResponsibleUsers(dbc, resource);
5328        } catch (Exception e) {
5329            dbc.report(
5330                null,
5331                Messages.get().container(Messages.ERR_READ_RESPONSIBLE_USERS_1, resource.getRootPath()),
5332                e);
5333        } finally {
5334            dbc.clear();
5335        }
5336        return result;
5337    }
5338
5339    /**
5340     * Returns a List of all siblings of the specified resource,
5341     * the specified resource being always part of the result set.<p>
5342     *
5343     * @param context the request context
5344     * @param resource the specified resource
5345     * @param filter a filter object
5346     *
5347     * @return a list of <code>{@link CmsResource}</code>s that
5348     *          are siblings to the specified resource,
5349     *          including the specified resource itself
5350     *
5351     * @throws CmsException if something goes wrong
5352     */
5353    public List<CmsResource> readSiblings(CmsRequestContext context, CmsResource resource, CmsResourceFilter filter)
5354    throws CmsException {
5355
5356        List<CmsResource> result = null;
5357        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5358        try {
5359            result = m_driverManager.readSiblings(dbc, resource, filter);
5360        } catch (Exception e) {
5361            dbc.report(null, Messages.get().container(Messages.ERR_READ_SIBLINGS_1, context.getSitePath(resource)), e);
5362        } finally {
5363            dbc.clear();
5364        }
5365        return result;
5366    }
5367
5368    /**
5369     * Returns the parameters of a resource in the table of all published template resources.<p>
5370     *
5371     * @param context the current request context
5372     * @param rfsName the rfs name of the resource
5373     *
5374     * @return the parameter string of the requested resource
5375     *
5376     * @throws CmsException if something goes wrong
5377     */
5378    public String readStaticExportPublishedResourceParameters(CmsRequestContext context, String rfsName)
5379    throws CmsException {
5380
5381        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5382        String result = null;
5383        try {
5384            result = m_driverManager.readStaticExportPublishedResourceParameters(dbc, rfsName);
5385        } catch (Exception e) {
5386            dbc.report(
5387                null,
5388                Messages.get().container(Messages.ERR_READ_STATEXP_PUBLISHED_RESOURCE_PARAMS_1, rfsName),
5389                e);
5390        } finally {
5391            dbc.clear();
5392        }
5393        return result;
5394    }
5395
5396    /**
5397     * Returns a list of all template resources which must be processed during a static export.<p>
5398     *
5399     * @param context the current request context
5400     * @param parameterResources flag for reading resources with parameters (1) or without (0)
5401     * @param timestamp for reading the data from the db
5402     *
5403     * @return a list of template resources as <code>{@link String}</code> objects
5404     *
5405     * @throws CmsException if something goes wrong
5406     */
5407    public List<String> readStaticExportResources(CmsRequestContext context, int parameterResources, long timestamp)
5408    throws CmsException {
5409
5410        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5411        List<String> result = null;
5412        try {
5413            result = m_driverManager.readStaticExportResources(dbc, parameterResources, timestamp);
5414        } catch (Exception e) {
5415            dbc.report(null, Messages.get().container(Messages.ERR_READ_STATEXP_RESOURCES_1, new Date(timestamp)), e);
5416        } finally {
5417            dbc.clear();
5418        }
5419        return result;
5420    }
5421
5422    /**
5423     * Returns the subscribed history resources that were deleted.<p>
5424     *
5425     * @param context the request context
5426     * @param poolName the name of the database pool to use
5427     * @param user the user that subscribed to the resource
5428     * @param groups the groups to check subscribed resources for
5429     * @param parent the parent resource (folder) of the deleted resources, if <code>null</code> all deleted resources will be returned
5430     * @param includeSubFolders indicates if the sub folders of the specified folder path should be considered, too
5431     * @param deletedFrom the time stamp from which the resources should have been deleted
5432     *
5433     * @return the subscribed history resources that were deleted
5434     *
5435     * @throws CmsException if something goes wrong
5436     */
5437    public List<I_CmsHistoryResource> readSubscribedDeletedResources(
5438        CmsRequestContext context,
5439        String poolName,
5440        CmsUser user,
5441        List<CmsGroup> groups,
5442        CmsResource parent,
5443        boolean includeSubFolders,
5444        long deletedFrom)
5445    throws CmsException {
5446
5447        List<I_CmsHistoryResource> result = null;
5448        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5449        try {
5450            result = m_driverManager.readSubscribedDeletedResources(
5451                dbc,
5452                poolName,
5453                user,
5454                groups,
5455                parent,
5456                includeSubFolders,
5457                deletedFrom);
5458        } catch (Exception e) {
5459            dbc.report(
5460                null,
5461                Messages.get().container(Messages.ERR_READ_SUBSCRIBED_DELETED_RESOURCES_1, user.getName()),
5462                e);
5463        } finally {
5464            dbc.clear();
5465        }
5466        return result;
5467    }
5468
5469    /**
5470     * Returns the resources that were subscribed by a user or group set in the filter.<p>
5471     *
5472     * @param context the request context
5473     * @param poolName the name of the database pool to use
5474     * @param filter the filter that is used to get the subscribed resources
5475     *
5476     * @return the resources that were subscribed by a user or group set in the filter
5477     *
5478     * @throws CmsException if something goes wrong
5479     */
5480    public List<CmsResource> readSubscribedResources(
5481        CmsRequestContext context,
5482        String poolName,
5483        CmsSubscriptionFilter filter)
5484    throws CmsException {
5485
5486        List<CmsResource> result = null;
5487        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5488        try {
5489            result = m_driverManager.readSubscribedResources(dbc, poolName, filter);
5490        } catch (Exception e) {
5491            dbc.report(null, Messages.get().container(Messages.ERR_READ_SUBSCRIBED_RESOURCES_1, filter.toString()), e);
5492        } finally {
5493            dbc.clear();
5494        }
5495        return result;
5496    }
5497
5498    /**
5499     * Reads the URL name mappings matching a given filter.<p>
5500     *
5501     * @param context the current request context
5502     * @param filter the filter to match
5503     *
5504     * @return the matching URL name mappings
5505     *
5506     * @throws CmsException if something goes wrong
5507     */
5508    public List<CmsUrlNameMappingEntry> readUrlNameMappings(CmsRequestContext context, CmsUrlNameMappingFilter filter)
5509    throws CmsException {
5510
5511        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5512        try {
5513            return m_driverManager.readUrlNameMappings(dbc, filter);
5514        } catch (Exception e) {
5515            CmsMessageContainer message = Messages.get().container(
5516                Messages.ERR_DB_OPERATION_1,
5517                e.getLocalizedMessage());
5518            dbc.report(null, message, e);
5519            return null; // will never be reached
5520        } finally {
5521            dbc.clear();
5522        }
5523    }
5524
5525    /**
5526     * Reads the newest URL names of a structure id for all locales.<p>
5527     *
5528     * @param context the current context
5529     * @param id a structure id
5530     *
5531     * @return the list of URL names for all
5532     * @throws CmsException if something goes wrong
5533     */
5534    public List<String> readUrlNamesForAllLocales(CmsRequestContext context, CmsUUID id) throws CmsException {
5535
5536        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5537        try {
5538            return m_driverManager.readUrlNamesForAllLocales(dbc, id);
5539        } catch (Exception e) {
5540            CmsMessageContainer message = Messages.get().container(
5541                Messages.ERR_READ_NEWEST_URLNAME_FOR_ID_1,
5542                id.toString());
5543            dbc.report(null, message, e);
5544            return null; // will never be reached
5545        } finally {
5546            dbc.clear();
5547        }
5548    }
5549
5550    /**
5551     * Returns a user object based on the id of a user.<p>
5552     *
5553     * @param context the current request context
5554     * @param id the id of the user to read
5555     *
5556     * @return the user read
5557     *
5558     * @throws CmsException if something goes wrong
5559     */
5560    public CmsUser readUser(CmsRequestContext context, CmsUUID id) throws CmsException {
5561
5562        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5563        CmsUser result = null;
5564        try {
5565            result = m_driverManager.readUser(dbc, id);
5566        } catch (Exception e) {
5567            dbc.report(null, Messages.get().container(Messages.ERR_READ_USER_FOR_ID_1, id.toString()), e);
5568        } finally {
5569            dbc.clear();
5570        }
5571        return result;
5572    }
5573
5574    /**
5575     * Returns a user object.<p>
5576     *
5577     * @param context the current request context
5578     * @param username the name of the user that is to be read
5579     *
5580     * @return user read form the cms
5581     *
5582     * @throws CmsException if operation was not successful
5583     */
5584    public CmsUser readUser(CmsRequestContext context, String username) throws CmsException {
5585
5586        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5587        CmsUser result = null;
5588        try {
5589            result = m_driverManager.readUser(dbc, CmsOrganizationalUnit.removeLeadingSeparator(username));
5590        } catch (Exception e) {
5591            dbc.report(null, Messages.get().container(Messages.ERR_READ_USER_FOR_NAME_1, username), e);
5592        } finally {
5593            dbc.clear();
5594        }
5595        return result;
5596    }
5597
5598    /**
5599     * Returns a user object if the password for the user is correct.<p>
5600     *
5601     * If the user/password pair is not valid a <code>{@link CmsException}</code> is thrown.<p>
5602     *
5603     * @param context the current request context
5604     * @param username the user name of the user that is to be read
5605     * @param password the password of the user that is to be read
5606     *
5607     * @return user read
5608     *
5609     * @throws CmsException if operation was not successful
5610     */
5611    public CmsUser readUser(CmsRequestContext context, String username, String password) throws CmsException {
5612
5613        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5614        CmsUser result = null;
5615        try {
5616            result = m_driverManager.readUser(dbc, CmsOrganizationalUnit.removeLeadingSeparator(username), password);
5617        } catch (Exception e) {
5618            dbc.report(null, Messages.get().container(Messages.ERR_READ_USER_FOR_NAME_1, username), e);
5619        } finally {
5620            dbc.clear();
5621        }
5622        return result;
5623    }
5624
5625    /**
5626     * Removes an access control entry for a given resource and principal.<p>
5627     *
5628     * @param context the current request context
5629     * @param resource the resource
5630     * @param principal the id of the principal to remove the the access control entry for
5631     *
5632     * @throws CmsException if something goes wrong
5633     * @throws CmsSecurityException if the user has insufficient permission for the given resource (control of access control is required).
5634     *
5635     */
5636    public void removeAccessControlEntry(CmsRequestContext context, CmsResource resource, CmsUUID principal)
5637    throws CmsException, CmsSecurityException {
5638
5639        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5640        try {
5641            checkOfflineProject(dbc);
5642            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_CONTROL, true, CmsResourceFilter.ALL);
5643            m_driverManager.removeAccessControlEntry(dbc, resource, principal);
5644        } catch (Exception e) {
5645            dbc.report(
5646                null,
5647                Messages.get().container(
5648                    Messages.ERR_REMOVE_ACL_ENTRY_2,
5649                    context.getSitePath(resource),
5650                    principal.toString()),
5651                e);
5652        } finally {
5653            dbc.clear();
5654        }
5655    }
5656
5657    /**
5658     * Removes a resource from the given organizational unit.<p>
5659     *
5660     * @param context the current request context
5661     * @param orgUnit the organizational unit to remove the resource from
5662     * @param resource the resource that is to be removed from the organizational unit
5663     *
5664     * @throws CmsException if something goes wrong
5665     *
5666     * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String)
5667     * @see org.opencms.security.CmsOrgUnitManager#addResourceToOrgUnit(CmsObject, String, String)
5668     */
5669    public void removeResourceFromOrgUnit(
5670        CmsRequestContext context,
5671        CmsOrganizationalUnit orgUnit,
5672        CmsResource resource)
5673    throws CmsException {
5674
5675        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5676        try {
5677            checkRole(dbc, CmsRole.ADMINISTRATOR.forOrgUnit(orgUnit.getName()));
5678            checkOfflineProject(dbc);
5679            m_driverManager.removeResourceFromOrgUnit(dbc, orgUnit, resource);
5680        } catch (Exception e) {
5681            dbc.report(
5682                null,
5683                Messages.get().container(
5684                    Messages.ERR_REMOVE_RESOURCE_FROM_ORGUNIT_2,
5685                    orgUnit.getName(),
5686                    dbc.removeSiteRoot(resource.getRootPath())),
5687                e);
5688        } finally {
5689            dbc.clear();
5690        }
5691    }
5692
5693    /**
5694     * Removes a resource from the current project of the user.<p>
5695     *
5696     * @param context the current request context
5697     * @param resource the resource to apply this operation to
5698     *
5699     * @throws CmsException if something goes wrong
5700     * @throws CmsRoleViolationException if the current user does not have management access to the project
5701     *
5702     * @see org.opencms.file.types.I_CmsResourceType#copyResourceToProject(CmsObject, CmsSecurityManager, CmsResource)
5703     */
5704    public void removeResourceFromProject(CmsRequestContext context, CmsResource resource)
5705    throws CmsException, CmsRoleViolationException {
5706
5707        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5708        try {
5709            checkOfflineProject(dbc);
5710            checkManagerOfProjectRole(dbc, context.getCurrentProject());
5711
5712            m_driverManager.removeResourceFromProject(dbc, resource);
5713        } catch (Exception e) {
5714            dbc.report(
5715                null,
5716                Messages.get().container(
5717                    Messages.ERR_COPY_RESOURCE_TO_PROJECT_2,
5718                    context.getSitePath(resource),
5719                    context.getCurrentProject().getName()),
5720                e);
5721        } finally {
5722            dbc.clear();
5723        }
5724    }
5725
5726    /**
5727     * Removes the given resource to the given user's publish list.<p>
5728     *
5729     * @param context the request context
5730     * @param structureIds the collection of structure IDs to remove
5731     *
5732     * @throws CmsException if something goes wrong
5733     */
5734    public void removeResourceFromUsersPubList(CmsRequestContext context, Collection<CmsUUID> structureIds)
5735    throws CmsException {
5736
5737        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5738        try {
5739            m_driverManager.removeResourceFromUsersPubList(dbc, context.getCurrentUser().getId(), structureIds);
5740        } catch (Exception e) {
5741            dbc.report(
5742                null,
5743                Messages.get().container(
5744                    Messages.ERR_REMOVE_RESOURCE_FROM_PUBLIST_2,
5745                    context.getCurrentUser().getName(),
5746                    structureIds),
5747                e);
5748
5749        } finally {
5750            dbc.clear();
5751        }
5752    }
5753
5754    /**
5755     * Removes a user from a group.<p>
5756     *
5757     * @param context the current request context
5758     * @param username the name of the user that is to be removed from the group
5759     * @param groupname the name of the group
5760     * @param readRoles if to read roles or groups
5761     *
5762     * @throws CmsException if operation was not successful
5763     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
5764     *
5765     */
5766    public void removeUserFromGroup(CmsRequestContext context, String username, String groupname, boolean readRoles)
5767    throws CmsException, CmsRoleViolationException {
5768
5769        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5770        try {
5771            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(groupname));
5772            checkRoleForUserModification(dbc, username, role);
5773            m_driverManager.removeUserFromGroup(
5774                dbc,
5775                CmsOrganizationalUnit.removeLeadingSeparator(username),
5776                CmsOrganizationalUnit.removeLeadingSeparator(groupname),
5777                readRoles);
5778        } catch (Exception e) {
5779            dbc.report(null, Messages.get().container(Messages.ERR_REMOVE_USER_FROM_GROUP_2, username, groupname), e);
5780        } finally {
5781            dbc.clear();
5782        }
5783    }
5784
5785    /**
5786     * Replaces the content, type and properties of a resource.<p>
5787     *
5788     * @param context the current request context
5789     * @param resource the name of the resource to apply this operation to
5790     * @param type the new type of the resource
5791     * @param content the new content of the resource
5792     * @param properties the new properties of the resource
5793     *
5794     * @throws CmsException if something goes wrong
5795     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
5796     *
5797     * @see CmsObject#replaceResource(String, int, byte[], List)
5798     * @see org.opencms.file.types.I_CmsResourceType#replaceResource(CmsObject, CmsSecurityManager, CmsResource, int, byte[], List)
5799     */
5800    @SuppressWarnings("javadoc")
5801    public void replaceResource(
5802        CmsRequestContext context,
5803        CmsResource resource,
5804        int type,
5805        byte[] content,
5806        List<CmsProperty> properties)
5807    throws CmsException, CmsSecurityException {
5808
5809        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5810        try {
5811            checkOfflineProject(dbc);
5812            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
5813            if (CmsResourceTypeJsp.isJspTypeId(type)) {
5814                // security check preventing the creation of a jsp file without permissions
5815                checkRoleForResource(dbc, CmsRole.VFS_MANAGER, resource);
5816            }
5817            m_driverManager.replaceResource(dbc, resource, type, content, properties);
5818        } catch (Exception e) {
5819            dbc.report(
5820                null,
5821                Messages.get().container(Messages.ERR_REPLACE_RESOURCE_1, context.getSitePath(resource)),
5822                e);
5823        } finally {
5824            dbc.clear();
5825        }
5826    }
5827
5828    /**
5829     * Resets the password for a specified user.<p>
5830     *
5831     * @param context the current request context
5832     * @param username the name of the user
5833     * @param oldPassword the old password
5834     * @param newPassword the new password
5835     *
5836     * @throws CmsException if the user data could not be read from the database
5837     * @throws CmsSecurityException if the specified user name and old password could not be verified
5838     */
5839    public void resetPassword(CmsRequestContext context, String username, String oldPassword, String newPassword)
5840    throws CmsException, CmsSecurityException {
5841
5842        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5843        try {
5844            m_driverManager.resetPassword(
5845                dbc,
5846                CmsOrganizationalUnit.removeLeadingSeparator(username),
5847                oldPassword,
5848                newPassword);
5849        } catch (Exception e) {
5850            dbc.report(null, Messages.get().container(Messages.ERR_RESET_PASSWORD_1, username), e);
5851        } finally {
5852            dbc.clear();
5853        }
5854    }
5855
5856    /**
5857     * Returns the original path of given resource, that is the online path for the resource.<p>
5858     *
5859     * If it differs from the offline path, the resource has been moved.<p>
5860     *
5861     * @param context the current request context
5862     * @param resource the resource to get the path for
5863     *
5864     * @return the online path
5865     *
5866     * @throws CmsException if something goes wrong
5867     *
5868     * @see org.opencms.workplace.commons.CmsUndoChanges#resourceOriginalPath(CmsObject, String)
5869     */
5870    public String resourceOriginalPath(CmsRequestContext context, CmsResource resource) throws CmsException {
5871
5872        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5873        String result = null;
5874        try {
5875            checkOfflineProject(dbc);
5876            result = m_driverManager.getVfsDriver(
5877                dbc).readResource(dbc, CmsProject.ONLINE_PROJECT_ID, resource.getStructureId(), true).getRootPath();
5878        } catch (Exception e) {
5879            dbc.report(
5880                null,
5881                Messages.get().container(
5882                    Messages.ERR_TEST_MOVED_RESOURCE_1,
5883                    dbc.removeSiteRoot(resource.getRootPath())),
5884                e);
5885        } finally {
5886            dbc.clear();
5887        }
5888        return result;
5889    }
5890
5891    /**
5892     * Restores a deleted resource identified by its structure id from the historical archive.<p>
5893     *
5894     * @param context the current request context
5895     * @param structureId the structure id of the resource to restore
5896     *
5897     * @throws CmsException if something goes wrong
5898     *
5899     * @see CmsObject#restoreDeletedResource(CmsUUID)
5900     */
5901    public void restoreDeletedResource(CmsRequestContext context, CmsUUID structureId) throws CmsException {
5902
5903        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5904        try {
5905            checkOfflineProject(dbc);
5906            // write permissions on parent folder are checked later
5907            m_driverManager.restoreDeletedResource(dbc, structureId);
5908        } catch (Exception e) {
5909            dbc.report(null, Messages.get().container(Messages.ERR_RESTORE_DELETED_RESOURCE_1, structureId), e);
5910        } finally {
5911            dbc.clear();
5912        }
5913    }
5914
5915    /**
5916     * Restores a resource in the current project with the given version from the historical archive.<p>
5917     *
5918     * @param context the current request context
5919     * @param resource the resource to restore from the archive
5920     * @param version the version number to restore
5921     *
5922     * @throws CmsException if something goes wrong
5923     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
5924     *
5925     * @see CmsObject#restoreResourceVersion(CmsUUID, int)
5926     * @see org.opencms.file.types.I_CmsResourceType#restoreResource(CmsObject, CmsSecurityManager, CmsResource, int)
5927     */
5928    public void restoreResource(CmsRequestContext context, CmsResource resource, int version)
5929    throws CmsException, CmsSecurityException {
5930
5931        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5932        try {
5933            checkOfflineProject(dbc);
5934            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
5935            m_driverManager.restoreResource(dbc, resource, version);
5936        } catch (Exception e) {
5937            dbc.report(
5938                null,
5939                Messages.get().container(
5940                    Messages.ERR_RESTORE_RESOURCE_2,
5941                    context.getSitePath(resource),
5942                    new Integer(version)),
5943                e);
5944        } finally {
5945            dbc.clear();
5946        }
5947    }
5948
5949    /**
5950     * Saves the aliases for a given resource.<p>
5951     *
5952     * This method completely replaces any existing aliases for the same structure id.
5953     *
5954     * @param context the request context
5955     * @param resource the resource for which the aliases should be written
5956     * @param aliases the list of aliases to write, where all aliases must have the same structure id as the resource
5957     *
5958     * @throws CmsException if something goes wrong
5959     */
5960    public void saveAliases(CmsRequestContext context, CmsResource resource, List<CmsAlias> aliases)
5961    throws CmsException {
5962
5963        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
5964        try {
5965            if ((aliases.size() > 0) && !(resource.getStructureId().equals(aliases.get(0).getStructureId()))) {
5966                throw new IllegalArgumentException("Resource does not match aliases!");
5967            }
5968            checkPermissions(context, resource, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL);
5969            m_driverManager.saveAliases(dbc, context.getCurrentProject(), resource.getStructureId(), aliases);
5970            Map<String, Object> eventData = new HashMap<String, Object>();
5971            eventData.put(I_CmsEventListener.KEY_RESOURCE, resource);
5972            eventData.put(I_CmsEventListener.KEY_CHANGE, new Integer(CmsDriverManager.CHANGED_RESOURCE));
5973            OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, eventData));
5974        } catch (Exception e) {
5975            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
5976        } finally {
5977            dbc.clear();
5978        }
5979    }
5980
5981    /**
5982     * Replaces the rewrite aliases for a given site root.<p>
5983     *
5984     * @param requestContext the current request context
5985     * @param siteRoot the site root for which the rewrite aliases should be replaced
5986     * @param newAliases the new list of aliases for the given site root
5987     *
5988     * @throws CmsException if something goes wrong
5989     */
5990    public void saveRewriteAliases(CmsRequestContext requestContext, String siteRoot, List<CmsRewriteAlias> newAliases)
5991    throws CmsException {
5992
5993        CmsDbContext dbc = m_dbContextFactory.getDbContext(requestContext);
5994        try {
5995            //            checkOfflineProject(dbc);
5996            //            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
5997            m_driverManager.saveRewriteAliases(dbc, siteRoot, newAliases);
5998        } catch (Exception e) {
5999            dbc.report(null, Messages.get().container(Messages.ERR_DB_OPERATION_0), e);
6000        } finally {
6001            dbc.clear();
6002        }
6003    }
6004
6005    /**
6006     * Searches users by search criteria.<p>
6007     *
6008     * @param requestContext the request context
6009     * @param searchParams the search criteria object
6010     *
6011     * @return a list of users
6012     * @throws CmsException if something goes wrong
6013     */
6014    public List<CmsUser> searchUsers(CmsRequestContext requestContext, CmsUserSearchParameters searchParams)
6015    throws CmsException {
6016
6017        CmsDbContext dbc = m_dbContextFactory.getDbContext(requestContext);
6018        try {
6019            return m_driverManager.searchUsers(dbc, searchParams);
6020        } catch (Exception e) {
6021            dbc.report(null, Messages.get().container(Messages.ERR_SEARCH_USERS_0), e);
6022            return null;
6023        } finally {
6024            dbc.clear();
6025        }
6026    }
6027
6028    /**
6029     * Changes the "expire" date of a resource.<p>
6030     *
6031     * @param context the current request context
6032     * @param resource the resource to touch
6033     * @param dateExpired the new expire date of the changed resource
6034     *
6035     * @throws CmsException if something goes wrong
6036     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
6037     *
6038     * @see CmsObject#setDateExpired(String, long, boolean)
6039     * @see org.opencms.file.types.I_CmsResourceType#setDateExpired(CmsObject, CmsSecurityManager, CmsResource, long, boolean)
6040     */
6041    public void setDateExpired(CmsRequestContext context, CmsResource resource, long dateExpired)
6042    throws CmsException, CmsSecurityException {
6043
6044        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6045        try {
6046            checkOfflineProject(dbc);
6047            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.IGNORE_EXPIRATION);
6048            m_driverManager.setDateExpired(dbc, resource, dateExpired);
6049        } catch (Exception e) {
6050            dbc.report(
6051                null,
6052                Messages.get().container(
6053                    Messages.ERR_SET_DATE_EXPIRED_2,
6054                    new Object[] {new Date(dateExpired), context.getSitePath(resource)}),
6055                e);
6056        } finally {
6057            dbc.clear();
6058        }
6059    }
6060
6061    /**
6062     * Changes the "last modified" time stamp of a resource.<p>
6063     *
6064     * @param context the current request context
6065     * @param resource the resource to touch
6066     * @param dateLastModified the new time stamp of the changed resource
6067     *
6068     * @throws CmsException if something goes wrong
6069     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
6070     *
6071     * @see CmsObject#setDateLastModified(String, long, boolean)
6072     * @see org.opencms.file.types.I_CmsResourceType#setDateLastModified(CmsObject, CmsSecurityManager, CmsResource, long, boolean)
6073     */
6074    public void setDateLastModified(CmsRequestContext context, CmsResource resource, long dateLastModified)
6075    throws CmsException, CmsSecurityException {
6076
6077        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6078        try {
6079            checkOfflineProject(dbc);
6080            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.IGNORE_EXPIRATION);
6081            m_driverManager.setDateLastModified(dbc, resource, dateLastModified);
6082        } catch (Exception e) {
6083            dbc.report(
6084                null,
6085                Messages.get().container(
6086                    Messages.ERR_SET_DATE_LAST_MODIFIED_2,
6087                    new Object[] {new Date(dateLastModified), context.getSitePath(resource)}),
6088                e);
6089        } finally {
6090            dbc.clear();
6091        }
6092    }
6093
6094    /**
6095     * Changes the "release" date of a resource.<p>
6096     *
6097     * @param context the current request context
6098     * @param resource the resource to touch
6099     * @param dateReleased the new release date of the changed resource
6100     *
6101     * @throws CmsException if something goes wrong
6102     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
6103     *
6104     * @see CmsObject#setDateReleased(String, long, boolean)
6105     * @see org.opencms.file.types.I_CmsResourceType#setDateReleased(CmsObject, CmsSecurityManager, CmsResource, long, boolean)
6106     */
6107    public void setDateReleased(CmsRequestContext context, CmsResource resource, long dateReleased)
6108    throws CmsException, CmsSecurityException {
6109
6110        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6111        try {
6112            checkOfflineProject(dbc);
6113            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.IGNORE_EXPIRATION);
6114            m_driverManager.setDateReleased(dbc, resource, dateReleased);
6115        } catch (Exception e) {
6116            dbc.report(
6117                null,
6118                Messages.get().container(
6119                    Messages.ERR_SET_DATE_RELEASED_2,
6120                    new Object[] {new Date(dateReleased), context.getSitePath(resource)}),
6121                e);
6122        } finally {
6123            dbc.clear();
6124        }
6125    }
6126
6127    /**
6128     * Sets a new parent-group for an already existing group.<p>
6129     *
6130     * @param context the current request context
6131     * @param groupName the name of the group that should be written
6132     * @param parentGroupName the name of the parent group to set,
6133     *                      or <code>null</code> if the parent
6134     *                      group should be deleted.
6135     *
6136     * @throws CmsException if operation was not successful
6137     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
6138     *
6139     */
6140    public void setParentGroup(CmsRequestContext context, String groupName, String parentGroupName)
6141    throws CmsException, CmsRoleViolationException {
6142
6143        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6144
6145        try {
6146            checkRole(dbc, CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(groupName)));
6147            m_driverManager.setParentGroup(
6148                dbc,
6149                CmsOrganizationalUnit.removeLeadingSeparator(groupName),
6150                CmsOrganizationalUnit.removeLeadingSeparator(parentGroupName));
6151        } catch (Exception e) {
6152            dbc.report(null, Messages.get().container(Messages.ERR_SET_PARENT_GROUP_2, parentGroupName, groupName), e);
6153        } finally {
6154            dbc.clear();
6155        }
6156    }
6157
6158    /**
6159     * Sets the password for a user.<p>
6160     *
6161     * @param context the current request context
6162     * @param username the name of the user
6163     * @param newPassword the new password
6164     *
6165     * @throws CmsException if operation was not successful
6166     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
6167     */
6168    public void setPassword(CmsRequestContext context, String username, String newPassword)
6169    throws CmsException, CmsRoleViolationException {
6170
6171        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6172        try {
6173            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(username));
6174            checkRoleForUserModification(dbc, username, role);
6175            m_driverManager.setPassword(dbc, CmsOrganizationalUnit.removeLeadingSeparator(username), newPassword);
6176        } catch (Exception e) {
6177            dbc.report(null, Messages.get().container(Messages.ERR_SET_PASSWORD_1, username), e);
6178        } finally {
6179            dbc.clear();
6180        }
6181    }
6182
6183    /**
6184     * Marks a subscribed resource as deleted.<p>
6185     *
6186     * @param context the request context
6187     * @param poolName the name of the database pool to use
6188     * @param resource the subscribed resource to mark as deleted
6189     *
6190     * @throws CmsException if something goes wrong
6191     */
6192    public void setSubscribedResourceAsDeleted(CmsRequestContext context, String poolName, CmsResource resource)
6193    throws CmsException {
6194
6195        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6196        try {
6197            m_driverManager.setSubscribedResourceAsDeleted(dbc, poolName, resource);
6198        } catch (Exception e) {
6199
6200            dbc.report(
6201                null,
6202                Messages.get().container(
6203                    Messages.ERR_SET_SUBSCRIBED_RESOURCE_AS_DELETED_1,
6204                    context.getSitePath(resource)),
6205                e);
6206
6207        } finally {
6208            dbc.clear();
6209        }
6210    }
6211
6212    /**
6213     * Moves an user to the given organizational unit.<p>
6214     *
6215     * @param context the current request context
6216     * @param orgUnit the organizational unit to add the principal to
6217     * @param user the user that is to be move to the organizational unit
6218     *
6219     * @throws CmsException if something goes wrong
6220     *
6221     * @see org.opencms.security.CmsOrgUnitManager#setUsersOrganizationalUnit(CmsObject, String, String)
6222     */
6223    public void setUsersOrganizationalUnit(CmsRequestContext context, CmsOrganizationalUnit orgUnit, CmsUser user)
6224    throws CmsException {
6225
6226        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6227        try {
6228            checkRole(dbc, CmsRole.ADMINISTRATOR.forOrgUnit(orgUnit.getName()));
6229            checkOfflineProject(dbc);
6230            m_driverManager.setUsersOrganizationalUnit(dbc, orgUnit, user);
6231        } catch (Exception e) {
6232            dbc.report(
6233                null,
6234                Messages.get().container(Messages.ERR_SET_USERS_ORGUNIT_2, orgUnit.getName(), user.getName()),
6235                e);
6236        } finally {
6237            dbc.clear();
6238        }
6239    }
6240
6241    /**
6242     * Subscribes the user or group to the resource.<p>
6243     *
6244     * @param context the request context
6245     * @param poolName the name of the database pool to use
6246     * @param principal the principal that subscribes to the resource
6247     * @param resource the resource to subscribe to
6248     *
6249     * @throws CmsException if something goes wrong
6250     */
6251    public void subscribeResourceFor(
6252        CmsRequestContext context,
6253        String poolName,
6254        CmsPrincipal principal,
6255        CmsResource resource)
6256    throws CmsException {
6257
6258        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6259        try {
6260            m_driverManager.subscribeResourceFor(dbc, poolName, principal, resource);
6261        } catch (Exception e) {
6262            if (principal instanceof CmsUser) {
6263                dbc.report(
6264                    null,
6265                    Messages.get().container(
6266                        Messages.ERR_SUBSCRIBE_RESOURCE_FOR_USER_2,
6267                        context.getSitePath(resource),
6268                        principal.getName()),
6269                    e);
6270            } else {
6271                dbc.report(
6272                    null,
6273                    Messages.get().container(
6274                        Messages.ERR_SUBSCRIBE_RESOURCE_FOR_GROUP_2,
6275                        context.getSitePath(resource),
6276                        principal.getName()),
6277                    e);
6278            }
6279        } finally {
6280            dbc.clear();
6281        }
6282    }
6283
6284    /**
6285     * Undelete the resource by resetting it's state.<p>
6286     *
6287     * @param context the current request context
6288     * @param resource the name of the resource to apply this operation to
6289     *
6290     * @throws CmsException if something goes wrong
6291     *
6292     * @see CmsObject#undeleteResource(String, boolean)
6293     * @see org.opencms.file.types.I_CmsResourceType#undelete(CmsObject, CmsSecurityManager, CmsResource, boolean)
6294     */
6295    public void undelete(CmsRequestContext context, CmsResource resource) throws CmsException {
6296
6297        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6298        try {
6299            checkOfflineProject(dbc);
6300            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
6301            checkSystemLocks(dbc, resource);
6302
6303            m_driverManager.undelete(dbc, resource);
6304        } catch (Exception e) {
6305            dbc.report(
6306                null,
6307                Messages.get().container(Messages.ERR_UNDELETE_FOR_RESOURCE_1, context.getSitePath(resource)),
6308                e);
6309        } finally {
6310            dbc.clear();
6311        }
6312    }
6313
6314    /**
6315     * Undos all changes in the resource by restoring the version from the
6316     * online project to the current offline project.<p>
6317     *
6318     * @param context the current request context
6319     * @param resource the name of the resource to apply this operation to
6320     * @param mode the undo mode, one of the <code>{@link CmsResource}#UNDO_XXX</code> constants
6321     *
6322     * @throws CmsException if something goes wrong
6323     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
6324     *
6325     * @see CmsObject#undoChanges(String, CmsResource.CmsResourceUndoMode)
6326     * @see org.opencms.file.types.I_CmsResourceType#undoChanges(CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceUndoMode)
6327     */
6328    public void undoChanges(CmsRequestContext context, CmsResource resource, CmsResource.CmsResourceUndoMode mode)
6329    throws CmsException, CmsSecurityException {
6330
6331        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6332        try {
6333            checkOfflineProject(dbc);
6334            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
6335            checkSystemLocks(dbc, resource);
6336
6337            m_driverManager.undoChanges(dbc, resource, mode);
6338        } catch (Exception e) {
6339            dbc.report(
6340                null,
6341                Messages.get().container(Messages.ERR_UNDO_CHANGES_FOR_RESOURCE_1, context.getSitePath(resource)),
6342                e);
6343        } finally {
6344            dbc.clear();
6345        }
6346    }
6347
6348    /**
6349     * Unlocks all resources in this project.<p>
6350     *
6351     * @param context the current request context
6352     * @param projectId the id of the project to be published
6353     *
6354     * @throws CmsException if something goes wrong
6355     * @throws CmsRoleViolationException if the current user does not own the required permissions
6356     */
6357    public void unlockProject(CmsRequestContext context, CmsUUID projectId)
6358    throws CmsException, CmsRoleViolationException {
6359
6360        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6361        CmsProject project = m_driverManager.readProject(dbc, projectId);
6362
6363        try {
6364            checkManagerOfProjectRole(dbc, project);
6365            m_driverManager.unlockProject(project);
6366        } catch (Exception e) {
6367            dbc.report(
6368                null,
6369                Messages.get().container(Messages.ERR_UNLOCK_PROJECT_2, projectId, dbc.currentUser().getName()),
6370                e);
6371        } finally {
6372            dbc.clear();
6373        }
6374    }
6375
6376    /**
6377     * Unlocks a resource.<p>
6378     *
6379     * @param context the current request context
6380     * @param resource the resource to unlock
6381     *
6382     * @throws CmsException if something goes wrong
6383     * @throws CmsSecurityException if the user has insufficient permission for the given resource (write access permission is required)
6384     *
6385     * @see CmsObject#unlockResource(String)
6386     * @see org.opencms.file.types.I_CmsResourceType#unlockResource(CmsObject, CmsSecurityManager, CmsResource)
6387     */
6388    public void unlockResource(CmsRequestContext context, CmsResource resource)
6389    throws CmsException, CmsSecurityException {
6390
6391        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6392        try {
6393            checkOfflineProject(dbc);
6394            checkPermissions(
6395                dbc,
6396                resource,
6397                CmsPermissionSet.ACCESS_WRITE,
6398                LockCheck.shallowOnly,
6399                CmsResourceFilter.ALL);
6400            m_driverManager.unlockResource(dbc, resource, false, false);
6401        } catch (CmsException e) {
6402            dbc.report(
6403                null,
6404                Messages.get().container(
6405                    Messages.ERR_UNLOCK_RESOURCE_3,
6406                    context.getSitePath(resource),
6407                    dbc.currentUser().getName(),
6408                    e.getLocalizedMessage(dbc.getRequestContext().getLocale())),
6409                e);
6410        } finally {
6411            dbc.clear();
6412        }
6413    }
6414
6415    /**
6416     * Unsubscribes all deleted resources that were deleted before the specified time stamp.<p>
6417     *
6418     * @param context the request context
6419     * @param poolName the name of the database pool to use
6420     * @param deletedTo the time stamp to which the resources have been deleted
6421     *
6422     * @throws CmsException if something goes wrong
6423     */
6424    public void unsubscribeAllDeletedResources(CmsRequestContext context, String poolName, long deletedTo)
6425    throws CmsException {
6426
6427        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6428        try {
6429            m_driverManager.unsubscribeAllDeletedResources(dbc, poolName, deletedTo);
6430        } catch (Exception e) {
6431
6432            dbc.report(null, Messages.get().container(Messages.ERR_UNSUBSCRIBE_ALL_DELETED_RESOURCES_USER_0), e);
6433
6434        } finally {
6435            dbc.clear();
6436        }
6437    }
6438
6439    /**
6440     * Unsubscribes the user or group from all resources.<p>
6441     *
6442     * @param context the request context
6443     * @param poolName the name of the database pool to use
6444     * @param principal the principal that unsubscribes from all resources
6445     *
6446     * @throws CmsException if something goes wrong
6447     */
6448    public void unsubscribeAllResourcesFor(CmsRequestContext context, String poolName, CmsPrincipal principal)
6449    throws CmsException {
6450
6451        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6452        try {
6453            m_driverManager.unsubscribeAllResourcesFor(dbc, poolName, principal);
6454        } catch (Exception e) {
6455            if (principal instanceof CmsUser) {
6456                dbc.report(
6457                    null,
6458                    Messages.get().container(Messages.ERR_UNSUBSCRIBE_ALL_RESOURCES_USER_1, principal.getName()),
6459                    e);
6460            } else {
6461                dbc.report(
6462                    null,
6463                    Messages.get().container(Messages.ERR_UNSUBSCRIBE_ALL_RESOURCES_GROUP_1, principal.getName()),
6464                    e);
6465            }
6466        } finally {
6467            dbc.clear();
6468        }
6469    }
6470
6471    /**
6472     * Unsubscribes the principal from the resource.<p>
6473     *
6474     * @param context the request context
6475     * @param poolName the name of the database pool to use
6476     * @param principal the principal that unsubscribes from the resource
6477     * @param resource the resource to unsubscribe from
6478     *
6479     * @throws CmsException if something goes wrong
6480     */
6481    public void unsubscribeResourceFor(
6482        CmsRequestContext context,
6483        String poolName,
6484        CmsPrincipal principal,
6485        CmsResource resource)
6486    throws CmsException {
6487
6488        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6489        try {
6490            m_driverManager.unsubscribeResourceFor(dbc, poolName, principal, resource);
6491        } catch (Exception e) {
6492            dbc.report(
6493                null,
6494                Messages.get().container(
6495                    Messages.ERR_UNSUBSCRIBE_RESOURCE_FOR_GROUP_2,
6496                    context.getSitePath(resource),
6497                    principal.getName()),
6498                e);
6499        } finally {
6500            dbc.clear();
6501        }
6502    }
6503
6504    /**
6505     * Unsubscribes all groups and users from the resource.<p>
6506     *
6507     * @param context the request context
6508     * @param poolName the name of the database pool to use
6509     * @param resource the resource to unsubscribe all groups and users from
6510     *
6511     * @throws CmsException if something goes wrong
6512     */
6513    public void unsubscribeResourceForAll(CmsRequestContext context, String poolName, CmsResource resource)
6514    throws CmsException {
6515
6516        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6517        try {
6518            m_driverManager.unsubscribeResourceForAll(dbc, poolName, resource);
6519        } catch (Exception e) {
6520            dbc.report(
6521                null,
6522                Messages.get().container(Messages.ERR_UNSUBSCRIBE_RESOURCE_ALL_1, context.getSitePath(resource)),
6523                e);
6524        } finally {
6525            dbc.clear();
6526        }
6527    }
6528
6529    /**
6530     * Updates the last login date on the given user to the current time.<p>
6531     *
6532     * @param context the current request context
6533     * @param user the user to be updated
6534     *
6535     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER} for the current project
6536     * @throws CmsException if operation was not successful
6537     */
6538    public void updateLastLoginDate(CmsRequestContext context, CmsUser user)
6539    throws CmsException, CmsRoleViolationException {
6540
6541        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6542        try {
6543            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(user.getName()));
6544            checkRoleForUserModification(dbc, user.getName(), role);
6545            m_driverManager.updateLastLoginDate(dbc, user);
6546        } catch (Exception e) {
6547            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_USER_1, user.getName()), e);
6548        } finally {
6549            dbc.clear();
6550        }
6551    }
6552
6553    /**
6554     * Logs everything that has not been written to DB jet.<p>
6555     *
6556     * @throws CmsException if something goes wrong
6557     */
6558    public void updateLog() throws CmsException {
6559
6560        if (m_dbContextFactory == null) {
6561            // already shutdown
6562            return;
6563        }
6564        CmsDbContext dbc = m_dbContextFactory.getDbContext();
6565        try {
6566            m_driverManager.updateLog(dbc);
6567        } finally {
6568            dbc.clear();
6569        }
6570    }
6571
6572    /**
6573     * Updates/Creates the relations for the given resource.<p>
6574     *
6575     * @param context the current user context
6576     * @param resource the resource to update the relations for
6577     * @param relations the relations to update
6578     *
6579     * @throws CmsException if something goes wrong
6580     *
6581     * @see CmsDriverManager#updateRelationsForResource(CmsDbContext, CmsResource, List)
6582     */
6583    public void updateRelationsForResource(CmsRequestContext context, CmsResource resource, List<CmsLink> relations)
6584    throws CmsException {
6585
6586        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6587        try {
6588            m_driverManager.updateRelationsForResource(dbc, resource, relations);
6589        } catch (Exception e) {
6590            dbc.report(
6591                null,
6592                Messages.get().container(Messages.ERR_UPDATE_RELATIONS_1, dbc.removeSiteRoot(resource.getRootPath())),
6593                e);
6594        } finally {
6595            dbc.clear();
6596        }
6597    }
6598
6599    /**
6600     * Tests if a user is member of the given group.<p>
6601     *
6602     * @param context the current request context
6603     * @param username the name of the user to check
6604     * @param groupname the name of the group to check
6605     *
6606     * @return <code>true</code>, if the user is in the group; or <code>false</code> otherwise
6607     *
6608     * @throws CmsException if operation was not successful
6609     */
6610    public boolean userInGroup(CmsRequestContext context, String username, String groupname) throws CmsException {
6611
6612        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6613        boolean result = false;
6614        try {
6615            result = m_driverManager.userInGroup(
6616                dbc,
6617                CmsOrganizationalUnit.removeLeadingSeparator(username),
6618                CmsOrganizationalUnit.removeLeadingSeparator(groupname),
6619                false);
6620        } catch (Exception e) {
6621            dbc.report(null, Messages.get().container(Messages.ERR_USER_IN_GROUP_2, username, groupname), e);
6622        } finally {
6623            dbc.clear();
6624        }
6625        return result;
6626    }
6627
6628    /**
6629     * Checks if a new password follows the rules for
6630     * new passwords, which are defined by a Class implementing the
6631     * <code>{@link org.opencms.security.I_CmsPasswordHandler}</code>
6632     * interface and configured in the opencms.properties file.<p>
6633     *
6634     * If this method throws no exception the password is valid.<p>
6635     *
6636     * @param password the new password that has to be checked
6637     *
6638     * @throws CmsSecurityException if the password is not valid
6639     */
6640    public void validatePassword(String password) throws CmsSecurityException {
6641
6642        m_driverManager.validatePassword(password);
6643    }
6644
6645    /**
6646     * Validates the relations for the given resources.<p>
6647     *
6648     * @param context the current request context
6649     * @param publishList the resources to validate during publishing
6650     * @param report a report to write the messages to
6651     *
6652     * @return a map with lists of invalid links
6653     *          (<code>{@link org.opencms.relations.CmsRelation}}</code> objects)
6654     *          keyed by root paths
6655     *
6656     * @throws Exception if something goes wrong
6657     */
6658    public Map<String, List<CmsRelation>> validateRelations(
6659        CmsRequestContext context,
6660        CmsPublishList publishList,
6661        I_CmsReport report)
6662    throws Exception {
6663
6664        Map<String, List<CmsRelation>> result = null;
6665        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6666        try {
6667            result = m_driverManager.validateRelations(dbc, publishList, report);
6668        } catch (Exception e) {
6669            dbc.report(null, Messages.get().container(Messages.ERR_VALIDATE_RELATIONS_0), e);
6670        } finally {
6671            dbc.clear();
6672        }
6673        return result;
6674    }
6675
6676    /**
6677     * Writes an access control entries to a given resource.<p>
6678     *
6679     * @param context the current request context
6680     * @param resource the resource
6681     * @param ace the entry to write
6682     *
6683     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_CONTROL} required)
6684     * @throws CmsException if something goes wrong
6685     */
6686    public void writeAccessControlEntry(CmsRequestContext context, CmsResource resource, CmsAccessControlEntry ace)
6687    throws CmsException, CmsSecurityException {
6688
6689        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6690        try {
6691            checkOfflineProject(dbc);
6692            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_CONTROL, true, CmsResourceFilter.ALL);
6693            if (ace.getPrincipal().equals(CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID)) {
6694                // only vfs managers can set the overwrite all ACE
6695                checkRoleForResource(dbc, CmsRole.VFS_MANAGER, resource);
6696            }
6697            m_driverManager.writeAccessControlEntry(dbc, resource, ace);
6698        } catch (Exception e) {
6699            dbc.report(
6700                null,
6701                Messages.get().container(Messages.ERR_WRITE_ACL_ENTRY_1, context.getSitePath(resource)),
6702                e);
6703        } finally {
6704            dbc.clear();
6705        }
6706    }
6707
6708    /**
6709     * Writes a resource to the OpenCms VFS, including it's content.<p>
6710     *
6711     * Applies only to resources of type <code>{@link CmsFile}</code>
6712     * i.e. resources that have a binary content attached.<p>
6713     *
6714     * Certain resource types might apply content validation or transformation rules
6715     * before the resource is actually written to the VFS. The returned result
6716     * might therefore be a modified version from the provided original.<p>
6717     *
6718     * @param context the current request context
6719     * @param resource the resource to apply this operation to
6720     *
6721     * @return the written resource (may have been modified)
6722     *
6723     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_WRITE} required)
6724     * @throws CmsException if something goes wrong
6725     *
6726     * @see CmsObject#writeFile(CmsFile)
6727     * @see org.opencms.file.types.I_CmsResourceType#writeFile(CmsObject, CmsSecurityManager, CmsFile)
6728     */
6729    public CmsFile writeFile(CmsRequestContext context, CmsFile resource) throws CmsException, CmsSecurityException {
6730
6731        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6732        CmsFile result = null;
6733        try {
6734            checkOfflineProject(dbc);
6735            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
6736            result = m_driverManager.writeFile(dbc, resource);
6737        } catch (Exception e) {
6738            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_FILE_1, context.getSitePath(resource)), e);
6739        } finally {
6740            dbc.clear();
6741        }
6742        return result;
6743    }
6744
6745    /**
6746     * Writes an already existing group.<p>
6747     *
6748     * The group id has to be a valid OpenCms group id.<br>
6749     *
6750     * The group with the given id will be completely overridden
6751     * by the given data.<p>
6752     *
6753     * @param context the current request context
6754     * @param group the group that should be written
6755     *
6756     * @throws CmsRoleViolationException if the current user does not own the role {@link CmsRole#ACCOUNT_MANAGER} for the current project
6757     * @throws CmsException if operation was not successful
6758     */
6759    public void writeGroup(CmsRequestContext context, CmsGroup group) throws CmsException, CmsRoleViolationException {
6760
6761        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6762        try {
6763            checkRole(dbc, CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(group.getName())));
6764            m_driverManager.writeGroup(dbc, group);
6765        } catch (Exception e) {
6766            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_GROUP_1, group.getName()), e);
6767        } finally {
6768            dbc.clear();
6769        }
6770    }
6771
6772    /**
6773     * Creates a historical entry of the current project.<p>
6774     *
6775     * @param context the current request context
6776     * @param publishTag the correlative publish tag
6777     * @param publishDate the date of publishing
6778     *
6779     * @throws CmsException if operation was not successful
6780     */
6781    public void writeHistoryProject(CmsRequestContext context, int publishTag, long publishDate) throws CmsException {
6782
6783        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6784        try {
6785            m_driverManager.writeHistoryProject(dbc, publishTag, publishDate);
6786        } catch (Exception e) {
6787            dbc.report(
6788                null,
6789                Messages.get().container(
6790                    Messages.ERR_HISTORY_PROJECT_4,
6791                    new Object[] {
6792                        new Integer(publishTag),
6793                        dbc.currentProject().getName(),
6794                        dbc.currentProject().getUuid(),
6795                        new Long(publishDate)}),
6796                e);
6797        } finally {
6798            dbc.clear();
6799        }
6800    }
6801
6802    /**
6803     * Writes the locks that are currently stored in-memory to the database to allow restoring them in
6804     * later startups.<p>
6805     *
6806     * This overwrites the locks previously stored in the underlying database table.<p>
6807     *
6808     * @throws CmsException if something goes wrong
6809     */
6810    public void writeLocks() throws CmsException {
6811
6812        if (m_dbContextFactory == null) {
6813            // already shutdown
6814            return;
6815        }
6816        CmsDbContext dbc = m_dbContextFactory.getDbContext();
6817        try {
6818            m_driverManager.writeLocks(dbc);
6819        } finally {
6820            dbc.clear();
6821        }
6822    }
6823
6824    /**
6825     * Writes an already existing organizational unit.<p>
6826     *
6827     * The organizational unit id has to be a valid OpenCms organizational unit id.<p>
6828     *
6829     * The organizational unit with the given id will be completely overridden
6830     * by the given data.<p>
6831     *
6832     * @param context the current request context
6833     * @param organizationalUnit the organizational unit that should be written
6834     *
6835     * @throws CmsException if operation was not successful
6836     *
6837     * @see org.opencms.security.CmsOrgUnitManager#writeOrganizationalUnit(CmsObject, CmsOrganizationalUnit)
6838     */
6839    public void writeOrganizationalUnit(CmsRequestContext context, CmsOrganizationalUnit organizationalUnit)
6840    throws CmsException {
6841
6842        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6843        try {
6844            checkRole(dbc, CmsRole.ADMINISTRATOR.forOrgUnit(organizationalUnit.getName()));
6845            checkOfflineProject(dbc);
6846            m_driverManager.writeOrganizationalUnit(dbc, organizationalUnit);
6847        } catch (Exception e) {
6848            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_ORGUNIT_1, organizationalUnit.getName()), e);
6849        } finally {
6850            dbc.clear();
6851        }
6852    }
6853
6854    /**
6855     * Writes an already existing project.<p>
6856     *
6857     * The project id has to be a valid OpenCms project id.<br>
6858     *
6859     * The project with the given id will be completely overridden
6860     * by the given data.<p>
6861     *
6862     * @param project the project that should be written
6863     * @param context the current request context
6864     *
6865     * @throws CmsRoleViolationException if the current user does not own the required permissions
6866     * @throws CmsException if operation was not successful
6867     */
6868    public void writeProject(CmsRequestContext context, CmsProject project)
6869    throws CmsRoleViolationException, CmsException {
6870
6871        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6872        try {
6873            checkManagerOfProjectRole(dbc, project);
6874            m_driverManager.writeProject(dbc, project);
6875        } catch (Exception e) {
6876            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_PROJECT_1, project.getName()), e);
6877        } finally {
6878            dbc.clear();
6879        }
6880    }
6881
6882    /**
6883     * Writes a property for a specified resource.<p>
6884     *
6885     * @param context the current request context
6886     * @param resource the resource to write the property for
6887     * @param property the property to write
6888     *
6889     * @throws CmsException if something goes wrong
6890     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_WRITE} required)
6891     *
6892     * @see CmsObject#writePropertyObject(String, CmsProperty)
6893     * @see org.opencms.file.types.I_CmsResourceType#writePropertyObject(CmsObject, CmsSecurityManager, CmsResource, CmsProperty)
6894     */
6895    public void writePropertyObject(CmsRequestContext context, CmsResource resource, CmsProperty property)
6896    throws CmsException, CmsSecurityException {
6897
6898        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6899        try {
6900            checkOfflineProject(dbc);
6901            checkPermissions(
6902                dbc,
6903                resource,
6904                CmsPermissionSet.ACCESS_WRITE,
6905                LockCheck.shallowOnly,
6906                CmsResourceFilter.IGNORE_EXPIRATION);
6907            m_driverManager.writePropertyObject(dbc, resource, property);
6908        } catch (Exception e) {
6909            dbc.report(
6910                null,
6911                Messages.get().container(Messages.ERR_WRITE_PROP_2, property.getName(), context.getSitePath(resource)),
6912                e);
6913        } finally {
6914            dbc.clear();
6915        }
6916    }
6917
6918    /**
6919     * Writes a list of properties for a specified resource.<p>
6920     *
6921     * Code calling this method has to ensure that the no properties
6922     * <code>a, b</code> are contained in the specified list so that <code>a.equals(b)</code>,
6923     * otherwise an exception is thrown.<p>
6924     *
6925     * @param context the current request context
6926     * @param resource the resource to write the properties for
6927     * @param properties the list of properties to write
6928     *
6929     * @throws CmsException if something goes wrong
6930     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_WRITE} required)
6931     *
6932     * @see CmsObject#writePropertyObjects(String, List)
6933     * @see org.opencms.file.types.I_CmsResourceType#writePropertyObjects(CmsObject, CmsSecurityManager, CmsResource, List)
6934     */
6935    public void writePropertyObjects(CmsRequestContext context, CmsResource resource, List<CmsProperty> properties)
6936    throws CmsException, CmsSecurityException {
6937
6938        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6939        try {
6940            checkOfflineProject(dbc);
6941            checkPermissions(
6942                dbc,
6943                resource,
6944                CmsPermissionSet.ACCESS_WRITE,
6945                LockCheck.shallowOnly,
6946                CmsResourceFilter.IGNORE_EXPIRATION);
6947            // write the properties
6948            m_driverManager.writePropertyObjects(dbc, resource, properties, true);
6949        } catch (Exception e) {
6950            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_PROPS_1, context.getSitePath(resource)), e);
6951        } finally {
6952            dbc.clear();
6953        }
6954    }
6955
6956    /**
6957     * Writes a resource to the OpenCms VFS.<p>
6958     *
6959     * @param context the current request context
6960     * @param resource the resource to write
6961     *
6962     * @throws CmsSecurityException if the user has insufficient permission for the given resource ({@link CmsPermissionSet#ACCESS_WRITE} required)
6963     * @throws CmsException if something goes wrong
6964     */
6965    public void writeResource(CmsRequestContext context, CmsResource resource)
6966    throws CmsException, CmsSecurityException {
6967
6968        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6969        try {
6970            checkOfflineProject(dbc);
6971            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
6972            m_driverManager.writeResource(dbc, resource);
6973        } catch (Exception e) {
6974            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_RESOURCE_1, context.getSitePath(resource)), e);
6975        } finally {
6976            dbc.clear();
6977        }
6978    }
6979
6980    /**
6981     * Writes the 'projectlastmodified' field of a resource record.<p>
6982     *
6983     * @param context the current database context
6984     * @param resource the resource which should be modified
6985     * @param project the project whose project id should be written into the resource record
6986     *
6987     * @throws CmsException if something goes wrong
6988     */
6989    public void writeResourceProjectLastModified(CmsRequestContext context, CmsResource resource, CmsProject project)
6990    throws CmsException {
6991
6992        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
6993        try {
6994            checkOfflineProject(dbc);
6995            checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_WRITE, true, CmsResourceFilter.ALL);
6996            m_driverManager.writeProjectLastModified(dbc, resource, project.getUuid());
6997        } catch (Exception e) {
6998            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_RESOURCE_1, context.getSitePath(resource)), e);
6999        } finally {
7000            dbc.clear();
7001        }
7002    }
7003
7004    /**
7005     * Inserts an entry in the published resource table.<p>
7006     *
7007     * This is done during static export.<p>
7008     *
7009     * @param context the current request context
7010     * @param resourceName The name of the resource to be added to the static export
7011     * @param linkType the type of resource exported (0= non-parameter, 1=parameter)
7012     * @param linkParameter the parameters added to the resource
7013     * @param timestamp a time stamp for writing the data into the db
7014     *
7015     * @throws CmsException if something goes wrong
7016     */
7017    public void writeStaticExportPublishedResource(
7018        CmsRequestContext context,
7019        String resourceName,
7020        int linkType,
7021        String linkParameter,
7022        long timestamp)
7023    throws CmsException {
7024
7025        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
7026        try {
7027            m_driverManager.writeStaticExportPublishedResource(dbc, resourceName, linkType, linkParameter, timestamp);
7028        } catch (Exception e) {
7029            dbc.report(
7030                null,
7031                Messages.get().container(
7032                    Messages.ERR_WRITE_STATEXP_PUBLISHED_RESOURCES_3,
7033                    resourceName,
7034                    linkParameter,
7035                    new Date(timestamp)),
7036                e);
7037        } finally {
7038            dbc.clear();
7039        }
7040    }
7041
7042    /**
7043     * Writes a new URL name mapping for a given resource.<p>
7044     *
7045     * The first name from the given sequence which is not already mapped to another resource will be used for
7046     * the URL name mapping.<p>
7047     *
7048     * @param context the request context
7049     * @param nameSeq the sequence of URL name candidates
7050     * @param structureId the structure id which should be mapped to the name
7051     * @param locale the locale for the mapping
7052     * @param replaceOnPublish mappings for which this is set will replace all other mappings for the same resource on publishing
7053     *
7054     * @return the name which was actually mapped to the structure id
7055     *
7056     * @throws CmsException if something goes wrong
7057     */
7058    public String writeUrlNameMapping(
7059        CmsRequestContext context,
7060        Iterator<String> nameSeq,
7061        CmsUUID structureId,
7062        String locale,
7063        boolean replaceOnPublish)
7064    throws CmsException {
7065
7066        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
7067        try {
7068            return m_driverManager.writeUrlNameMapping(dbc, nameSeq, structureId, locale, replaceOnPublish);
7069        } catch (Exception e) {
7070            CmsMessageContainer message = Messages.get().container(
7071                Messages.ERR_ADD_URLNAME_MAPPING_2,
7072                nameSeq.toString(),
7073                structureId.toString());
7074            dbc.report(null, message, e);
7075            return null;
7076        } finally {
7077            dbc.clear();
7078        }
7079    }
7080
7081    /**
7082     * Updates the user information. <p>
7083     *
7084     * The user id has to be a valid OpenCms user id.<br>
7085     *
7086     * The user with the given id will be completely overridden
7087     * by the given data.<p>
7088     *
7089     * @param context the current request context
7090     * @param user the user to be updated
7091     *
7092     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER} for the current project
7093     * @throws CmsException if operation was not successful
7094     */
7095    public void writeUser(CmsRequestContext context, CmsUser user) throws CmsException, CmsRoleViolationException {
7096
7097        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
7098        try {
7099            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(user.getName()));
7100            checkRoleForUserModification(dbc, user.getName(), role);
7101            m_driverManager.writeUser(dbc, user);
7102        } catch (Exception e) {
7103            dbc.report(null, Messages.get().container(Messages.ERR_WRITE_USER_1, user.getName()), e);
7104        } finally {
7105            dbc.clear();
7106        }
7107    }
7108
7109    /**
7110     * Performs a blocking permission check on a resource.<p>
7111     *
7112     * If the required permissions are not satisfied by the permissions the user has on the resource,
7113     * an exception is thrown.<p>
7114     *
7115     * @param dbc the current database context
7116     * @param resource the resource on which permissions are required
7117     * @param requiredPermissions the set of permissions required to access the resource
7118     * @param checkLock if true, the lock status of the resource is also checked
7119     * @param filter the filter for the resource
7120     *
7121     * @throws CmsException in case of any i/o error
7122     * @throws CmsSecurityException if the required permissions are not satisfied
7123     *
7124     * @see #hasPermissions(CmsRequestContext, CmsResource, CmsPermissionSet, boolean, CmsResourceFilter)
7125     */
7126    protected void checkPermissions(
7127        CmsDbContext dbc,
7128        CmsResource resource,
7129        CmsPermissionSet requiredPermissions,
7130        boolean checkLock,
7131        CmsResourceFilter filter)
7132    throws CmsException, CmsSecurityException {
7133
7134        // get the permissions
7135        I_CmsPermissionHandler.CmsPermissionCheckResult permissions = hasPermissions(
7136            dbc,
7137            resource,
7138            requiredPermissions,
7139            checkLock ? LockCheck.yes : LockCheck.no,
7140            filter);
7141        if (!permissions.isAllowed()) {
7142            checkPermissions(dbc.getRequestContext(), resource, requiredPermissions, permissions);
7143        }
7144    }
7145
7146    /**
7147     * Performs a blocking permission check on a resource.<p>
7148     *
7149     * If the required permissions are not satisfied by the permissions the user has on the resource,
7150     * an exception is thrown.<p>
7151     *
7152     * @param dbc the current database context
7153     * @param resource the resource on which permissions are required
7154     * @param requiredPermissions the set of permissions required to access the resource
7155     * @param checkLock if true, the lock status of the resource is also checked
7156     * @param filter the filter for the resource
7157     *
7158     * @throws CmsException in case of any i/o error
7159     * @throws CmsSecurityException if the required permissions are not satisfied
7160     *
7161     * @see #hasPermissions(CmsRequestContext, CmsResource, CmsPermissionSet, boolean, CmsResourceFilter)
7162     */
7163    protected void checkPermissions(
7164        CmsDbContext dbc,
7165        CmsResource resource,
7166        CmsPermissionSet requiredPermissions,
7167        LockCheck checkLock,
7168        CmsResourceFilter filter)
7169    throws CmsException, CmsSecurityException {
7170
7171        // get the permissions
7172        I_CmsPermissionHandler.CmsPermissionCheckResult permissions = hasPermissions(
7173            dbc,
7174            resource,
7175            requiredPermissions,
7176            checkLock,
7177            filter);
7178        if (!permissions.isAllowed()) {
7179            checkPermissions(dbc.getRequestContext(), resource, requiredPermissions, permissions);
7180        }
7181    }
7182
7183    /**
7184     * Applies the permission check result of a previous call
7185     * to {@link #hasPermissions(CmsRequestContext, CmsResource, CmsPermissionSet, boolean, CmsResourceFilter)}.<p>
7186     *
7187     * @param context the current request context
7188     * @param resource the resource on which permissions are required
7189     * @param requiredPermissions the set of permissions required to access the resource
7190     * @param permissions the permissions to check
7191     *
7192     * @throws CmsSecurityException if the required permissions are not satisfied
7193     * @throws CmsLockException if the lock status is not as required
7194     * @throws CmsVfsResourceNotFoundException if the required resource has been filtered
7195     */
7196    protected void checkPermissions(
7197        CmsRequestContext context,
7198        CmsResource resource,
7199        CmsPermissionSet requiredPermissions,
7200        I_CmsPermissionHandler.CmsPermissionCheckResult permissions)
7201    throws CmsSecurityException, CmsLockException, CmsVfsResourceNotFoundException {
7202
7203        if (permissions == I_CmsPermissionHandler.PERM_FILTERED) {
7204            throw new CmsVfsResourceNotFoundException(
7205                Messages.get().container(Messages.ERR_PERM_FILTERED_1, context.getSitePath(resource)));
7206        }
7207        if (permissions == I_CmsPermissionHandler.PERM_DENIED) {
7208            throw new CmsPermissionViolationException(
7209                Messages.get().container(
7210                    Messages.ERR_PERM_DENIED_2,
7211                    context.getSitePath(resource),
7212                    requiredPermissions.getPermissionString()));
7213        }
7214        if (permissions == I_CmsPermissionHandler.PERM_NOTLOCKED) {
7215            throw new CmsLockException(
7216                Messages.get().container(
7217                    Messages.ERR_PERM_NOTLOCKED_2,
7218                    context.getSitePath(resource),
7219                    context.getCurrentUser().getName()));
7220        }
7221    }
7222
7223    /**
7224     * Checks that the current user has enough permissions to modify the given user.<p>
7225     *
7226     * @param dbc the database context
7227     * @param username the name of the user to modify
7228     * @param role the needed role
7229     *
7230     * @throws CmsDataAccessException if something goes wrong accessing the database
7231     * @throws CmsRoleViolationException if the user has not the needed permissions
7232     */
7233    protected void checkRoleForUserModification(CmsDbContext dbc, String username, CmsRole role)
7234    throws CmsDataAccessException, CmsRoleViolationException {
7235
7236        CmsUser userToModify = m_driverManager.readUser(dbc, CmsOrganizationalUnit.removeLeadingSeparator(username));
7237        if (dbc.currentUser().equals(userToModify)) {
7238            // a user is allowed to write his own data
7239            return;
7240        }
7241        if (hasRole(dbc, dbc.currentUser(), CmsRole.ROOT_ADMIN)) {
7242            // a user with the ROOT_ADMIN role may change any other user
7243            return;
7244        }
7245        if (hasRole(dbc, userToModify, CmsRole.ADMINISTRATOR)) {
7246            // check the user that is going to do the modification is administrator
7247            checkRole(dbc, CmsRole.ADMINISTRATOR);
7248        } else {
7249            // check the user that is going to do the modification has the given role
7250            checkRole(dbc, role);
7251        }
7252
7253    }
7254
7255    /**
7256     * Checks if the given resource contains a resource that has a system lock.<p>
7257     *
7258     * @param dbc the current database context
7259     * @param resource the resource to check
7260     *
7261     * @throws CmsException in case there is a system lock contained in the given resource
7262     */
7263    protected void checkSystemLocks(CmsDbContext dbc, CmsResource resource) throws CmsException {
7264
7265        if (m_lockManager.hasSystemLocks(dbc, resource)) {
7266            throw new CmsLockException(
7267                Messages.get().container(
7268                    Messages.ERR_RESOURCE_SYSTEM_LOCKED_1,
7269                    dbc.removeSiteRoot(resource.getRootPath())));
7270        }
7271    }
7272
7273    /**
7274     * Internal recursive method for deleting a resource.<p>
7275     *
7276     * @param dbc the db context
7277     * @param resource the name of the resource to delete (full path)
7278     * @param siblingMode indicates how to handle siblings of the deleted resource
7279     *
7280     * @throws CmsException if something goes wrong
7281     */
7282    protected void deleteResource(CmsDbContext dbc, CmsResource resource, CmsResource.CmsResourceDeleteMode siblingMode)
7283    throws CmsException {
7284
7285        if (resource.isFolder()) {
7286            // collect all resources in the folder (but exclude deleted ones)
7287            List<CmsResource> resources = m_driverManager.readChildResources(
7288                dbc,
7289                resource,
7290                CmsResourceFilter.IGNORE_EXPIRATION,
7291                true,
7292                true,
7293                false);
7294
7295            Set<CmsUUID> deletedResources = new HashSet<CmsUUID>();
7296            // now walk through all sub-resources in the folder
7297            for (int i = 0; i < resources.size(); i++) {
7298                CmsResource childResource = resources.get(i);
7299                if ((siblingMode == CmsResource.DELETE_REMOVE_SIBLINGS)
7300                    && deletedResources.contains(childResource.getResourceId())) {
7301                    // sibling mode is "delete all siblings" and another sibling of the current child resource has already
7302                    // been deleted- do nothing and continue with the next child resource.
7303                    continue;
7304                }
7305                if (childResource.isFolder()) {
7306                    // recurse into this method for subfolders
7307                    deleteResource(dbc, childResource, siblingMode);
7308                } else {
7309                    // handle child resources
7310                    m_driverManager.deleteResource(dbc, childResource, siblingMode);
7311                }
7312                deletedResources.add(childResource.getResourceId());
7313            }
7314            deletedResources.clear();
7315        }
7316        // handle the resource itself
7317        m_driverManager.deleteResource(dbc, resource, siblingMode);
7318    }
7319
7320    /**
7321     * Deletes a user, where all permissions and resources attributes of the user
7322     * were transfered to a replacement user, if given.<p>
7323     *
7324     * @param context the current request context
7325     * @param user the user to be deleted
7326     * @param replacement the user to be transfered, can be <code>null</code>
7327     *
7328     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER}
7329     * @throws CmsSecurityException in case the user is a default user
7330     * @throws CmsException if something goes wrong
7331     */
7332    protected void deleteUser(CmsRequestContext context, CmsUser user, CmsUser replacement)
7333    throws CmsException, CmsSecurityException, CmsRoleViolationException {
7334
7335        if (OpenCms.getDefaultUsers().isDefaultUser(user.getName())) {
7336            throw new CmsSecurityException(
7337                org.opencms.security.Messages.get().container(
7338                    org.opencms.security.Messages.ERR_CANT_DELETE_DEFAULT_USER_1,
7339                    user.getName()));
7340        }
7341        if (context.getCurrentUser().equals(user)) {
7342            throw new CmsSecurityException(Messages.get().container(Messages.ERR_USER_CANT_DELETE_ITSELF_USER_0));
7343        }
7344
7345        CmsDbContext dbc = null;
7346        try {
7347            dbc = getDbContextForDeletePrincipal(context);
7348            CmsRole role = CmsRole.ACCOUNT_MANAGER.forOrgUnit(getParentOrganizationalUnit(user.getName()));
7349            checkRoleForUserModification(dbc, user.getName(), role);
7350            m_driverManager.deleteUser(
7351                dbc,
7352                dbc.getRequestContext().getCurrentProject(),
7353                user.getName(),
7354                null == replacement ? null : replacement.getName());
7355        } catch (Exception e) {
7356            CmsDbContext dbcForException = m_dbContextFactory.getDbContext(context);
7357            dbcForException.report(null, Messages.get().container(Messages.ERR_DELETE_USER_1, user.getName()), e);
7358            dbcForException.clear();
7359        } finally {
7360            if (null != dbc) {
7361                dbc.clear();
7362            }
7363        }
7364    }
7365
7366    /**
7367     * Returns all resources of organizational units for which the current user has
7368     * the given role role.<p>
7369     *
7370     * @param dbc the current database context
7371     * @param role the role to check
7372     *
7373     * @return a list of {@link org.opencms.file.CmsResource} objects
7374     *
7375     * @throws CmsException if something goes wrong
7376     */
7377    protected List<CmsResource> getManageableResources(CmsDbContext dbc, CmsRole role) throws CmsException {
7378
7379        CmsOrganizationalUnit ou = m_driverManager.readOrganizationalUnit(dbc, role.getOuFqn());
7380        if (hasRole(dbc, dbc.currentUser(), role)) {
7381            return m_driverManager.getResourcesForOrganizationalUnit(dbc, ou);
7382        }
7383        List<CmsResource> resources = new ArrayList<CmsResource>();
7384        Iterator<CmsOrganizationalUnit> it = m_driverManager.getOrganizationalUnits(dbc, ou, false).iterator();
7385        while (it.hasNext()) {
7386            CmsOrganizationalUnit orgUnit = it.next();
7387            resources.addAll(getManageableResources(dbc, role.forOrgUnit(orgUnit.getName())));
7388        }
7389        return resources;
7390    }
7391
7392    /**
7393     * Returns the organizational unit for the parent of the given fully qualified name.<p>
7394     *
7395     * @param fqn the fully qualified name to get the parent organizational unit for
7396     *
7397     * @return the parent organizational unit for the fully qualified name
7398     */
7399    protected String getParentOrganizationalUnit(String fqn) {
7400
7401        String ouFqn = CmsOrganizationalUnit.getParentFqn(CmsOrganizationalUnit.removeLeadingSeparator(fqn));
7402        if (ouFqn == null) {
7403            ouFqn = "";
7404        }
7405        return ouFqn;
7406    }
7407
7408    /**
7409     * Performs a non-blocking permission check on a resource.<p>
7410     *
7411     * This test will not throw an exception in case the required permissions are not
7412     * available for the requested operation. Instead, it will return one of the
7413     * following values:<ul>
7414     * <li><code>{@link I_CmsPermissionHandler#PERM_ALLOWED}</code></li>
7415     * <li><code>{@link I_CmsPermissionHandler#PERM_FILTERED}</code></li>
7416     * <li><code>{@link I_CmsPermissionHandler#PERM_DENIED}</code></li></ul><p>
7417     *
7418     * @param dbc the current database context
7419     * @param resource the resource on which permissions are required
7420     * @param requiredPermissions the set of permissions required for the operation
7421     * @param checkLock if true, a lock for the current user is required for
7422     *      all write operations, if false it's ok to write as long as the resource
7423     *      is not locked by another user
7424     * @param filter the resource filter to use
7425     *
7426     * @return <code>{@link I_CmsPermissionHandler#PERM_ALLOWED}</code> if the user has sufficient permissions on the resource
7427     *      for the requested operation
7428     *
7429     * @throws CmsException in case of i/o errors (NOT because of insufficient permissions)
7430     */
7431    protected I_CmsPermissionHandler.CmsPermissionCheckResult hasPermissions(
7432        CmsDbContext dbc,
7433        CmsResource resource,
7434        CmsPermissionSet requiredPermissions,
7435        LockCheck checkLock,
7436        CmsResourceFilter filter)
7437    throws CmsException {
7438
7439        return m_permissionHandler.hasPermissions(dbc, resource, requiredPermissions, checkLock, filter);
7440    }
7441
7442    /**
7443     * Returns <code>true</code> if at least one of the given group names is equal to a group name
7444     * of the given role in the given organizational unit.<p>
7445     *
7446     * This checks the given list against the group of the given role as well as against the role group
7447     * of all parent roles.<p>
7448     *
7449     * If the organizational unit is <code>null</code>, this method will check if the
7450     * given user has the given role for at least one organizational unit.<p>
7451     *
7452     * @param role the role to check
7453     * @param roles the groups to match the role groups against
7454     *
7455     * @return <code>true</code> if at last one of the given group names is equal to a group name
7456     *      of this role
7457     */
7458    protected boolean hasRole(CmsRole role, List<CmsGroup> roles) {
7459
7460        // iterates the role groups the user is in
7461        for (CmsGroup group : roles) {
7462            String groupName = group.getName();
7463            // iterate the role hierarchy
7464            for (String distictGroupName : role.getDistinctGroupNames()) {
7465                if (distictGroupName.startsWith(CmsOrganizationalUnit.SEPARATOR)) {
7466                    // this is a ou independent role
7467                    // we need an exact match, and we ignore the ou parameter
7468                    if (groupName.equals(distictGroupName.substring(1))) {
7469                        return true;
7470                    }
7471                } else {
7472                    // first check if the user has the role at all
7473                    if (groupName.endsWith(CmsOrganizationalUnit.SEPARATOR + distictGroupName)
7474                        || groupName.equals(distictGroupName)) {
7475                        // this is a ou dependent role
7476                        if (role.getOuFqn() == null) {
7477                            // ou parameter is null, so the user needs to have the role in at least one ou does not matter which
7478                            return true;
7479                        } else {
7480                            // the user needs to have the role in the given ou or in a parent ou
7481                            // now check that the ou matches
7482                            String groupFqn = CmsOrganizationalUnit.getParentFqn(groupName);
7483                            if (role.getOuFqn().startsWith(groupFqn)) {
7484                                return true;
7485                            }
7486                        }
7487                    }
7488                }
7489            }
7490        }
7491        return false;
7492    }
7493
7494    /**
7495     * Internal recursive method to move a resource.<p>
7496     *
7497     * @param dbc the db context
7498     * @param source the source resource
7499     * @param destination the destination path
7500     * @param allMovedResources a set used to collect all moved resources
7501     *
7502     * @throws CmsException if something goes wrong
7503     */
7504    protected void moveResource(
7505        CmsDbContext dbc,
7506        CmsResource source,
7507        String destination,
7508        Set<CmsResource> allMovedResources)
7509    throws CmsException {
7510
7511        List<CmsResource> resources = null;
7512
7513        if (source.isFolder()) {
7514            if (!CmsResource.isFolder(destination)) {
7515                // ensure folder name end's with a /
7516                destination = destination.concat("/");
7517            }
7518            // collect all resources in the folder without checking permissions
7519            resources = m_driverManager.readChildResources(dbc, source, CmsResourceFilter.ALL, true, true, false);
7520        }
7521
7522        // target permissions will be checked later
7523        m_driverManager.moveResource(dbc, source, destination, false);
7524
7525        // make sure lock is set
7526        CmsResource destinationResource = m_driverManager.readResource(dbc, destination, CmsResourceFilter.ALL);
7527        try {
7528            // the destination must always get a new lock
7529            m_driverManager.lockResource(dbc, destinationResource, CmsLockType.EXCLUSIVE);
7530        } catch (Exception e) {
7531            // could happen with with shared locks on single files
7532            if (LOG.isWarnEnabled()) {
7533                LOG.warn(e.getLocalizedMessage(), e);
7534            }
7535        }
7536
7537        if (resources != null) {
7538            // Ensure consistent order that is not database-dependent, since readChildResources doesn't specify an ordering.
7539            // this is necessary to make test cases more useful.
7540            Collections.sort(resources, (r1, r2) -> r1.getRootPath().compareTo(r2.getRootPath()));
7541
7542            // now walk through all sub-resources in the folder
7543            for (int i = 0; i < resources.size(); i++) {
7544                CmsResource childResource = resources.get(i);
7545                String childDestination = destination.concat(childResource.getName());
7546                // recurse with child resource
7547                moveResource(dbc, childResource, childDestination, allMovedResources);
7548            }
7549        }
7550
7551        List<CmsResource> movedResources = m_driverManager.readChildResources(
7552            dbc,
7553            destinationResource,
7554            CmsResourceFilter.ALL,
7555            true,
7556            true,
7557            false);
7558        allMovedResources.add(destinationResource);
7559        allMovedResources.addAll(movedResources);
7560
7561    }
7562
7563    /**
7564     * Reads a folder from the VFS, using the specified resource filter.<p>
7565     *
7566     * @param dbc the current database context
7567     * @param resourcename the name of the folder to read (full path)
7568     * @param filter the resource filter to use while reading
7569     *
7570     * @return the folder that was read
7571     *
7572     * @throws CmsException if something goes wrong
7573     */
7574    protected CmsFolder readFolder(CmsDbContext dbc, String resourcename, CmsResourceFilter filter)
7575    throws CmsException {
7576
7577        CmsResource resource = readResource(dbc, resourcename, filter);
7578        return m_driverManager.convertResourceToFolder(resource);
7579    }
7580
7581    /**
7582     * Reads a resource from the OpenCms VFS, using the specified resource filter.<p>
7583     *
7584     * @param dbc the current database context
7585     * @param structureID the ID of the structure to read
7586     * @param filter the resource filter to use while reading
7587     *
7588     * @return the resource that was read
7589     *
7590     * @throws CmsException if something goes wrong
7591     *
7592     * @see CmsObject#readResource(CmsUUID, CmsResourceFilter)
7593     * @see CmsObject#readResource(CmsUUID)
7594     * @see CmsObject#readFile(CmsResource)
7595     */
7596    protected CmsResource readResource(CmsDbContext dbc, CmsUUID structureID, CmsResourceFilter filter)
7597    throws CmsException {
7598
7599        // read the resource from the VFS
7600        CmsResource resource = m_driverManager.readResource(dbc, structureID, filter);
7601
7602        // check if the user has read access to the resource
7603        checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, true, filter);
7604
7605        // access was granted - return the resource
7606        return resource;
7607    }
7608
7609    /**
7610     * Reads a resource from the OpenCms VFS, using the specified resource filter.<p>
7611     *
7612     * @param dbc the current database context
7613     * @param resourcePath the name of the resource to read (full path)
7614     * @param filter the resource filter to use while reading
7615     *
7616     * @return the resource that was read
7617     *
7618     * @throws CmsException if something goes wrong
7619     *
7620     * @see CmsObject#readResource(String, CmsResourceFilter)
7621     * @see CmsObject#readResource(String)
7622     * @see CmsObject#readFile(CmsResource)
7623     */
7624    protected CmsResource readResource(CmsDbContext dbc, String resourcePath, CmsResourceFilter filter)
7625    throws CmsException {
7626
7627        // read the resource from the VFS
7628        CmsResource resource = m_driverManager.readResource(dbc, resourcePath, filter);
7629
7630        // check if the user has read access to the resource
7631        checkPermissions(dbc, resource, CmsPermissionSet.ACCESS_READ, true, filter);
7632
7633        // access was granted - return the resource
7634        return resource;
7635    }
7636
7637    /**
7638     * Determines a project where the deletion of a principal can be executed and sets it in the returned db context.<p>
7639     *
7640     * @param context the current request context
7641     *
7642     * @return the db context to use when deleting the principal.
7643     *
7644     * @throws CmsDataAccessException if determining a project that is suitable to delete the prinicipal fails.
7645     */
7646    private CmsDbContext getDbContextForDeletePrincipal(CmsRequestContext context) throws CmsDataAccessException {
7647
7648        CmsProject currentProject = context.getCurrentProject();
7649        CmsDbContext dbc = m_dbContextFactory.getDbContext(context);
7650        CmsUUID projectId = dbc.getProjectId();
7651        // principal modifications are allowed if the current project is not the online project
7652        if (currentProject.isOnlineProject()) {
7653            // this is needed because
7654            // I_CmsUserDriver#removeAccessControlEntriesForPrincipal(CmsDbContext, CmsProject, CmsProject, CmsUUID)
7655            // expects an offline project, if not, data will become inconsistent
7656
7657            // if the current project is the online project, check if there is a valid offline project at all
7658            List<CmsProject> projects = m_driverManager.getProjectDriver(dbc).readProjects(dbc, "");
7659            for (CmsProject project : projects) {
7660                if (!project.isOnlineProject()) {
7661                    try {
7662                        dbc.setProjectId(project.getUuid());
7663                        if (null != m_driverManager.readResource(dbc, "/", CmsResourceFilter.ALL)) {
7664                            // shallow clone the context with project adjusted
7665                            context = new CmsRequestContext(
7666                                context.getCurrentUser(),
7667                                project,
7668                                context.getUri(),
7669                                context.getRequestMatcher(),
7670                                context.getSiteRoot(),
7671                                context.isSecureRequest(),
7672                                context.getLocale(),
7673                                context.getEncoding(),
7674                                context.getRemoteAddress(),
7675                                context.getRequestTime(),
7676                                context.getDirectoryTranslator(),
7677                                context.getFileTranslator(),
7678                                context.getOuFqn(),
7679                                context.isForceAbsoluteLinks());
7680                            dbc = m_dbContextFactory.getDbContext(context);
7681                            projectId = dbc.getProjectId();
7682                            break;
7683                        }
7684                    } catch (Exception e) {
7685                        // ignore
7686                    }
7687                }
7688            }
7689        }
7690        dbc.setProjectId(projectId);
7691        return dbc;
7692    }
7693
7694}