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