001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://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.file;
029
030import org.opencms.db.CmsDbEntryNotFoundException;
031import org.opencms.db.CmsModificationContext;
032import org.opencms.db.CmsPublishedResource;
033import org.opencms.db.CmsResourceState;
034import org.opencms.db.CmsSecurityManager;
035import org.opencms.db.log.CmsLogEntry;
036import org.opencms.db.log.CmsLogFilter;
037import org.opencms.db.storage.I_CmsStorageDelivery;
038import org.opencms.db.urlname.CmsUrlNameMappingEntry;
039import org.opencms.db.urlname.CmsUrlNameMappingFilter;
040import org.opencms.file.CmsResource.CmsResourceDeleteMode;
041import org.opencms.file.history.CmsHistoryPrincipal;
042import org.opencms.file.history.CmsHistoryProject;
043import org.opencms.file.history.I_CmsHistoryResource;
044import org.opencms.file.quota.CmsFolderSizeEntry;
045import org.opencms.file.quota.CmsFolderSizeOptions;
046import org.opencms.file.types.CmsResourceTypeFolder;
047import org.opencms.file.types.CmsResourceTypePlain;
048import org.opencms.file.types.I_CmsResourceType;
049import org.opencms.i18n.CmsLocaleGroupService;
050import org.opencms.lock.CmsLock;
051import org.opencms.lock.CmsLockFilter;
052import org.opencms.lock.CmsLockType;
053import org.opencms.main.CmsException;
054import org.opencms.main.CmsIllegalArgumentException;
055import org.opencms.main.CmsLog;
056import org.opencms.main.I_CmsEventListener;
057import org.opencms.main.OpenCms;
058import org.opencms.relations.CmsRelation;
059import org.opencms.relations.CmsRelationFilter;
060import org.opencms.relations.CmsRelationType;
061import org.opencms.report.I_CmsReport;
062import org.opencms.security.CmsAccessControlEntry;
063import org.opencms.security.CmsAccessControlList;
064import org.opencms.security.CmsOrganizationalUnit;
065import org.opencms.security.CmsPermissionSet;
066import org.opencms.security.CmsPrincipal;
067import org.opencms.security.CmsRole;
068import org.opencms.security.CmsRoleViolationException;
069import org.opencms.security.CmsSecurityException;
070import org.opencms.security.I_CmsPermissionHandler;
071import org.opencms.security.I_CmsPrincipal;
072import org.opencms.security.twofactor.CmsSecondFactorInfo;
073import org.opencms.util.CmsPair;
074import org.opencms.util.CmsStringUtil;
075import org.opencms.util.CmsUUID;
076import org.opencms.xml.content.CmsNumberSuffixNameSequence;
077
078import java.io.ByteArrayInputStream;
079import java.io.OutputStream;
080import java.util.ArrayList;
081import java.util.Collections;
082import java.util.Iterator;
083import java.util.List;
084import java.util.Locale;
085import java.util.Map;
086import java.util.Set;
087import java.util.function.Predicate;
088
089import org.apache.commons.logging.Log;
090
091/**
092 * This pivotal class provides all authorized access to the OpenCms VFS resources.<p>
093 *
094 * It encapsulates user identification and permissions.
095 * Think of it as an initialized "shell" to access the OpenCms VFS.
096 * Every call to a method here will be checked for user permissions
097 * according to the <code>{@link org.opencms.file.CmsRequestContext}</code> this CmsObject instance was created with.<p>
098 *
099 * From a JSP page running in OpenCms, use <code>{@link org.opencms.jsp.CmsJspBean#getCmsObject()}</code> to gain
100 * access to the current users CmsObject. Usually this is done with a <code>{@link org.opencms.jsp.CmsJspActionElement}</code>.<p>
101 *
102 * To generate a new instance of this class in your application, use
103 * <code>{@link org.opencms.main.OpenCms#initCmsObject(String)}</code>. The argument String should be
104 * the name of the guest user, usually "Guest" and more formally obtained by <code>{@link org.opencms.db.CmsDefaultUsers#getUserGuest()}</code>.
105 * This will give you an initialized context with guest user permissions.
106 * Then use <code>{@link CmsObject#loginUser(String, String)}</code> to log in the user you want.
107 * Obviously you need the password for the new user.
108 * You should never try to create an instance of this class using the constructor,
109 * this is reserved for internal operation only.<p>
110 *
111 * @since 6.0.0
112 */
113public final class CmsObject {
114
115    /** Logger instance for this class. */
116    private static final Log LOG = CmsLog.getLog(CmsObject.class);
117
118    /** The request context. */
119    protected CmsRequestContext m_context;
120
121    /** The security manager to access the cms. */
122    protected CmsSecurityManager m_securityManager;
123
124    /**
125     * Connects an OpenCms user context to a running database.<p>
126     *
127     * <b>Please note:</b> This constructor is internal to OpenCms and not for public use.
128     * If you want to create a new instance of a <code>{@link CmsObject}</code> in your application,
129     * use <code>{@link org.opencms.main.OpenCms#initCmsObject(String)}</code>.<p>
130     *
131     * @param securityManager the security manager
132     * @param context the request context that contains the user authentication
133     */
134    public CmsObject(CmsSecurityManager securityManager, CmsRequestContext context) {
135
136        init(securityManager, context);
137    }
138
139    /**
140     * Adds a new relation to the given resource.<p>
141     *
142     * @param resource the source resource
143     * @param target the target resource
144     * @param type the type of the relation
145     *
146     * @throws CmsException if something goes wrong
147     */
148    public void addRelationToResource(CmsResource resource, CmsResource target, String type) throws CmsException {
149
150        createRelation(resource, target, type, false);
151    }
152
153    /**
154     * Adds a new relation to the given resource.<p>
155     *
156     * @param resourceName the name of the source resource
157     * @param targetPath the path of the target resource
158     * @param type the type of the relation
159     *
160     * @throws CmsException if something goes wrong
161     */
162    public void addRelationToResource(String resourceName, String targetPath, String type) throws CmsException {
163
164        createRelation(resourceName, targetPath, type, false);
165    }
166
167    /**
168     * Convenience method to add the site root from the current user's
169     * request context to the given resource name.<p>
170     *
171     * @param resourcename the resource name
172     *
173     * @return the resource name with the site root added
174     *
175     * @see CmsRequestContext#addSiteRoot(String)
176     */
177    public String addSiteRoot(String resourcename) {
178
179        return m_context.addSiteRoot(resourcename);
180    }
181
182    /**
183     * Adds a user to a group.<p>
184     *
185     * @param username the name of the user that is to be added to the group
186     * @param groupname the name of the group
187     *
188     * @throws CmsException if something goes wrong
189     */
190    public void addUserToGroup(String username, String groupname) throws CmsException {
191
192        m_securityManager.addUserToGroup(m_context, username, groupname, false);
193    }
194
195    /**
196     * This method works just like {@link CmsObject#adjustLinks(String, String)}, but you can specify multiple source
197     * files, and the target folder is interpreted as the folder into which the source files have been copied.<p>
198     *
199     * @param sourceFiles the list of source files
200     * @param targetParentFolder the folder into which the source files have been copied
201     *
202     * @throws CmsException if something goes wrong
203     */
204    public void adjustLinks(List<String> sourceFiles, String targetParentFolder) throws CmsException {
205
206        CmsObject cms = OpenCms.initCmsObject(this);
207        cms.getRequestContext().setSiteRoot("");
208        List<String> rootSourceFiles = new ArrayList<String>();
209        for (String sourceFile : sourceFiles) {
210            rootSourceFiles.add(addSiteRoot(sourceFile));
211        }
212        String rootTargetParentFolder = addSiteRoot(targetParentFolder);
213
214        CmsLinkRewriter rewriter = new CmsLinkRewriter(cms, rootSourceFiles, rootTargetParentFolder);
215        rewriter.rewriteLinks();
216    }
217
218    /**
219     * This method works just like {@link CmsObject#adjustLinks(String, String)}, but instead of specifying
220     * a single source and target folder, you can specify multiple sources and the corresponding targets in
221     * a map of strings.
222     *
223     * @param sourceTargetMap a map with the source files as keys and the corresponding targets as values
224     * @param targetParentFolder the folder into which the source files have been copied
225     *
226     * @throws CmsException if something goes wrong
227     */
228    public void adjustLinks(Map<String, String> sourceTargetMap, String targetParentFolder) throws CmsException {
229
230        CmsObject cms = OpenCms.initCmsObject(this);
231        cms.getRequestContext().setSiteRoot("");
232        List<CmsPair<String, String>> sourcesAndTargets = new ArrayList<CmsPair<String, String>>();
233        for (Map.Entry<String, String> entry : sourceTargetMap.entrySet()) {
234            String rootSource = addSiteRoot(entry.getKey());
235            String rootTarget = addSiteRoot(entry.getValue());
236            sourcesAndTargets.add(CmsPair.create(rootSource, rootTarget));
237        }
238        String rootTargetParentFolder = addSiteRoot(targetParentFolder);
239        CmsLinkRewriter rewriter = new CmsLinkRewriter(cms, rootTargetParentFolder, sourcesAndTargets);
240        rewriter.rewriteLinks();
241    }
242
243    /**
244     * Adjusts all links in the target folder that point to the source folder
245     * so that they are kept "relative" in the target folder where possible.
246     *
247     * If a link is found from the target folder to the source folder,
248     * then the target folder is checked if a target of the same name
249     * is found also "relative" inside the target Folder, and if so,
250     * the link is changed to that "relative" target. This is mainly used to keep
251     * relative links inside a copied folder structure intact.
252     *
253     * Example: Image we have folder /folderA/ that contains files
254     * /folderA/x1 and /folderA/y1. x1 has a link to y1 and y1 to x1.
255     * Now someone copies /folderA/ to /folderB/. So we end up with
256     * /folderB/x2 and /folderB/y2. Because of the link mechanism in OpenCms,
257     * x2 will have a link to y1 and y2 to x1. By using this method,
258     * the links from x2 to y1 will be replaced by a link x2 to y2,
259     * and y2 to x1 with y2 to x2.
260     *
261     * Link replacement works for links in XML files as well as relation only
262     * type links.
263     *
264     * @param sourceFolder the source folder
265     * @param targetFolder the target folder
266     *
267     * @throws CmsException if something goes wrong
268     */
269    public void adjustLinks(String sourceFolder, String targetFolder) throws CmsException {
270
271        String rootSourceFolder = addSiteRoot(sourceFolder);
272        String rootTargetFolder = addSiteRoot(targetFolder);
273        String siteRoot = getRequestContext().getSiteRoot();
274        getRequestContext().setSiteRoot("");
275        try {
276            CmsLinkRewriter linkRewriter = new CmsLinkRewriter(this, rootSourceFolder, rootTargetFolder);
277            linkRewriter.rewriteLinks();
278        } finally {
279            getRequestContext().setSiteRoot(siteRoot);
280        }
281    }
282
283    /**
284     * Changes the access control for a given resource and a given principal(user/group).<p>
285     *
286     * @param resourceName name of the resource
287     * @param principalType the type of the principal (currently group or user):
288     *      <ul>
289     *          <li><code>{@link I_CmsPrincipal#PRINCIPAL_USER}</code></li>
290     *          <li><code>{@link I_CmsPrincipal#PRINCIPAL_GROUP}</code></li>
291     *      </ul>
292     * @param principalName name of the principal
293     * @param allowedPermissions bit set of allowed permissions
294     * @param deniedPermissions bit set of denied permissions
295     * @param flags additional flags of the access control entry
296     *
297     * @throws CmsException if something goes wrong
298     */
299    public void chacc(
300        String resourceName,
301        String principalType,
302        String principalName,
303        int allowedPermissions,
304        int deniedPermissions,
305        int flags)
306    throws CmsException {
307
308        CmsResource res = readResource(resourceName, CmsResourceFilter.ALL);
309
310        CmsAccessControlEntry acEntry = null;
311        try {
312            I_CmsPrincipal principal = CmsPrincipal.readPrincipal(this, principalType, principalName);
313            acEntry = new CmsAccessControlEntry(
314                res.getResourceId(),
315                principal.getId(),
316                allowedPermissions,
317                deniedPermissions,
318                flags);
319            acEntry.setFlagsForPrincipal(principal);
320        } catch (CmsDbEntryNotFoundException e) {
321            // check for special ids
322            if (principalName.equalsIgnoreCase(CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_NAME)) {
323                acEntry = new CmsAccessControlEntry(
324                    res.getResourceId(),
325                    CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_ID,
326                    allowedPermissions,
327                    deniedPermissions,
328                    flags);
329                acEntry.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_ALLOTHERS);
330            } else if (principalName.equalsIgnoreCase(CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_NAME)) {
331                acEntry = new CmsAccessControlEntry(
332                    res.getResourceId(),
333                    CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID,
334                    allowedPermissions,
335                    deniedPermissions,
336                    flags);
337                acEntry.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE_ALL);
338            } else if (principalType.equalsIgnoreCase(CmsRole.PRINCIPAL_ROLE)) {
339                // only vfs managers can set role based permissions
340                m_securityManager.checkRoleForResource(m_context, CmsRole.VFS_MANAGER, res);
341                // check for role
342                CmsRole role = CmsRole.valueOfRoleName(principalName);
343                // role based permissions can only be set in the system folder
344                if (role == null) {
345                    throw e;
346                }
347                acEntry = new CmsAccessControlEntry(
348                    res.getResourceId(),
349                    role.getId(),
350                    allowedPermissions,
351                    deniedPermissions,
352                    flags);
353                acEntry.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_ROLE);
354            } else {
355                throw e;
356            }
357        }
358
359        m_securityManager.writeAccessControlEntry(m_context, res, acEntry);
360    }
361
362    /**
363     * Changes the access control for a given resource and a given principal(user/group).<p>
364     *
365     * @param resourceName name of the resource
366     * @param principalType the type of the principal (group or user):
367     *      <ul>
368     *          <li><code>{@link I_CmsPrincipal#PRINCIPAL_USER}</code></li>
369     *          <li><code>{@link I_CmsPrincipal#PRINCIPAL_GROUP}</code></li>
370     *      </ul>
371     * @param principalName name of the principal
372     * @param permissionString the permissions in the format ((+|-)(r|w|v|c|i|o))*
373     *
374     * @throws CmsException if something goes wrong
375     */
376    public void chacc(String resourceName, String principalType, String principalName, String permissionString)
377    throws CmsException {
378
379        CmsResource res = readResource(resourceName, CmsResourceFilter.ALL);
380
381        CmsAccessControlEntry acEntry = null;
382        try {
383            I_CmsPrincipal principal = CmsPrincipal.readPrincipal(this, principalType, principalName);
384            acEntry = new CmsAccessControlEntry(res.getResourceId(), principal.getId(), permissionString);
385            acEntry.setFlagsForPrincipal(principal);
386        } catch (CmsDbEntryNotFoundException e) {
387            // check for special ids
388            if (principalName.equalsIgnoreCase(CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_NAME)) {
389                acEntry = new CmsAccessControlEntry(
390                    res.getResourceId(),
391                    CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_ID,
392                    permissionString);
393                acEntry.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_ALLOTHERS);
394            } else if (principalName.equalsIgnoreCase(CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_NAME)) {
395                acEntry = new CmsAccessControlEntry(
396                    res.getResourceId(),
397                    CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID,
398                    permissionString);
399                acEntry.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE_ALL);
400            } else if (principalType.equalsIgnoreCase(CmsRole.PRINCIPAL_ROLE)) {
401                // only vfs managers can set role based permissions
402                m_securityManager.checkRoleForResource(m_context, CmsRole.VFS_MANAGER, res);
403                // check for role
404                CmsRole role = CmsRole.valueOfRoleName(principalName);
405                // role based permissions can only be set in the system folder
406                if (role == null) {
407                    throw e;
408                }
409                acEntry = new CmsAccessControlEntry(res.getResourceId(), role.getId(), permissionString);
410                acEntry.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_ROLE);
411            } else {
412                throw e;
413            }
414        }
415
416        m_securityManager.writeAccessControlEntry(m_context, res, acEntry);
417    }
418
419    /**
420     * Changes the lock of a resource to the current user,
421     * that is "steals" the lock from another user.<p>
422     *
423     * This is the "steal lock" operation.<p>
424     *
425     * @param resource the resource to change the lock
426     *
427     * @throws CmsException if something goes wrong
428     */
429    public void changeLock(CmsResource resource) throws CmsException {
430
431        getResourceType(resource).changeLock(this, m_securityManager, resource);
432    }
433
434    /**
435     * Changes the lock of a resource to the current user,
436     * that is "steals" the lock from another user.<p>
437     *
438     * This is the "steal lock" operation.<p>
439     *
440     * @param resourcename the name of the resource to change the lock with complete path
441     *
442     * @throws CmsException if something goes wrong
443     */
444    public void changeLock(String resourcename) throws CmsException {
445
446        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
447        changeLock(resource);
448    }
449
450    /**
451     * Returns a list with all sub resources of a given folder that have set the given property,
452     * matching the current property's value with the given old value and replacing it by a given new value.<p>
453     *
454     * @param resourcename the name of the resource to change the property value
455     * @param property the name of the property to change the value
456     * @param oldValue the old value of the property, can be a regular expression
457     * @param newValue the new value of the property
458     * @param recursive if true, change recursively all property values on sub-resources (only for folders)
459     *
460     * @return a list with the <code>{@link CmsResource}</code>'s where the property value has been changed
461     *
462     * @throws CmsException if operation was not successful
463     */
464    public List<CmsResource> changeResourcesInFolderWithProperty(
465        String resourcename,
466        String property,
467        String oldValue,
468        String newValue,
469        boolean recursive)
470    throws CmsException {
471
472        CmsResource resource = readResource(resourcename, CmsResourceFilter.IGNORE_EXPIRATION);
473        return m_securityManager.changeResourcesInFolderWithProperty(
474            m_context,
475            resource,
476            property,
477            oldValue,
478            newValue,
479            recursive);
480    }
481
482    /**
483     * Checks if a login for the given user name and password would work without taking two-factor authentication into account.
484     *
485     * If this succeeds, it does not actually log the CmsObject in. But if it fails, it throws an exception and increments
486     * the failed login counter for the given user.
487     *
488     * @param userName the user name to check
489     * @param password the password to check
490     * @throws CmsException if the login check fails
491     */
492    public void checkLoginUser(String userName, String password) throws CmsException {
493
494        m_securityManager.checkLogin(m_context, userName, password, m_context.getRemoteAddress());
495
496    }
497
498    /**
499     * Changes the resource flags of a resource.<p>
500     *
501     * The resource flags are used to indicate various "special" conditions
502     * for a resource. Most notably, the "internal only" setting which signals
503     * that a resource can not be directly requested with it's URL.<p>
504     *
505     * @param resourcename the name of the resource to change the flags for (full current site relative path)
506     * @param flags the new flags for this resource
507     *
508     * @throws CmsException if something goes wrong
509     */
510    public void chflags(String resourcename, int flags) throws CmsException {
511
512        CmsResource resource = readResource(resourcename, CmsResourceFilter.IGNORE_EXPIRATION);
513        getResourceType(resource).chflags(this, m_securityManager, resource, flags);
514    }
515
516    /**
517     * Changes the resource type of a resource.<p>
518     *
519     * OpenCms handles resources according to the resource type,
520     * not the file suffix. This is e.g. why a JSP in OpenCms can have the
521     * suffix ".html" instead of ".jsp" only. Changing the resource type
522     * makes sense e.g. if you want to make a plain text file a JSP resource,
523     * or a binary file an image, etc.<p>
524     *
525     * @param resource the resource whose type should be changed
526     * @param type the new resource type for this resource
527     *
528     * @throws CmsException if something goes wrong
529     */
530    public void chtype(CmsResource resource, I_CmsResourceType type) throws CmsException {
531
532        getResourceType(resource).chtype(this, m_securityManager, resource, type);
533    }
534
535    /**
536     * Changes the resource type of a resource.<p>
537     *
538     * OpenCms handles resources according to the resource type,
539     * not the file suffix. This is e.g. why a JSP in OpenCms can have the
540     * suffix ".html" instead of ".jsp" only. Changing the resource type
541     * makes sense e.g. if you want to make a plain text file a JSP resource,
542     * or a binary file an image, etc.<p>
543     *
544     * @param resourcename the name of the resource to change the type for (full current site relative path)
545     * @param type the new resource type for this resource
546     *
547     * @throws CmsException if something goes wrong
548     */
549    public void chtype(String resourcename, I_CmsResourceType type) throws CmsException {
550
551        CmsResource resource = readResource(resourcename, CmsResourceFilter.IGNORE_EXPIRATION);
552        getResourceType(resource).chtype(this, m_securityManager, resource, type);
553    }
554
555    /**
556     * Changes the resource type of a resource.<p>
557     *
558     * OpenCms handles resources according to the resource type,
559     * not the file suffix. This is e.g. why a JSP in OpenCms can have the
560     * suffix ".html" instead of ".jsp" only. Changing the resource type
561     * makes sense e.g. if you want to make a plain text file a JSP resource,
562     * or a binary file an image, etc.<p>
563     *
564     * @param resourcename the name of the resource to change the type for (full current site relative path)
565     * @param type the new resource type for this resource
566     *
567     * @throws CmsException if something goes wrong
568     *
569     * @deprecated
570     * Use {@link #chtype(String, I_CmsResourceType)} instead.
571     * Resource types should always be referenced either by its type class (preferred) or by type name.
572     * Use of int based resource type references will be discontinued in a future OpenCms release.
573     */
574    @Deprecated
575    public void chtype(String resourcename, int type) throws CmsException {
576
577        chtype(resourcename, getResourceType(type));
578    }
579
580    /**
581     * Copies a resource.<p>
582     *
583     * The copied resource will always be locked to the current user
584     * after the copy operation.<p>
585     *
586     * Siblings will be treated according to the
587     * <code>{@link org.opencms.file.CmsResource#COPY_PRESERVE_SIBLING}</code> mode.<p>
588     *
589     * @param source the name of the resource to copy (full current site relative path)
590     * @param destination the name of the copy destination (full current site relative path)
591     *
592     * @throws CmsException if something goes wrong
593     * @throws CmsIllegalArgumentException if the <code>destination</code> argument is null or of length 0
594     *
595     * @see #copyResource(String, String, CmsResource.CmsResourceCopyMode)
596     */
597    public void copyResource(String source, String destination) throws CmsException, CmsIllegalArgumentException {
598
599        copyResource(source, destination, CmsResource.COPY_PRESERVE_SIBLING);
600    }
601
602    /**
603     * Copies a resource.<p>
604     *
605     * The copied resource will always be locked to the current user
606     * after the copy operation.<p>
607     *
608     * The <code>siblingMode</code> parameter controls how to handle siblings
609     * during the copy operation.<br>
610     * Possible values for this parameter are: <br>
611     * <ul>
612     * <li><code>{@link CmsResource#COPY_AS_NEW}</code></li>
613     * <li><code>{@link CmsResource#COPY_AS_SIBLING}</code></li>
614     * <li><code>{@link CmsResource#COPY_PRESERVE_SIBLING}</code></li>
615     * </ul><p>
616     *
617     * @param source the name of the resource to copy (full current site relative path)
618     * @param destination the name of the copy destination (full current site relative path)
619     * @param siblingMode indicates how to handle siblings during copy
620     *
621     * @throws CmsException if something goes wrong
622     * @throws CmsIllegalArgumentException if the <code>destination</code> argument is null or of length 0
623     */
624    public void copyResource(String source, String destination, CmsResource.CmsResourceCopyMode siblingMode)
625    throws CmsException, CmsIllegalArgumentException {
626
627        CmsResource resource = readResource(source, CmsResourceFilter.IGNORE_EXPIRATION);
628        getResourceType(resource).copyResource(this, m_securityManager, resource, destination, siblingMode);
629    }
630
631    /**
632     * Copies a resource to the current project of the user.<p>
633     *
634     * This is used to extend the current users project with the
635     * specified resource, in case that the resource is not yet part of the project.
636     * The resource is not really copied like in a regular copy operation,
637     * it is in fact only "enabled" in the current users project.<p>
638     *
639     * @param resource the resource to copy to the current project
640     *
641     * @throws CmsException if something goes wrong
642     */
643    public void copyResourceToProject(CmsResource resource) throws CmsException {
644
645        getResourceType(resource).copyResourceToProject(this, m_securityManager, resource);
646    }
647
648    /**
649     * Copies a resource to the current project of the user.<p>
650     *
651     * This is used to extend the current users project with the
652     * specified resource, in case that the resource is not yet part of the project.
653     * The resource is not really copied like in a regular copy operation,
654     * it is in fact only "enabled" in the current users project.<p>
655     *
656     * @param resourcename the name of the resource to copy to the current project (full current site relative path)
657     *
658     * @throws CmsException if something goes wrong
659     */
660    public void copyResourceToProject(String resourcename) throws CmsException {
661
662        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
663        copyResourceToProject(resource);
664    }
665
666    /**
667     * Counts the locked resources in a project.<p>
668     *
669     * @param id the id of the project
670     *
671     * @return the number of locked resources in this project
672     *
673     * @throws CmsException if operation was not successful
674     */
675    public int countLockedResources(CmsUUID id) throws CmsException {
676
677        return m_securityManager.countLockedResources(m_context, id);
678    }
679
680    /**
681     * Copies access control entries of a given resource to another resource.<p>
682     *
683     * Already existing access control entries of the destination resource are removed.<p>
684     *
685     * @param sourceName the name of the resource of which the access control entries are copied
686     * @param destName the name of the resource to which the access control entries are applied
687     *
688     * @throws CmsException if something goes wrong
689     */
690    public void cpacc(String sourceName, String destName) throws CmsException {
691
692        CmsResource source = readResource(sourceName);
693        CmsResource dest = readResource(destName);
694        m_securityManager.copyAccessControlEntries(m_context, source, dest);
695    }
696
697    /**
698     * Creates a new user group.<p>
699     *
700     * @param groupFqn the name of the new group
701     * @param description the description of the new group
702     * @param flags the flags for the new group
703     * @param parent the parent group (or <code>null</code>)
704     *
705     * @return a <code>{@link CmsGroup}</code> object representing the newly created group
706     *
707     * @throws CmsException if operation was not successful
708     */
709    public CmsGroup createGroup(String groupFqn, String description, int flags, String parent) throws CmsException {
710
711        return m_securityManager.createGroup(m_context, groupFqn, description, flags, parent);
712    }
713
714    /**
715     * Creates a new project.<p>
716     *
717     * @param name the name of the project to create
718     * @param description the description for the new project
719     * @param groupname the name of the project user group
720     * @param managergroupname the name of the project manager group
721     *
722     * @return the created project
723     *
724     * @throws CmsException if something goes wrong
725     */
726    public CmsProject createProject(String name, String description, String groupname, String managergroupname)
727    throws CmsException {
728
729        return m_securityManager.createProject(
730            m_context,
731            name,
732            description,
733            groupname,
734            managergroupname,
735            CmsProject.PROJECT_TYPE_NORMAL);
736    }
737
738    /**
739     * Creates a new project.<p>
740     *
741     * @param name the name of the project to create
742     * @param description the description for the new project
743     * @param groupname the name of the project user group
744     * @param managergroupname the name of the project manager group
745     * @param projecttype the type of the project (normal or temporary)
746     *
747     * @return the created project
748     *
749     * @throws CmsException if operation was not successful
750     */
751    public CmsProject createProject(
752        String name,
753        String description,
754        String groupname,
755        String managergroupname,
756        CmsProject.CmsProjectType projecttype)
757    throws CmsException {
758
759        return m_securityManager.createProject(m_context, name, description, groupname, managergroupname, projecttype);
760    }
761
762    /**
763     * Creates a property definition.<p>
764     *
765     * Property definitions are valid for all resource types.<p>
766     *
767     * @param name the name of the property definition to create
768     *
769     * @return the created property definition
770     *
771     * @throws CmsException if something goes wrong
772     */
773    public CmsPropertyDefinition createPropertyDefinition(String name) throws CmsException {
774
775        return (m_securityManager.createPropertyDefinition(m_context, name));
776    }
777
778    /**
779     * Creates a resource with the given properties and content.
780     * Will throw an exception, if a resource with the given name already exists.<p>
781     *
782     * @param sitePath the site path for the resource
783     * @param resource the resource object to be imported
784     * @param content the content of the resource
785     * @param properties the properties of the resource
786     *
787     * @return the imported resource
788     *
789     * @throws CmsException if something goes wrong
790     */
791    public CmsResource createResource(
792        String sitePath,
793        CmsResource resource,
794        byte[] content,
795        List<CmsProperty> properties)
796    throws CmsException {
797
798        resource.setUserLastModified(getRequestContext().getCurrentUser().getId());
799        resource.setDateLastModified(System.currentTimeMillis());
800        // ensure resource record is updated
801        resource.setState(CmsResource.STATE_NEW);
802        return m_securityManager.createResource(
803            m_context,
804            m_context.addSiteRoot(sitePath),
805            resource,
806            content,
807            properties);
808    }
809
810    /**
811     * Creates a new resource of the given resource type with
812     * empty content and no properties.<p>
813     *
814     * @param resourcename the name of the resource to create (full current site relative path)
815     * @param type the type of the resource to create
816     *
817     * @return the created resource
818     *
819     * @throws CmsException if something goes wrong
820     * @throws CmsIllegalArgumentException if the given <code>resourcename</code> is null or of length 0
821     *
822     * @see #createResource(String, int, byte[], List)
823     */
824    public CmsResource createResource(String resourcename, I_CmsResourceType type)
825    throws CmsException, CmsIllegalArgumentException {
826
827        return createResource(resourcename, type, new byte[0], new ArrayList<CmsProperty>(0));
828    }
829
830    /**
831     * Creates a new resource of the given resource type
832     * with the provided content and properties.<p>
833     *
834     * @param resourcename the name of the resource to create (full current site relative path)
835     * @param type the type of the resource to create
836     * @param content the contents for the new resource
837     * @param properties the properties for the new resource
838     *
839     * @return the created resource
840     *
841     * @throws CmsException if something goes wrong
842     * @throws CmsIllegalArgumentException if the <code>resourcename</code> argument is null or of length 0
843     */
844    public CmsResource createResource(
845        String resourcename,
846        I_CmsResourceType type,
847        byte[] content,
848        List<CmsProperty> properties)
849    throws CmsException, CmsIllegalArgumentException {
850
851        return type.createResource(this, m_securityManager, resourcename, content, properties);
852    }
853
854    /**
855     * Creates a new resource of the given resource type with
856     * empty content and no properties.<p>
857     *
858     * @param resourcename the name of the resource to create (full current site relative path)
859     * @param type the type of the resource to create
860     *
861     * @return the created resource
862     *
863     * @throws CmsException if something goes wrong
864     * @throws CmsIllegalArgumentException if the given <code>resourcename</code> is null or of length 0
865     *
866     * @see #createResource(String, int, byte[], List)
867     *
868     * @deprecated
869     * Use {@link #createResource(String, I_CmsResourceType)} instead.
870     * Resource types should always be referenced either by its type class (preferred) or by type name.
871     * Use of int based resource type references will be discontinued in a future OpenCms release.
872     */
873    @Deprecated
874    public CmsResource createResource(String resourcename, int type) throws CmsException, CmsIllegalArgumentException {
875
876        return createResource(resourcename, getResourceType(type), new byte[0], new ArrayList<CmsProperty>(0));
877    }
878
879    /**
880     * Creates a new resource of the given resource type
881     * with the provided content and properties.<p>
882     *
883     * @param resourcename the name of the resource to create (full current site relative path)
884     * @param type the type of the resource to create
885     * @param content the contents for the new resource
886     * @param properties the properties for the new resource
887     *
888     * @return the created resource
889     *
890     * @throws CmsException if something goes wrong
891     * @throws CmsIllegalArgumentException if the <code>resourcename</code> argument is null or of length 0
892     *
893     * @deprecated
894     * Use {@link #createResource(String, I_CmsResourceType, byte[], List)} instead.
895     * Resource types should always be referenced either by its type class (preferred) or by type name.
896     * Use of int based resource type references will be discontinued in a future OpenCms release.
897     */
898    @Deprecated
899    public CmsResource createResource(String resourcename, int type, byte[] content, List<CmsProperty> properties)
900    throws CmsException, CmsIllegalArgumentException {
901
902        return createResource(resourcename, getResourceType(type), content, properties);
903    }
904
905    /**
906     * Creates a new sibling of the source resource.<p>
907     *
908     * @param source the name of the resource to create a sibling for with complete path
909     * @param destination the name of the sibling to create with complete path
910     * @param properties the individual properties for the new sibling
911     *
912     * @return the new created sibling
913     *
914     * @throws CmsException if something goes wrong
915     */
916    public CmsResource createSibling(String source, String destination, List<CmsProperty> properties)
917    throws CmsException {
918
919        CmsResource resource = readResource(source, CmsResourceFilter.IGNORE_EXPIRATION);
920        return getResourceType(resource).createSibling(this, m_securityManager, resource, destination, properties);
921    }
922
923    /**
924     * Creates the project for the temporary workplace files.<p>
925     *
926     * @return the created project for the temporary workplace files
927     *
928     * @throws CmsException if something goes wrong
929     */
930    public CmsProject createTempfileProject() throws CmsException {
931
932        return m_securityManager.createTempfileProject(m_context);
933    }
934
935    /**
936     * Creates a new user.<p>
937     *
938     * @param userFqn the name for the new user
939     * @param password the password for the new user
940     * @param description the description for the new user
941     * @param additionalInfos the additional infos for the user
942     *
943     * @return the created user
944     *
945     * @throws CmsException if something goes wrong
946     */
947    public CmsUser createUser(String userFqn, String password, String description, Map<String, Object> additionalInfos)
948    throws CmsException {
949
950        return m_securityManager.createUser(m_context, userFqn, password, description, additionalInfos);
951    }
952
953    /**
954     * Deletes all published resource entries.<p>
955     *
956     * @param linkType the type of resource deleted (0= non-parameter, 1=parameter)
957     *
958     * @throws CmsException if something goes wrong
959     */
960    public void deleteAllStaticExportPublishedResources(int linkType) throws CmsException {
961
962        m_securityManager.deleteAllStaticExportPublishedResources(m_context, linkType);
963    }
964
965    /**
966     * Deletes a group, where all permissions, users and children of the group
967     * are transfered to a replacement group.<p>
968     *
969     * @param groupId the id of the group to be deleted
970     * @param replacementId the id of the group to be transfered, can be <code>null</code>
971     *
972     * @throws CmsException if operation was not successful
973     */
974    public void deleteGroup(CmsUUID groupId, CmsUUID replacementId) throws CmsException {
975
976        m_securityManager.deleteGroup(m_context, groupId, replacementId);
977    }
978
979    /**
980     * Deletes a user group.<p>
981     *
982     * Only groups that contain no subgroups can be deleted.<p>
983     *
984     * @param group the name of the group
985     *
986     * @throws CmsException if operation was not successful
987     */
988    public void deleteGroup(String group) throws CmsException {
989
990        m_securityManager.deleteGroup(m_context, group);
991    }
992
993    /**
994     * Deletes the versions from the history tables, keeping the given number of versions per resource.<p>
995     *
996     * @param versionsToKeep number of versions to keep, is ignored if negative
997     * @param versionsDeleted number of versions to keep for deleted resources, is ignored if negative
998     * @param timeDeleted deleted resources older than this will also be deleted, is ignored if negative
999     * @param report the report for output logging
1000     *
1001     * @throws CmsException if operation was not successful
1002     */
1003    public void deleteHistoricalVersions(int versionsToKeep, int versionsDeleted, long timeDeleted, I_CmsReport report)
1004    throws CmsException {
1005
1006        m_securityManager.deleteHistoricalVersions(
1007            m_context,
1008            versionsToKeep,
1009            versionsDeleted,
1010            timeDeleted,
1011            res -> true,
1012            report);
1013    }
1014
1015    /**
1016     * Deletes the versions from the history tables, keeping the given number of versions per resource.<p>
1017     *
1018     * @param versionsToKeep number of versions to keep, is ignored if negative
1019     * @param versionsDeleted number of versions to keep for deleted resources, is ignored if negative
1020     * @param timeDeleted deleted resources older than this will also be deleted, is ignored if negative
1021     * @param clearDeletedFilter a filter to evaluate whether a the history entry for deleted resources should be cleared
1022     * @param report the report for output logging
1023     *
1024     * @throws CmsException if operation was not successful
1025     */
1026    public void deleteHistoricalVersions(
1027        int versionsToKeep,
1028        int versionsDeleted,
1029        long timeDeleted,
1030        Predicate<I_CmsHistoryResource> clearDeletedFilter,
1031        I_CmsReport report)
1032    throws CmsException {
1033
1034        m_securityManager.deleteHistoricalVersions(
1035            m_context,
1036            versionsToKeep,
1037            versionsDeleted,
1038            timeDeleted,
1039            clearDeletedFilter,
1040            report);
1041    }
1042
1043    /**
1044     * Deletes the log entries matching the given filter.<p>
1045     *
1046     * @param filter the filter to use for deleting the log entries
1047     *
1048     * @throws CmsException if something goes wrong
1049     *
1050     * @see CmsSecurityManager#deleteLogEntries(CmsRequestContext, CmsLogFilter)
1051     * @see #getLogEntries(CmsLogFilter)
1052     */
1053    public void deleteLogEntries(CmsLogFilter filter) throws CmsException {
1054
1055        m_securityManager.deleteLogEntries(m_context, filter);
1056    }
1057
1058    /**
1059     * Deletes a project.<p>
1060     *
1061     * All resources inside the project have to be be reset to their online state.<p>
1062     *
1063     * @param id the id of the project to delete
1064     *
1065     * @throws CmsException if operation was not successful
1066     */
1067    public void deleteProject(CmsUUID id) throws CmsException {
1068
1069        m_securityManager.deleteProject(m_context, id);
1070    }
1071
1072    /**
1073     * Deletes a property definition.<p>
1074     *
1075     * @param name the name of the property definition to delete
1076     *
1077     * @throws CmsException if something goes wrong
1078     */
1079    public void deletePropertyDefinition(String name) throws CmsException {
1080
1081        m_securityManager.deletePropertyDefinition(m_context, name);
1082    }
1083
1084    /**
1085     * Deletes the relations to a given resource.<p>
1086     *
1087     * @param resource the resource to delete the relations from
1088     * @param filter the filter to use for deleting the relations
1089     *
1090     * @throws CmsException if something goes wrong
1091     */
1092    public void deleteRelationsFromResource(CmsResource resource, CmsRelationFilter filter) throws CmsException {
1093
1094        m_securityManager.deleteRelationsForResource(m_context, resource, filter);
1095    }
1096
1097    /**
1098     * Deletes the relations to a given resource.<p>
1099     *
1100     * @param resourceName the resource to delete the relations from
1101     * @param filter the filter to use for deleting the relations
1102     *
1103     * @throws CmsException if something goes wrong
1104     */
1105    public void deleteRelationsFromResource(String resourceName, CmsRelationFilter filter) throws CmsException {
1106
1107        CmsResource resource = readResource(resourceName, CmsResourceFilter.ALL);
1108        m_securityManager.deleteRelationsForResource(m_context, resource, filter);
1109    }
1110
1111    /**
1112     * Deletes a resource.<p>
1113     *
1114     * The <code>siblingMode</code> parameter controls how to handle siblings
1115     * during the delete operation.<br>
1116     * Possible values for this parameter are: <br>
1117     * <ul>
1118     * <li><code>{@link CmsResource#DELETE_REMOVE_SIBLINGS}</code></li>
1119     * <li><code>{@link CmsResource#DELETE_PRESERVE_SIBLINGS}</code></li>
1120     * </ul><p>
1121     *
1122     * @param res the resource to delete
1123     * @param deletePreserveSiblings indicates how to handle siblings of the deleted resource
1124     *
1125     * @throws CmsException if something goes wrong
1126     */
1127    public void deleteResource(CmsResource res, CmsResourceDeleteMode deletePreserveSiblings) throws CmsException {
1128
1129        getResourceType(res).deleteResource(this, m_securityManager, res, deletePreserveSiblings);
1130    }
1131
1132    /**
1133     * Deletes a resource given its name.<p>
1134     *
1135     * The <code>siblingMode</code> parameter controls how to handle siblings
1136     * during the delete operation.<br>
1137     * Possible values for this parameter are: <br>
1138     * <ul>
1139     * <li><code>{@link CmsResource#DELETE_REMOVE_SIBLINGS}</code></li>
1140     * <li><code>{@link CmsResource#DELETE_PRESERVE_SIBLINGS}</code></li>
1141     * </ul><p>
1142     *
1143     * @param resourcename the name of the resource to delete (full current site relative path)
1144     * @param siblingMode indicates how to handle siblings of the deleted resource
1145     *
1146     * @throws CmsException if something goes wrong
1147     */
1148    public void deleteResource(String resourcename, CmsResource.CmsResourceDeleteMode siblingMode) throws CmsException {
1149
1150        // throw the exception if resource name is an empty string
1151        if (CmsStringUtil.isEmptyOrWhitespaceOnly(resourcename)) {
1152            throw new CmsVfsResourceNotFoundException(
1153                Messages.get().container(Messages.ERR_DELETE_RESOURCE_1, resourcename));
1154        }
1155
1156        CmsResource resource = readResource(resourcename, CmsResourceFilter.IGNORE_EXPIRATION);
1157        getResourceType(resource).deleteResource(this, m_securityManager, resource, siblingMode);
1158    }
1159
1160    /**
1161     * Deletes a published resource entry.<p>
1162     *
1163     * @param resourceName The name of the resource to be deleted in the static export
1164     * @param linkType the type of resource deleted (0= non-parameter, 1=parameter)
1165     * @param linkParameter the parameters of the resource
1166     *
1167     * @throws CmsException if something goes wrong
1168     */
1169    public void deleteStaticExportPublishedResource(String resourceName, int linkType, String linkParameter)
1170    throws CmsException {
1171
1172        m_securityManager.deleteStaticExportPublishedResource(m_context, resourceName, linkType, linkParameter);
1173    }
1174
1175    /**
1176     * Deletes a user.<p>
1177     *
1178     * @param userId the id of the user to be deleted
1179     *
1180     * @throws CmsException if operation was not successful
1181     */
1182    public void deleteUser(CmsUUID userId) throws CmsException {
1183
1184        m_securityManager.deleteUser(m_context, userId);
1185    }
1186
1187    /**
1188     * Deletes a user, where all permissions and resources attributes of the user
1189     * were transfered to a replacement user.<p>
1190     *
1191     * @param userId the id of the user to be deleted
1192     * @param replacementId the id of the user to be transfered, can be <code>null</code>
1193     *
1194     * @throws CmsException if operation was not successful
1195     */
1196    public void deleteUser(CmsUUID userId, CmsUUID replacementId) throws CmsException {
1197
1198        m_securityManager.deleteUser(m_context, userId, replacementId);
1199    }
1200
1201    /**
1202     * Deletes a user.<p>
1203     *
1204     * @param username the name of the user to be deleted
1205     *
1206     * @throws CmsException if operation was not successful
1207     */
1208    public void deleteUser(String username) throws CmsException {
1209
1210        m_securityManager.deleteUser(m_context, username);
1211    }
1212
1213    /**
1214     * Checks the availability of a resource in the VFS,
1215     * using the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
1216     *
1217     * A resource may be of type <code>{@link CmsFile}</code> or
1218     * <code>{@link CmsFolder}</code>.<p>
1219     *
1220     * This method also takes into account the user permissions, so if
1221     * the given resource exists, but the current user has not the required
1222     * permissions, then this method will return <code>false</code>.<p>
1223     *
1224     * @param structureId the structure id of the resource to check
1225     *
1226     * @return <code>true</code> if the resource is available
1227     *
1228     * @see #readResource(CmsUUID)
1229     * @see #existsResource(CmsUUID, CmsResourceFilter)
1230     */
1231    public boolean existsResource(CmsUUID structureId) {
1232
1233        return existsResource(structureId, CmsResourceFilter.DEFAULT);
1234    }
1235
1236    /**
1237     * Checks the availability of a resource in the VFS,
1238     * using the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
1239     *
1240     * A resource may be of type <code>{@link CmsFile}</code> or
1241     * <code>{@link CmsFolder}</code>.<p>
1242     *
1243     * The specified filter controls what kind of resources should be "found"
1244     * during the read operation. This will depend on the application. For example,
1245     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
1246     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
1247     * will ignore the date release / date expired information of the resource.<p>
1248     *
1249     * This method also takes into account the user permissions, so if
1250     * the given resource exists, but the current user has not the required
1251     * permissions, then this method will return <code>false</code>.<p>
1252     *
1253     * @param structureId the structure id of the resource to check
1254     * @param filter the resource filter to use while checking
1255     *
1256     * @return <code>true</code> if the resource is available
1257     *
1258     * @see #readResource(CmsUUID)
1259     * @see #readResource(CmsUUID, CmsResourceFilter)
1260     */
1261    public boolean existsResource(CmsUUID structureId, CmsResourceFilter filter) {
1262
1263        return m_securityManager.existsResource(m_context, structureId, filter);
1264    }
1265
1266    /**
1267     * Checks the availability of a resource in the VFS,
1268     * using the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
1269     *
1270     * A resource may be of type <code>{@link CmsFile}</code> or
1271     * <code>{@link CmsFolder}</code>.<p>
1272     *
1273     * This method also takes into account the user permissions, so if
1274     * the given resource exists, but the current user has not the required
1275     * permissions, then this method will return <code>false</code>.<p>
1276     *
1277     * @param resourcename the name of the resource to check (full current site relative path)
1278     *
1279     * @return <code>true</code> if the resource is available
1280     *
1281     * @see #readResource(String)
1282     * @see #existsResource(String, CmsResourceFilter)
1283     */
1284    public boolean existsResource(String resourcename) {
1285
1286        return existsResource(resourcename, CmsResourceFilter.DEFAULT);
1287    }
1288
1289    /**
1290     * Checks the availability of a resource in the VFS,
1291     * using the provided filter.<p>
1292     *
1293     * A resource may be of type <code>{@link CmsFile}</code> or
1294     * <code>{@link CmsFolder}</code>.<p>
1295     *
1296     * The specified filter controls what kind of resources should be "found"
1297     * during the read operation. This will depend on the application. For example,
1298     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
1299     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
1300     * will ignore the date release / date expired information of the resource.<p>
1301     *
1302     * This method also takes into account the user permissions, so if
1303     * the given resource exists, but the current user has not the required
1304     * permissions, then this method will return <code>false</code>.<p>
1305     *
1306     * @param resourcename the name of the resource to check (full current site relative path)
1307     * @param filter the resource filter to use while checking
1308     *
1309     * @return <code>true</code> if the resource is available
1310     *
1311     * @see #readResource(String)
1312     * @see #readResource(String, CmsResourceFilter)
1313     */
1314    public boolean existsResource(String resourcename, CmsResourceFilter filter) {
1315
1316        return m_securityManager.existsResource(m_context, addSiteRoot(resourcename), filter);
1317    }
1318
1319    /**
1320     * Returns the list of access control entries of a resource given its name.<p>
1321     *
1322     * @param resourceName the name of the resource
1323     *
1324     * @return a list of <code>{@link CmsAccessControlEntry}</code> objects
1325     *
1326     * @throws CmsException if something goes wrong
1327     */
1328    public List<CmsAccessControlEntry> getAccessControlEntries(String resourceName) throws CmsException {
1329
1330        return getAccessControlEntries(resourceName, true);
1331    }
1332
1333    /**
1334     * Returns the list of access control entries of a resource given its name.<p>
1335     *
1336     * @param resourceName the name of the resource
1337     * @param getInherited <code>true</code>, if inherited access control entries should be returned, too
1338     *
1339     * @return a list of <code>{@link CmsAccessControlEntry}</code> objects defining all permissions for the given resource
1340     *
1341     * @throws CmsException if something goes wrong
1342     */
1343    public List<CmsAccessControlEntry> getAccessControlEntries(String resourceName, boolean getInherited)
1344    throws CmsException {
1345
1346        CmsResource res = readResource(resourceName, CmsResourceFilter.ALL);
1347        return m_securityManager.getAccessControlEntries(m_context, res, getInherited);
1348    }
1349
1350    /**
1351     * Returns the access control list (summarized access control entries) of a given resource.<p>
1352     *
1353     * @param resourceName the name of the resource
1354     *
1355     * @return the access control list of the resource
1356     *
1357     * @throws CmsException if something goes wrong
1358     */
1359    public CmsAccessControlList getAccessControlList(String resourceName) throws CmsException {
1360
1361        return getAccessControlList(resourceName, false);
1362    }
1363
1364    /**
1365     * Returns the access control list (summarized access control entries) of a given resource.<p>
1366     *
1367     * If <code>inheritedOnly</code> is set, only inherited access control entries are returned.<p>
1368     *
1369     * @param resourceName the name of the resource
1370     * @param inheritedOnly if set, the non-inherited entries are skipped
1371     *
1372     * @return the access control list of the resource
1373     *
1374     * @throws CmsException if something goes wrong
1375     */
1376    public CmsAccessControlList getAccessControlList(String resourceName, boolean inheritedOnly) throws CmsException {
1377
1378        CmsResource res = readResource(resourceName, CmsResourceFilter.ALL);
1379        return m_securityManager.getAccessControlList(m_context, res, inheritedOnly);
1380    }
1381
1382    /**
1383     * Gets all access control entries for the current project.<p>
1384     *
1385     * @return the list of all access control entries
1386     *
1387     * @throws CmsException if something goes wrong
1388     */
1389    public List<CmsAccessControlEntry> getAllAccessControlEntries() throws CmsException {
1390
1391        return m_securityManager.getAllAccessControlEntries(m_context);
1392    }
1393
1394    /**
1395     * Returns a list with all projects from history.<p>
1396     *
1397     * @return list of <code>{@link CmsHistoryProject}</code> objects
1398     *           with all projects from history
1399     *
1400     * @throws CmsException  if operation was not successful
1401     */
1402    public List<CmsHistoryProject> getAllHistoricalProjects() throws CmsException {
1403
1404        return m_securityManager.getAllHistoricalProjects(m_context);
1405    }
1406
1407    /**
1408     * Gets all URL names for a given structure id.<p>
1409     *
1410     * @param id the structure id
1411     * @return the list of all URL names for that structure id
1412     *
1413     * @throws CmsException if something goes wrong
1414     */
1415    public List<String> getAllUrlNames(CmsUUID id) throws CmsException {
1416
1417        return m_securityManager.readAllUrlNameMappingEntries(m_context, id);
1418    }
1419
1420    /**
1421     * Returns a list of child resources to the given resource that can not be locked by the current user.<p>
1422     *
1423     * @param resource the resource
1424     *
1425     * @return a list of child resources to the given resource that can not be locked by the current user
1426     *
1427     * @throws CmsException if something goes wrong reading the resources
1428     */
1429    public List<CmsResource> getBlockingLockedResources(CmsResource resource) throws CmsException {
1430
1431        if (resource.isFolder()) {
1432            CmsLockFilter blockingFilter = CmsLockFilter.FILTER_NON_INHERITED;
1433            blockingFilter = blockingFilter.filterNotLockableByUser(getRequestContext().getCurrentUser());
1434            return getLockedResources(resource, blockingFilter);
1435        }
1436        return Collections.<CmsResource> emptyList();
1437    }
1438
1439    /**
1440     * Returns a list of child resources to the given resource that can not be locked by the current user.<p>
1441     *
1442     * @param resourceName the resource site path
1443     *
1444     * @return a list of child resources to the given resource that can not be locked by the current user
1445     *
1446     * @throws CmsException if something goes wrong reading the resources
1447     */
1448    public List<CmsResource> getBlockingLockedResources(String resourceName) throws CmsException {
1449
1450        CmsResource resource = readResource(resourceName);
1451        return getBlockingLockedResources(resource);
1452    }
1453
1454    /**
1455     * Returns all child groups of a group.<p>
1456     *
1457     * @param groupname the name of the group
1458     * @param includeSubChildren if set also returns all sub-child groups of the given group
1459     *
1460     * @return a list of all child <code>{@link CmsGroup}</code> objects or <code>null</code>
1461     *
1462     * @throws CmsException if operation was not successful
1463     */
1464    public List<CmsGroup> getChildren(String groupname, boolean includeSubChildren) throws CmsException {
1465
1466        return m_securityManager.getChildren(m_context, groupname, includeSubChildren);
1467    }
1468
1469    /**
1470     * Returns the detail name of a resource.<p>
1471     *
1472     * The detail view URI of a content element consists of its detail page URI and the detail name returned by this
1473     * method.<p>
1474     *
1475     * @param res the resource for which the detail name should be retrieved
1476     * @param locale the locale for the detail name
1477     * @param defaultLocales the default locales for the detail name
1478     *
1479     * @return the detail name
1480     * @throws CmsException if something goes wrong
1481     */
1482    public String getDetailName(CmsResource res, Locale locale, List<Locale> defaultLocales) throws CmsException {
1483
1484        String urlName = readBestUrlName(res.getStructureId(), locale, defaultLocales);
1485        if (urlName == null) {
1486            urlName = res.getStructureId().toString();
1487        }
1488        return urlName;
1489    }
1490
1491    /**
1492     * Returns all file resources contained in a folder.<p>
1493     *
1494     * The result is filtered according to the rules of
1495     * the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
1496     *
1497     * @param resourcename the full current site relative path of the resource to return the child resources for
1498     *
1499     * @return a list of all child files as <code>{@link CmsResource}</code> objects
1500     *
1501     * @throws CmsException if something goes wrong
1502     *
1503     * @see #getFilesInFolder(String, CmsResourceFilter)
1504     */
1505    public List<CmsResource> getFilesInFolder(String resourcename) throws CmsException {
1506
1507        return getFilesInFolder(resourcename, CmsResourceFilter.DEFAULT);
1508    }
1509
1510    /**
1511     * Returns all file resources contained in a folder.<p>
1512     *
1513     * With the <code>{@link CmsResourceFilter}</code> provided as parameter
1514     * you can control if you want to include deleted, invisible or
1515     * time-invalid resources in the result.<p>
1516     *
1517     * @param resourcename the full path of the resource to return the child resources for
1518     * @param filter the resource filter to use
1519     *
1520     * @return a list of all child file as <code>{@link CmsResource}</code> objects
1521     *
1522     * @throws CmsException if something goes wrong
1523     */
1524    public List<CmsResource> getFilesInFolder(String resourcename, CmsResourceFilter filter) throws CmsException {
1525
1526        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
1527        return m_securityManager.readChildResources(m_context, resource, filter, false, true);
1528    }
1529
1530    /**
1531     * Returns all the groups the given user belongs to.<p>
1532     *
1533     * @param username the name of the user
1534     * @param directGroupsOnly if set only the direct assigned groups will be returned, if not also indirect roles
1535     *
1536     * @return a list of <code>{@link CmsGroup}</code> objects
1537     *
1538     * @throws CmsException if operation was not successful
1539     */
1540    public List<CmsGroup> getGroupsOfUser(String username, boolean directGroupsOnly) throws CmsException {
1541
1542        return getGroupsOfUser(username, directGroupsOnly, true);
1543    }
1544
1545    /**
1546     * Returns all the groups the given user belongs to.<p>
1547     *
1548     * @param username the name of the user
1549     * @param directGroupsOnly if set only the direct assigned groups will be returned, if not also indirect roles
1550     * @param includeOtherOus if to include groups of other organizational units
1551     *
1552     * @return a list of <code>{@link CmsGroup}</code> objects
1553     *
1554     * @throws CmsException if operation was not successful
1555     */
1556    public List<CmsGroup> getGroupsOfUser(String username, boolean directGroupsOnly, boolean includeOtherOus)
1557    throws CmsException {
1558
1559        return getGroupsOfUser(username, directGroupsOnly, includeOtherOus, m_context.getRemoteAddress());
1560    }
1561
1562    /**
1563     * Returns the groups of a user filtered by the specified IP address.<p>
1564     *
1565     * @param username the name of the user
1566     * @param directGroupsOnly if set only the direct assigned groups will be returned, if not also indirect roles
1567     * @param remoteAddress the IP address to filter the groups in the result list
1568     * @param includeOtherOus if to include groups of other organizational units
1569     *
1570     * @return a list of <code>{@link CmsGroup}</code> objects filtered by the specified IP address
1571     *
1572     * @throws CmsException if operation was not successful
1573     */
1574    public List<CmsGroup> getGroupsOfUser(
1575        String username,
1576        boolean directGroupsOnly,
1577        boolean includeOtherOus,
1578        String remoteAddress)
1579    throws CmsException {
1580
1581        return m_securityManager.getGroupsOfUser(
1582            m_context,
1583            username,
1584            (includeOtherOus ? "" : CmsOrganizationalUnit.getParentFqn(username)),
1585            includeOtherOus,
1586            false,
1587            directGroupsOnly,
1588            remoteAddress);
1589    }
1590
1591    /**
1592     * Creates a new locale group service.<p>
1593     *
1594     * @return a locale group service instance
1595     */
1596    public CmsLocaleGroupService getLocaleGroupService() {
1597
1598        return new CmsLocaleGroupService(this);
1599    }
1600
1601    /**
1602     * Returns the edition lock state for a specified resource.<p>
1603     *
1604     * If the resource is waiting to be publish you might get a lock of type {@link CmsLockType#PUBLISH}.<p>
1605     *
1606     * @param resource the resource to return the edition lock state for
1607     *
1608     * @return the edition lock state for the specified resource
1609     *
1610     * @throws CmsException if something goes wrong
1611     */
1612    public CmsLock getLock(CmsResource resource) throws CmsException {
1613
1614        return m_securityManager.getLock(m_context, resource);
1615    }
1616
1617    /**
1618     * Returns the lock state for a specified resource name.<p>
1619     *
1620     * If the resource is waiting to be publish you might get a lock of type {@link CmsLockType#PUBLISH}.<p>
1621     *
1622     * @param resourcename the name if the resource to get the lock state for (full current site relative path)
1623     *
1624     * @return the lock state for the specified resource
1625     *
1626     * @throws CmsException if something goes wrong
1627     */
1628    public CmsLock getLock(String resourcename) throws CmsException {
1629
1630        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
1631        return getLock(resource);
1632    }
1633
1634    /**
1635     * Returns all locked resources within a folder or matches the lock of the given resource.<p>
1636     *
1637     * @param resource the resource to check
1638     * @param filter the lock filter
1639     *
1640     * @return a list of locked resources
1641     *
1642     * @throws CmsException if operation was not successful
1643     */
1644    public List<CmsResource> getLockedResources(CmsResource resource, CmsLockFilter filter) throws CmsException {
1645
1646        return m_securityManager.getLockedResourcesObjects(m_context, resource, filter);
1647    }
1648
1649    /**
1650     * Returns all locked resources within a folder or matches the lock of the given resource.<p>
1651     *
1652     * @param resourceName the name of the resource to check
1653     * @param filter the lock filter
1654     *
1655     * @return a list of locked resource paths (relative to current site)
1656     *
1657     * @throws CmsException if operation was not successful
1658     */
1659    public List<String> getLockedResources(String resourceName, CmsLockFilter filter) throws CmsException {
1660
1661        CmsResource resource = readResource(resourceName, CmsResourceFilter.ALL);
1662        return m_securityManager.getLockedResources(m_context, resource, filter);
1663    }
1664
1665    /**
1666     * Returns all locked resources within a folder or matches the lock of the given resource, but uses a cache for resource lookup.<p>
1667     *
1668     * @param resource the resource to check
1669     * @param filter the lock filter
1670     * @param cache the cache to use for resource lookups
1671     *
1672     * @return a list of locked resources
1673     *
1674     * @throws CmsException if operation was not successful
1675     */
1676    public List<CmsResource> getLockedResourcesWithCache(
1677        CmsResource resource,
1678        CmsLockFilter filter,
1679        Map<String, CmsResource> cache)
1680    throws CmsException {
1681
1682        return m_securityManager.getLockedResourcesObjectsWithCache(m_context, resource, filter, cache);
1683    }
1684
1685    /**
1686     * Returns all log entries matching the given filter.<p>
1687     *
1688     * @param filter the filter to match the relation
1689     *
1690     * @return a list containing all log entries matching the given filter
1691     *
1692     * @throws CmsException if something goes wrong
1693     *
1694     * @see CmsSecurityManager#getLogEntries(CmsRequestContext, CmsLogFilter)
1695     * @see #deleteLogEntries(CmsLogFilter)
1696     */
1697    public List<CmsLogEntry> getLogEntries(CmsLogFilter filter) throws CmsException {
1698
1699        return m_securityManager.getLogEntries(m_context, filter);
1700    }
1701
1702    /**
1703     * Returns the name a resource would have if it were moved to the
1704     * "lost and found" folder. <p>
1705     *
1706     * In general, it is the same name as the given resource has, the only exception is
1707     * if a resource in the "lost and found" folder with the same name already exists.
1708     * In such case, a counter is added to the resource name.<p>
1709     *
1710     * @param resourcename the name of the resource to get the "lost and found" name for (full current site relative path)
1711     *
1712     * @return the tentative name of the resource inside the "lost and found" folder
1713     *
1714     * @throws CmsException if something goes wrong
1715     *
1716     * @see #moveToLostAndFound(String)
1717     */
1718    public String getLostAndFoundName(String resourcename) throws CmsException {
1719
1720        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
1721        return m_securityManager.moveToLostAndFound(m_context, resource, true);
1722    }
1723
1724    /**
1725     * Returns the parent group of a group.<p>
1726     *
1727     * @param groupname the name of the group
1728     *
1729     * @return group the parent group or <code>null</code>
1730     *
1731     * @throws CmsException if operation was not successful
1732     */
1733    public CmsGroup getParent(String groupname) throws CmsException {
1734
1735        return m_securityManager.getParent(m_context, groupname);
1736    }
1737
1738    /**
1739     * Returns the set of permissions of the current user for a given resource.<p>
1740     *
1741     * @param resourceName the name of the resource
1742     *
1743     * @return the bit set of the permissions of the current user
1744     *
1745     * @throws CmsException if something goes wrong
1746     */
1747    public CmsPermissionSet getPermissions(String resourceName) throws CmsException {
1748
1749        return getPermissions(resourceName, m_context.getCurrentUser().getName());
1750    }
1751
1752    /**
1753     * Returns the set of permissions of a given user for a given resource.<p>
1754     *
1755     * @param resourceName the name of the resource
1756     * @param userName the name of the user
1757     *
1758     * @return the current permissions on this resource
1759     *
1760     * @throws CmsException if something goes wrong
1761     */
1762    public CmsPermissionSet getPermissions(String resourceName, String userName) throws CmsException {
1763
1764        // reading permissions is allowed even if the resource is marked as deleted
1765        CmsResource resource = readResource(resourceName, CmsResourceFilter.ALL);
1766        CmsUser user = readUser(userName);
1767        return m_securityManager.getPermissions(m_context, resource, user);
1768    }
1769
1770    /**
1771     * Returns all relations for the given resource matching the given filter.<p>
1772     *
1773     * You should have view/read permissions on the given resource.<p>
1774     *
1775     * You may become source and/or target paths to resource you do not have view/read permissions on.<p>
1776     *
1777     * @param resource the resource to retrieve the relations for
1778     * @param filter the filter to match the relation
1779     *
1780     * @return a List containing all {@link org.opencms.relations.CmsRelation}
1781     *          objects for the given resource matching the given filter
1782     *
1783     * @throws CmsException if something goes wrong
1784     *
1785     * @see CmsSecurityManager#getRelationsForResource(CmsRequestContext, CmsResource, CmsRelationFilter)
1786     */
1787    public List<CmsRelation> getRelationsForResource(CmsResource resource, CmsRelationFilter filter)
1788    throws CmsException {
1789
1790        return m_securityManager.getRelationsForResource(m_context, resource, filter);
1791    }
1792
1793    /**
1794     * Returns all relations for the given resource matching the given filter.<p>
1795     *
1796     * You should have view/read permissions on the given resource.<p>
1797     *
1798     * You may become source and/or target paths to resource you do not have view/read permissions on.<p>
1799     *
1800     * @param resourceName the name of the resource to retrieve the relations for
1801     * @param filter the filter to match the relation
1802     *
1803     * @return a List containing all {@link org.opencms.relations.CmsRelation}
1804     *          objects for the given resource matching the given filter
1805     *
1806     * @throws CmsException if something goes wrong
1807     *
1808     * @see CmsSecurityManager#getRelationsForResource(CmsRequestContext, CmsResource, CmsRelationFilter)
1809     */
1810    public List<CmsRelation> getRelationsForResource(String resourceName, CmsRelationFilter filter)
1811    throws CmsException {
1812
1813        return getRelationsForResource(readResource(resourceName, CmsResourceFilter.ALL), filter);
1814    }
1815
1816    /**
1817     * Returns the current users request context.<p>
1818     *
1819     * This request context is used to authenticate the user for all
1820     * OpenCms operations. It also contains the request runtime settings, e.g.
1821     * about the current site this request was made on.<p>
1822     *
1823     * @return the current users request context
1824     */
1825    public CmsRequestContext getRequestContext() {
1826
1827        return m_context;
1828    }
1829
1830    /**
1831     * Returns all resources associated to a given principal via an ACE with the given permissions.<p>
1832     *
1833     * If the <code>includeAttr</code> flag is set it returns also all resources associated to
1834     * a given principal through some of following attributes.<p>
1835     *
1836     * <ul>
1837     *    <li>User Created</li>
1838     *    <li>User Last Modified</li>
1839     * </ul><p>
1840     *
1841     * @param principalId the id of the principal
1842     * @param permissions a set of permissions to match, can be <code>null</code> for all ACEs
1843     * @param includeAttr a flag to include resources associated by attributes
1844     *
1845     * @return a set of <code>{@link CmsResource}</code> objects
1846     *
1847     * @throws CmsException if something goes wrong
1848     */
1849    public Set<CmsResource> getResourcesForPrincipal(
1850        CmsUUID principalId,
1851        CmsPermissionSet permissions,
1852        boolean includeAttr)
1853    throws CmsException {
1854
1855        return m_securityManager.getResourcesForPrincipal(getRequestContext(), principalId, permissions, includeAttr);
1856    }
1857
1858    /**
1859     * Returns all child resources of a resource, that is the resources
1860     * contained in a folder.<p>
1861     *
1862     * With the <code>{@link CmsResourceFilter}</code> provided as parameter
1863     * you can control if you want to include deleted, invisible or
1864     * time-invalid resources in the result.<p>
1865     *
1866     * This method is mainly used by the workplace explorer.<p>
1867     *
1868     * @param resourcename the full current site relative path of the resource to return the child resources for
1869     * @param filter the resource filter to use
1870     *
1871     * @return a list of all child <code>{@link CmsResource}</code>s
1872     *
1873     * @throws CmsException if something goes wrong
1874     */
1875    public List<CmsResource> getResourcesInFolder(String resourcename, CmsResourceFilter filter) throws CmsException {
1876
1877        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
1878        return m_securityManager.readChildResources(m_context, resource, filter, true, true);
1879    }
1880
1881    /**
1882     * Adjusts the absolute resource root path for the current site.<p>
1883     *
1884     * The full root path of a resource is always available using
1885     * <code>{@link CmsResource#getRootPath()}</code>. From this name this method cuts
1886     * of the current site root using
1887     * <code>{@link CmsRequestContext#removeSiteRoot(String)}</code>.<p>
1888     *
1889     * If the resource root path does not start with the current site root,
1890     * it is left untouched.<p>
1891     *
1892     * @param resource the resource to get the adjusted site root path for
1893     *
1894     * @return the absolute resource path adjusted for the current site
1895     *
1896     * @see CmsRequestContext#removeSiteRoot(String)
1897     * @see CmsRequestContext#getSitePath(CmsResource)
1898     * @see CmsResource#getRootPath()
1899     */
1900    public String getSitePath(CmsResource resource) {
1901
1902        return m_context.getSitePath(resource);
1903    }
1904
1905    /**
1906     * Returns a delivery-capable storage backend by its stable storage identifier.<p>
1907     *
1908     * @param storage the stable storage identifier
1909     *
1910     * @return the delivery-capable storage backend, or <code>null</code> if not supported
1911     *
1912     * @throws CmsException if the delivery backend can not be resolved
1913     */
1914    public I_CmsStorageDelivery getStoredContentDelivery(String storage) throws CmsException {
1915
1916        return m_securityManager.getStoredContentDelivery(m_context, storage);
1917    }
1918
1919    /**
1920     * Returns all folder resources contained in a folder.<p>
1921     *
1922     * The result is filtered according to the rules of
1923     * the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
1924     *
1925     * @param resourcename the full current site relative path of the resource to return the child resources for.
1926     *
1927     * @return a list of all child file as <code>{@link CmsResource}</code> objects
1928     *
1929     * @throws CmsException if something goes wrong
1930     *
1931     * @see #getSubFolders(String, CmsResourceFilter)
1932     */
1933    public List<CmsResource> getSubFolders(String resourcename) throws CmsException {
1934
1935        return getSubFolders(resourcename, CmsResourceFilter.DEFAULT);
1936    }
1937
1938    /**
1939     * Returns all folder resources contained in a folder.<p>
1940     *
1941     * With the <code>{@link CmsResourceFilter}</code> provided as parameter
1942     * you can control if you want to include deleted, invisible or
1943     * time-invalid resources in the result.<p>
1944     *
1945     * @param resourcename the full current site relative path of the resource to return the child resources for.
1946     *
1947     * @return a list of all child folder <code>{@link CmsResource}</code>s
1948     * @param filter the resource filter to use
1949     *
1950     * @throws CmsException if something goes wrong
1951     */
1952    public List<CmsResource> getSubFolders(String resourcename, CmsResourceFilter filter) throws CmsException {
1953
1954        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
1955        return m_securityManager.readChildResources(m_context, resource, filter, true, false);
1956    }
1957
1958    /**
1959     * Returns the newest URL names for the given structure id for each locale.<p>
1960     *
1961     * @param id the structure id
1962     * @return the list of URL names for each locale
1963     *
1964     * @throws CmsException if something goes wrong
1965     */
1966    public List<String> getUrlNamesForAllLocales(CmsUUID id) throws CmsException {
1967
1968        return m_securityManager.readUrlNamesForAllLocales(m_context, id);
1969    }
1970
1971    /**
1972     * Returns all direct users of a given group.<p>
1973     *
1974     * Users that are "indirectly" in the group are not returned in the result.<p>
1975     *
1976     * @param groupname the name of the group to get all users for
1977     *
1978     * @return all <code>{@link CmsUser}</code> objects in the group
1979     *
1980     * @throws CmsException if operation was not successful
1981     */
1982    public List<CmsUser> getUsersOfGroup(String groupname) throws CmsException {
1983
1984        return getUsersOfGroup(groupname, true);
1985    }
1986
1987    /**
1988     * Returns all direct users of a given group.<p>
1989     *
1990     * Users that are "indirectly" in the group are not returned in the result.<p>
1991     *
1992     * @param groupname the name of the group to get all users for
1993     * @param includeOtherOus if the result should include users of other ous
1994     *
1995     * @return all <code>{@link CmsUser}</code> objects in the group
1996     *
1997     * @throws CmsException if operation was not successful
1998     */
1999    public List<CmsUser> getUsersOfGroup(String groupname, boolean includeOtherOus) throws CmsException {
2000
2001        return m_securityManager.getUsersOfGroup(m_context, groupname, includeOtherOus, true, false);
2002    }
2003
2004    /**
2005     * Checks if the current user has required permissions to access a given resource.<p>
2006     *
2007     * @param resource the resource to check the permissions for
2008     * @param requiredPermissions the set of permissions to check for
2009     *
2010     * @return <code>true</code> if the required permissions are satisfied
2011     *
2012     * @throws CmsException if something goes wrong
2013     */
2014    public boolean hasPermissions(CmsResource resource, CmsPermissionSet requiredPermissions) throws CmsException {
2015
2016        return m_securityManager.hasPermissions(
2017            m_context,
2018            resource,
2019            requiredPermissions,
2020            true,
2021            CmsResourceFilter.ALL).isAllowed();
2022    }
2023
2024    /**
2025     * Checks if the current user has required permissions to access a given resource.<p>
2026     *
2027     * @param resource the resource to check the permissions for
2028     * @param requiredPermissions the set of permissions to check for
2029     * @param checkLock if <code>true</code> the lock status of the resource is checked for write operations
2030     *      and the resource needs be locked by the current user so that the test is passed,
2031     *      if <code>false</code> the lock is not checked at all
2032     * @param filter the resource filter to use
2033     *
2034     * @return <code>true</code> if the required permissions are satisfied
2035     *
2036     * @throws CmsException if something goes wrong
2037     */
2038    public boolean hasPermissions(
2039        CmsResource resource,
2040        CmsPermissionSet requiredPermissions,
2041        boolean checkLock,
2042        CmsResourceFilter filter)
2043    throws CmsException {
2044
2045        return I_CmsPermissionHandler.PERM_ALLOWED == m_securityManager.hasPermissions(
2046            m_context,
2047            resource,
2048            requiredPermissions,
2049            checkLock,
2050            filter);
2051    }
2052
2053    /**
2054     * Writes a list of access control entries as new access control entries of a given resource.<p>
2055     *
2056     * Already existing access control entries of this resource are removed before.<p>
2057     *
2058     * @param resource the resource to attach the control entries to
2059     * @param acEntries a list of <code>{@link CmsAccessControlEntry}</code> objects
2060     *
2061     * @throws CmsException if something goes wrong
2062     */
2063    public void importAccessControlEntries(CmsResource resource, List<CmsAccessControlEntry> acEntries)
2064    throws CmsException {
2065
2066        m_securityManager.importAccessControlEntries(m_context, resource, acEntries);
2067    }
2068
2069    /**
2070     * Imports a new relation to the given resource.<p>
2071     *
2072     * @param resourceName the name of the source resource
2073     * @param targetPath the path of the target resource
2074     * @param relationType the type of the relation
2075     *
2076     * @throws CmsException if something goes wrong
2077     */
2078    public void importRelation(String resourceName, String targetPath, String relationType) throws CmsException {
2079
2080        createRelation(resourceName, targetPath, relationType, true);
2081    }
2082
2083    /**
2084     * Imports a resource to the OpenCms VFS.<p>
2085     *
2086     * If a resource already exists in the VFS (i.e. has the same name and
2087     * same id) it is replaced by the imported resource.<p>
2088     *
2089     * If a resource with the same name but a different id exists,
2090     * the imported resource is (usually) moved to the "lost and found" folder.<p>
2091     *
2092     * @param resourcename the name for the resource after import (full current site relative path)
2093     * @param resource the resource object to be imported
2094     * @param content the content of the resource
2095     * @param properties the properties of the resource
2096     *
2097     * @return the imported resource
2098     *
2099     * @throws CmsException if something goes wrong
2100     *
2101     * @see CmsObject#moveToLostAndFound(String)
2102     */
2103    public CmsResource importResource(
2104        String resourcename,
2105        CmsResource resource,
2106        byte[] content,
2107        List<CmsProperty> properties)
2108    throws CmsException {
2109
2110        return getResourceType(
2111            resource).importResource(this, m_securityManager, null, resourcename, resource, content, properties);
2112    }
2113
2114    /**
2115     * Imports a resource to the OpenCms VFS.<p>
2116     *
2117     * If a resource already exists in the VFS (i.e. has the same name and
2118     * same id) it is replaced by the imported resource.<p>
2119     *
2120     * If a resource with the same name but a different id exists,
2121     * the imported resource is (usually) moved to the "lost and found" folder.<p>
2122     *
2123     * @param resourcename the name for the resource after import (full current site relative path)
2124     * @param report optional report to write non-critical errors to (may be null)
2125     * @param resource the resource object to be imported
2126     * @param content the content of the resource
2127     * @param properties the properties of the resource
2128     *
2129     * @return the imported resource
2130     *
2131     * @throws CmsException if something goes wrong
2132     *
2133     * @see CmsObject#moveToLostAndFound(String)
2134     */
2135    public CmsResource importResource(
2136        String resourcename,
2137        I_CmsReport report,
2138        CmsResource resource,
2139        byte[] content,
2140        List<CmsProperty> properties)
2141    throws CmsException {
2142
2143        return getResourceType(
2144            resource).importResource(this, m_securityManager, report, resourcename, resource, content, properties);
2145    }
2146
2147    /**
2148     * Creates a new user by import.<p>
2149     *
2150     * @param id the id of the user
2151     * @param name the new name for the user
2152     * @param password the new password for the user
2153     * @param firstname the first name of the user
2154     * @param lastname the last name of the user
2155     * @param email the email of the user
2156     * @param flags the flags for a user (for example <code>{@link I_CmsPrincipal#FLAG_ENABLED}</code>)
2157     * @param dateCreated the creation date
2158     * @param additionalInfos the additional user infos
2159     *
2160     * @return the imported user
2161     *
2162     * @throws CmsException if something goes wrong
2163     */
2164    public CmsUser importUser(
2165        String id,
2166        String name,
2167        String password,
2168        String firstname,
2169        String lastname,
2170        String email,
2171        int flags,
2172        long dateCreated,
2173        Map<String, Object> additionalInfos)
2174    throws CmsException {
2175
2176        return m_securityManager.importUser(
2177            m_context,
2178            id,
2179            name,
2180            password,
2181            firstname,
2182            lastname,
2183            email,
2184            flags,
2185            dateCreated,
2186            additionalInfos);
2187    }
2188
2189    /**
2190     * Increments a counter and returns its old value.<p>
2191     *
2192     * @param name the name of the counter
2193     *
2194     * @return the value of the counter before incrementing
2195     *
2196     * @throws CmsException if something goes wrong
2197     */
2198    public int incrementCounter(String name) throws CmsException {
2199
2200        return m_securityManager.incrementCounter(m_context, name);
2201    }
2202
2203    /**
2204     * Checks if the specified resource is inside the current project.<p>
2205     *
2206     * The project "view" is determined by a set of path prefixes.
2207     * If the resource starts with any one of this prefixes, it is considered to
2208     * be "inside" the project.<p>
2209     *
2210     * @param resourcename the specified resource name (full current site relative path)
2211     *
2212     * @return <code>true</code>, if the specified resource is inside the current project
2213     */
2214    public boolean isInsideCurrentProject(String resourcename) {
2215
2216        return m_securityManager.isInsideCurrentProject(m_context, addSiteRoot(resourcename));
2217    }
2218
2219    /**
2220     * Checks if the current user has management access to the current project.<p>
2221     *
2222     * @return <code>true</code>, if the user has management access to the current project
2223     */
2224
2225    public boolean isManagerOfProject() {
2226
2227        return m_securityManager.isManagerOfProject(m_context);
2228    }
2229
2230    /**
2231     * Locks a resource.<p>
2232     *
2233     * This will be an exclusive, persistent lock that is removed only if the user unlocks it.<p>
2234     *
2235     * @param resource the resource to lock
2236     *
2237     * @throws CmsException if something goes wrong
2238     */
2239    public void lockResource(CmsResource resource) throws CmsException {
2240
2241        getResourceType(resource).lockResource(this, m_securityManager, resource, CmsLockType.EXCLUSIVE);
2242    }
2243
2244    /**
2245     * Locks a resource.<p>
2246     *
2247     * This will be an exclusive, persistent lock that is removed only if the user unlocks it.<p>
2248     *
2249     * @param resourcename the name of the resource to lock (full current site relative path)
2250     *
2251     * @throws CmsException if something goes wrong
2252     */
2253    public void lockResource(String resourcename) throws CmsException {
2254
2255        lockResource(resourcename, CmsLockType.EXCLUSIVE);
2256    }
2257
2258    /**
2259     * Locks the given resource with a shallow lock that is not inherited on subresources.
2260     *
2261     * <p>Shallow locks are non-persistent, like temporary locks.
2262     *
2263     * @param resource the resource to lock
2264     * @throws CmsException if something goes wrong
2265     */
2266    public void lockResourceShallow(CmsResource resource) throws CmsException {
2267
2268        getResourceType(resource).lockResource(this, m_securityManager, resource, CmsLockType.SHALLOW);
2269    }
2270
2271    /**
2272     * Locks a resource temporary.<p>
2273     *
2274     * This will be an exclusive, temporary lock valid only for the current users session.
2275     * Usually this should not be used directly, this method is intended for the OpenCms workplace only.<p>
2276     *
2277     * @param resource the resource to lock
2278     *
2279     * @throws CmsException if something goes wrong
2280     *
2281     * @see CmsObject#lockResource(String)
2282     */
2283    public void lockResourceTemporary(CmsResource resource) throws CmsException {
2284
2285        getResourceType(resource).lockResource(this, m_securityManager, resource, CmsLockType.TEMPORARY);
2286    }
2287
2288    /**
2289     * Locks a resource temporary.<p>
2290     *
2291     * This will be an exclusive, temporary lock valid only for the current users session.
2292     * Usually this should not be used directly, this method is intended for the OpenCms workplace only.<p>
2293     *
2294     * @param resourcename the name of the resource to lock (full current site relative path)
2295     *
2296     * @throws CmsException if something goes wrong
2297     *
2298     * @see CmsObject#lockResource(String)
2299     */
2300    public void lockResourceTemporary(String resourcename) throws CmsException {
2301
2302        lockResource(resourcename, CmsLockType.TEMPORARY);
2303    }
2304
2305    /**
2306     * Logs a user into the Cms, if the password is correct.<p>
2307     *
2308     * @param username the name of the user
2309     * @param password the password of the user
2310     *
2311     * @return the name of the logged in user
2312     *
2313     * @throws CmsException if the login was not successful
2314     */
2315    public String loginUser(String username, String password) throws CmsException {
2316
2317        return loginUser(username, password, null, m_context.getRemoteAddress());
2318    }
2319
2320    /**
2321     * Logs in the user.
2322     *
2323     * @param username the user name
2324     * @param password the password
2325     * @param code the second factor information for 2FA
2326     * @return the logged in user
2327     *
2328     * @throws CmsException if something goes wrong
2329     */
2330    public String loginUser(String username, String password, CmsSecondFactorInfo code) throws CmsException {
2331
2332        return loginUser(username, password, code, m_context.getRemoteAddress());
2333    }
2334
2335    /**
2336     * Logs a user with a given ip address into the Cms, if the password is correct.<p>
2337     *
2338     * @param username the name of the user
2339     * @param password the password of the user
2340     * @param code the second factor information for 2FA
2341     * @param remoteAddress the ip address
2342     *
2343     * @return the name of the logged in user
2344     *
2345     * @throws CmsException if the login was not successful
2346     */
2347    public String loginUser(String username, String password, CmsSecondFactorInfo code, String remoteAddress)
2348    throws CmsException {
2349
2350        // login the user
2351        CmsUser newUser = m_securityManager.loginUser(m_context, username, password, code, remoteAddress);
2352        // set the project back to the "Online" project
2353        CmsProject newProject = m_securityManager.readProject(CmsProject.ONLINE_PROJECT_ID);
2354        // switch the cms context to the new user and project
2355        m_context.switchUser(newUser, newProject, newUser.getOuFqn());
2356        // init this CmsObject with the new user
2357        init(m_securityManager, m_context);
2358        // fire a login event
2359        fireEvent(I_CmsEventListener.EVENT_LOGIN_USER, newUser);
2360        // return the users login name
2361        return newUser.getName();
2362    }
2363
2364    /**
2365     * Logs a user with a given ip address into the Cms, if the password is correct.<p>
2366     *
2367     * @param username the name of the user
2368     * @param password the password of the user
2369     * @param remoteAddress the ip address
2370     *
2371     * @return the name of the logged in user
2372     *
2373     * @throws CmsException if the login was not successful
2374     */
2375    public String loginUser(String username, String password, String remoteAddress) throws CmsException {
2376
2377        return loginUser(username, password, (CmsSecondFactorInfo)null, remoteAddress);
2378    }
2379
2380    /**
2381     * Lookups and reads the user or group with the given UUID.<p>
2382     *
2383     * @param principalId the uuid of a user or group
2384     *
2385     * @return the user or group with the given UUID
2386     */
2387    public I_CmsPrincipal lookupPrincipal(CmsUUID principalId) {
2388
2389        return m_securityManager.lookupPrincipal(m_context, principalId);
2390    }
2391
2392    /**
2393     * Lookups and reads the user or group with the given name.<p>
2394     *
2395     * @param principalName the name of the user or group
2396     *
2397     * @return the user or group with the given name
2398     */
2399    public I_CmsPrincipal lookupPrincipal(String principalName) {
2400
2401        return m_securityManager.lookupPrincipal(m_context, principalName);
2402    }
2403
2404    /**
2405     * Moves a resource to the given destination.<p>
2406     *
2407     * A move operation in OpenCms is always a copy (as sibling) followed by a delete,
2408     * this is a result of the online/offline structure of the
2409     * OpenCms VFS. This way you can see the deleted files/folders in the offline
2410     * project, and you will be unable to undelete them.<p>
2411     *
2412     * @param source the name of the resource to move (full current site relative path)
2413     * @param destination the destination resource name (full current site relative path)
2414     *
2415     * @throws CmsException if something goes wrong
2416     *
2417     * @see #renameResource(String, String)
2418     */
2419    public void moveResource(String source, String destination) throws CmsException {
2420
2421        CmsResource resource = readResource(source, CmsResourceFilter.IGNORE_EXPIRATION);
2422        getResourceType(resource).moveResource(this, m_securityManager, resource, destination);
2423    }
2424
2425    /**
2426     * Moves a resource to the "lost and found" folder.<p>
2427     *
2428     * The "lost and found" folder is a special system folder.
2429     *
2430     * This operation is used e.g. during import of resources
2431     * when a resource with the same name but a different resource ID
2432     * already exists in the VFS. In this case, the imported resource is
2433     * moved to the "lost and found" folder.<p>
2434     *
2435     * @param resourcename the name of the resource to move to "lost and found" (full current site relative path)
2436     *
2437     * @return the name of the resource inside the "lost and found" folder
2438     *
2439     * @throws CmsException if something goes wrong
2440     *
2441     * @see #getLostAndFoundName(String)
2442     */
2443    public String moveToLostAndFound(String resourcename) throws CmsException {
2444
2445        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
2446        return m_securityManager.moveToLostAndFound(m_context, resource, false);
2447    }
2448
2449    /**
2450     * Reads all available versions for a given resource.<p>
2451     *
2452     * @param resource the resource for which to read the versions
2453     * @return the list of historical versions of the resource
2454     *
2455     * @throws CmsException if something goes wrong
2456     */
2457    public List<I_CmsHistoryResource> readAllAvailableVersions(CmsResource resource) throws CmsException {
2458
2459        return m_securityManager.readAllAvailableVersions(m_context, resource);
2460    }
2461
2462    /**
2463     * Reads all historical versions of a resource.<br>
2464     *
2465     * The reading excludes the file content, if the resource is a file.<p>
2466     *
2467     * @param resourceName the name of the resource to be read
2468     *
2469     * @return a list of historical resources, as <code>{@link I_CmsHistoryResource}</code> objects
2470     *
2471     * @throws CmsException if operation was not successful
2472     */
2473    public List<I_CmsHistoryResource> readAllAvailableVersions(String resourceName) throws CmsException {
2474
2475        CmsResource resource = readResource(resourceName, CmsResourceFilter.ALL);
2476        return m_securityManager.readAllAvailableVersions(m_context, resource);
2477    }
2478
2479    /**
2480     * Reads all property definitions.<p>
2481     *
2482     * @return a list with the <code>{@link CmsPropertyDefinition}</code> objects (may be empty)
2483     *
2484     * @throws CmsException if something goes wrong
2485     */
2486    public List<CmsPropertyDefinition> readAllPropertyDefinitions() throws CmsException {
2487
2488        return m_securityManager.readAllPropertyDefinitions(m_context);
2489    }
2490
2491    /**
2492     * Returns the first ancestor folder matching the filter criteria.<p>
2493     *
2494     * If no folder matching the filter criteria is found, null is returned.<p>
2495     *
2496     * @param resourcename the name of the resource to start (full current site relative path)
2497     * @param filter the resource filter to match while reading the ancestors
2498     *
2499     * @return the first ancestor folder matching the filter criteria or null if no folder was found
2500     *
2501     * @throws CmsException if something goes wrong
2502     */
2503    public CmsFolder readAncestor(String resourcename, CmsResourceFilter filter) throws CmsException {
2504
2505        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
2506        return m_securityManager.readAncestor(m_context, resource, filter);
2507    }
2508
2509    /**
2510     * Returns the first ancestor folder matching the resource type.<p>
2511     *
2512     * If no folder with the requested resource type is found, null is returned.<p>
2513     *
2514     * @param resourcename the name of the resource to start (full current site relative path)
2515     * @param type the resource type of the folder to match
2516     *
2517     * @return the first ancestor folder matching the filter criteria or null if no folder was found
2518     *
2519     * @throws CmsException if something goes wrong
2520     */
2521    @SuppressWarnings("deprecation")
2522    public CmsFolder readAncestor(String resourcename, int type) throws CmsException {
2523
2524        return readAncestor(resourcename, CmsResourceFilter.requireType(type));
2525    }
2526
2527    /**
2528     * Reads the newest URL name which is mapped to the given structure id.<p>
2529     *
2530     * If the structure id is not mapped to any name, null will be returned.<p>
2531     *
2532     * @param id the structure id for which the newest mapped name should be returned
2533     * @param locale the locale for which the URL name should be selected if possible
2534     * @param defaultLocales the default locales which should be used if the locale is not available
2535     * @return an URL name or null
2536     * @throws CmsException if something goes wrong
2537     */
2538    public String readBestUrlName(CmsUUID id, Locale locale, List<Locale> defaultLocales) throws CmsException {
2539
2540        return m_securityManager.readBestUrlName(m_context, id, locale, defaultLocales);
2541    }
2542
2543    /**
2544     * Returns the default resource for the given folder.<p>
2545     * <ol>
2546     *   <li>the {@link CmsPropertyDefinition#PROPERTY_DEFAULT_FILE} is checked, and
2547     *   <li>if still no file could be found, the configured default files in the
2548     *       <code>opencms-vfs.xml</code> configuration are iterated until a match is
2549     *       found, and
2550     *   <li>if still no file could be found, <code>null</code> is returned
2551     * </ol>
2552     *
2553     * @param folderResource the folder
2554     * @param resourceFilter the resource filter
2555     *
2556     * @return the default file for the given folder
2557     *
2558     * @throws CmsSecurityException  if the user has no permissions to read the resulting file
2559     */
2560    public CmsResource readDefaultFile(CmsResource folderResource, CmsResourceFilter resourceFilter)
2561    throws CmsSecurityException {
2562
2563        return m_securityManager.readDefaultFile(m_context, folderResource, resourceFilter);
2564    }
2565
2566    /**
2567     * Returns the default resource for the given folder.<p>
2568     *
2569     * If the given resource name or id identifies a file, then this file is returned.<p>
2570     *
2571     * Otherwise, in case of a folder:<br>
2572     * <ol>
2573     *   <li>the {@link CmsPropertyDefinition#PROPERTY_DEFAULT_FILE} is checked, and
2574     *   <li>if still no file could be found, the configured default files in the
2575     *       <code>opencms-vfs.xml</code> configuration are iterated until a match is
2576     *       found, and
2577     *   <li>if still no file could be found, <code>null</code> is returned
2578     * </ol>
2579     *
2580     * @param resourceNameOrID the name or id of the folder to read the default file for
2581     *
2582     * @return the default file for the given folder
2583     *
2584     * @throws CmsException if something goes wrong
2585     * @throws CmsSecurityException if the user has no permissions to read the resulting file
2586     */
2587    public CmsResource readDefaultFile(String resourceNameOrID) throws CmsException, CmsSecurityException {
2588
2589        return readDefaultFile(resourceNameOrID, CmsResourceFilter.DEFAULT);
2590    }
2591
2592    /**
2593     * Returns the default resource for the given folder.<p>
2594     *
2595     * If the given resource name or id identifies a file, then this file is returned.<p>
2596     *
2597     * Otherwise, in case of a folder:<br>
2598     * <ol>
2599     *   <li>the {@link CmsPropertyDefinition#PROPERTY_DEFAULT_FILE} is checked, and
2600     *   <li>if still no file could be found, the configured default files in the
2601     *       <code>opencms-vfs.xml</code> configuration are iterated until a match is
2602     *       found, and
2603     *   <li>if still no file could be found, <code>null</code> is returned
2604     * </ol>
2605     *
2606     * @param resourceNameOrID the name or id of the folder to read the default file for#
2607     * @param filter the resource filter to use for reading the resources
2608     *
2609     * @return the default file for the given folder
2610     *
2611     * @throws CmsException if something goes wrong
2612     * @throws CmsSecurityException if the user has no permissions to read the resulting file
2613     */
2614    public CmsResource readDefaultFile(String resourceNameOrID, CmsResourceFilter filter)
2615    throws CmsException, CmsSecurityException {
2616
2617        CmsResource resource;
2618        if (CmsUUID.isValidUUID(resourceNameOrID)) {
2619            resource = readResource(new CmsUUID(resourceNameOrID), filter);
2620        } else {
2621            resource = readResource(resourceNameOrID, filter);
2622        }
2623        return m_securityManager.readDefaultFile(m_context, resource, filter);
2624    }
2625
2626    /**
2627     * Reads all deleted (historical) resources below the given path,
2628     * including the full tree below the path, if required.<p>
2629     *
2630     * The result list may include resources with the same name of
2631     * resources (with different id's).<p>
2632     *
2633     * Use in conjunction with the {@link #restoreDeletedResource(CmsUUID)}
2634     * method.<p>
2635     *
2636     * @param resourcename the parent path to read the resources from
2637     * @param readTree <code>true</code> to read all sub resources
2638     *
2639     * @return a list of <code>{@link I_CmsHistoryResource}</code> objects
2640     *
2641     * @throws CmsException if something goes wrong
2642     *
2643     * @see #readResource(CmsUUID, int)
2644     * @see #readResources(String, CmsResourceFilter, boolean)
2645     */
2646    public List<I_CmsHistoryResource> readDeletedResources(String resourcename, boolean readTree) throws CmsException {
2647
2648        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
2649        return m_securityManager.readDeletedResources(m_context, resource, readTree);
2650    }
2651
2652    /**
2653     * Reads a file resource (including it's binary content) from the VFS,
2654     * for the given resource (this may also be an historical version of the resource).<p>
2655     *
2656     * In case the input {@link CmsResource} object already is a {@link CmsFile} with contents
2657     * available, it is casted to a file and returned unchanged. Otherwise the file is read
2658     * from the VFS.<p>
2659     *
2660     * In case you do not need the file content,
2661     * use <code>{@link #readResource(String)}</code> or
2662     * <code>{@link #readResource(String, CmsResourceFilter)}</code> instead.<p>
2663     *
2664     * No resource filter is applied when reading the resource, since we already have
2665     * a full resource instance and assume we just want the content for that instance.
2666     * In case you need to apply a filter, use {@link #readFile(String, CmsResourceFilter)} instead.<p>
2667     *
2668     * @param resource the resource to read
2669     *
2670     * @return the file resource that was read
2671     *
2672     * @throws CmsException if the file resource could not be read for any reason
2673     *
2674     * @see #readFile(String)
2675     * @see #readFile(String, CmsResourceFilter)
2676     */
2677    public CmsFile readFile(CmsResource resource) throws CmsException {
2678
2679        // test if we already have a file
2680        if (resource instanceof CmsFile) {
2681            // resource is already a file
2682            CmsFile file = (CmsFile)resource;
2683            if ((file.getContents() != null) && (file.getContents().length > 0)) {
2684                // file has the contents already available
2685                return file;
2686            }
2687        }
2688
2689        return m_securityManager.readFile(m_context, resource);
2690    }
2691
2692    /**
2693     * Reads a file resource (including it's binary content) from the VFS,
2694     * using the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
2695     *
2696     * In case you do not need the file content,
2697     * use <code>{@link #readResource(String)}</code> instead.<p>
2698     *
2699     * @param resourcename the name of the resource to read (full current site relative path)
2700     *
2701     * @return the file resource that was read
2702     *
2703     * @throws CmsException if the file resource could not be read for any reason
2704     *
2705     * @see #readFile(String, CmsResourceFilter)
2706     * @see #readFile(CmsResource)
2707     * @see #readResource(String)
2708     */
2709    public CmsFile readFile(String resourcename) throws CmsException {
2710
2711        return readFile(resourcename, CmsResourceFilter.DEFAULT);
2712    }
2713
2714    /**
2715     * Reads a file resource (including it's binary content) from the VFS,
2716     * using the specified resource filter.<p>
2717     *
2718     * In case you do not need the file content,
2719     * use <code>{@link #readResource(String, CmsResourceFilter)}</code> instead.<p>
2720     *
2721     * The specified filter controls what kind of resources should be "found"
2722     * during the read operation. This will depend on the application. For example,
2723     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
2724     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
2725     * will ignore the date release / date expired information of the resource.<p>
2726     *
2727     * @param resourcename the name of the resource to read (full current site relative path)
2728     * @param filter the resource filter to use while reading
2729     *
2730     * @return the file resource that was read
2731     *
2732     * @throws CmsException if the file resource could not be read for any reason
2733     *
2734     * @see #readFile(String)
2735     * @see #readFile(CmsResource)
2736     * @see #readResource(String, CmsResourceFilter)
2737     */
2738    public CmsFile readFile(String resourcename, CmsResourceFilter filter) throws CmsException {
2739
2740        CmsResource resource = readResource(resourcename, filter);
2741        return readFile(resource);
2742    }
2743
2744    /**
2745     * Reads the content of a file resource and passes it to an input stream handler.<p>
2746     *
2747     * @param resource the resource to read
2748     * @param handler the stream handler
2749     *
2750     * @throws CmsException if the file resource could not be read for any reason
2751     */
2752    public void readFileContentFrom(CmsResource resource, I_CmsFileContentStreamHandler handler) throws CmsException {
2753
2754        if (resource instanceof CmsFile) {
2755            CmsFile file = (CmsFile)resource;
2756            if ((file.getContents() != null) && (file.getContents().length > 0)) {
2757                try (ByteArrayInputStream in = new ByteArrayInputStream(file.getContents())) {
2758                    handler.read(in);
2759                    return;
2760                } catch (Exception e) {
2761                    throw new CmsVfsException(
2762                        Messages.get().container(Messages.ERR_READ_FILE_1, getRequestContext().getSitePath(resource)),
2763                        e);
2764                }
2765            }
2766        }
2767
2768        m_securityManager.readFileContentFrom(m_context, resource, handler);
2769    }
2770
2771    /**
2772     * Reads the content of a file resource and writes it to an output stream.<p>
2773     *
2774     * @param resource the resource to read
2775     * @param out the output stream to write to
2776     *
2777     * @throws CmsException if the file resource could not be read for any reason
2778     */
2779    public void readFileContentTo(CmsResource resource, OutputStream out) throws CmsException {
2780
2781        if (resource instanceof CmsFile) {
2782            CmsFile file = (CmsFile)resource;
2783            if ((file.getContents() != null) && (file.getContents().length > 0)) {
2784                try {
2785                    out.write(file.getContents());
2786                    return;
2787                } catch (Exception e) {
2788                    throw new CmsVfsException(
2789                        Messages.get().container(Messages.ERR_READ_FILE_1, getRequestContext().getSitePath(resource)),
2790                        e);
2791                }
2792            }
2793        }
2794
2795        m_securityManager.readFileContentTo(m_context, resource, out);
2796    }
2797
2798    /**
2799     * Reads a folder resource from the VFS,
2800     * using the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
2801     *
2802     * @param resourcename the name of the folder resource to read (full current site relative path)
2803     *
2804     * @return the folder resource that was read
2805     *
2806     * @throws CmsException if the resource could not be read for any reason
2807     *
2808     * @see #readResource(String, CmsResourceFilter)
2809     * @see #readFolder(String, CmsResourceFilter)
2810     */
2811    public CmsFolder readFolder(String resourcename) throws CmsException {
2812
2813        return readFolder(resourcename, CmsResourceFilter.DEFAULT);
2814    }
2815
2816    /**
2817     * Reads a folder resource from the VFS,
2818     * using the specified resource filter.<p>
2819     *
2820     * The specified filter controls what kind of resources should be "found"
2821     * during the read operation. This will depend on the application. For example,
2822     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
2823     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
2824     * will ignore the date release / date expired information of the resource.<p>
2825     *
2826     * @param resourcename the name of the folder resource to read (full current site relative path)
2827     * @param filter the resource filter to use while reading
2828     *
2829     * @return the folder resource that was read
2830     *
2831     * @throws CmsException if the resource could not be read for any reason
2832     *
2833     * @see #readResource(String, CmsResourceFilter)
2834     */
2835    public CmsFolder readFolder(String resourcename, CmsResourceFilter filter) throws CmsException {
2836
2837        return m_securityManager.readFolder(m_context, addSiteRoot(resourcename), filter);
2838    }
2839
2840    public List<CmsFolderSizeEntry> readFolderSizeStats(CmsFolderSizeOptions options) throws CmsException {
2841
2842        return m_securityManager.readFolderSizeStats(m_context, options);
2843    }
2844
2845    /**
2846     * Reads the group of a project.<p>
2847     *
2848     * @param project the project to read the group from
2849     *
2850     * @return the group of the given project
2851     */
2852    public CmsGroup readGroup(CmsProject project) {
2853
2854        return m_securityManager.readGroup(m_context, project);
2855    }
2856
2857    /**
2858     * Reads a group based on its id.<p>
2859     *
2860     * @param groupId the id of the group to be read
2861     *
2862     * @return the group that has the provided id
2863     *
2864     * @throws CmsException if something goes wrong
2865     *
2866     * @see #readHistoryPrincipal(CmsUUID) for retrieving deleted groups
2867     */
2868    public CmsGroup readGroup(CmsUUID groupId) throws CmsException {
2869
2870        return m_securityManager.readGroup(m_context, groupId);
2871    }
2872
2873    /**
2874     * Reads a group based on its name.<p>
2875     *
2876     * @param groupName the name of the group to be read
2877     *
2878     * @return the group that has the provided name
2879     *
2880     * @throws CmsException if something goes wrong
2881     */
2882    public CmsGroup readGroup(String groupName) throws CmsException {
2883
2884        return m_securityManager.readGroup(m_context, groupName);
2885    }
2886
2887    /**
2888     * Reads a principal (an user or group) from the historical archive based on its ID.<p>
2889     *
2890     * @param principalId the id of the principal to read
2891     *
2892     * @return the historical principal entry with the given id
2893     *
2894     * @throws CmsException if something goes wrong, ie. {@link org.opencms.db.CmsDbEntryNotFoundException}
2895     *
2896     * @see #readUser(CmsUUID)
2897     * @see #readGroup(CmsUUID)
2898     */
2899    public CmsHistoryPrincipal readHistoryPrincipal(CmsUUID principalId) throws CmsException {
2900
2901        return m_securityManager.readHistoricalPrincipal(m_context, principalId);
2902    }
2903
2904    /**
2905     * Returns the latest historical project entry with the given id.<p>
2906     *
2907     * @param projectId the project id
2908     *
2909     * @return the requested historical project entry
2910     *
2911     * @throws CmsException if operation was not successful
2912     */
2913    public CmsHistoryProject readHistoryProject(CmsUUID projectId) throws CmsException {
2914
2915        return (m_securityManager.readHistoryProject(m_context, projectId));
2916    }
2917
2918    /**
2919     * Returns a historical project entry.<p>
2920     *
2921     * @param publishTag publish tag of the project
2922     *
2923     * @return the requested historical project entry
2924     *
2925     * @throws CmsException if operation was not successful
2926     */
2927    public CmsHistoryProject readHistoryProject(int publishTag) throws CmsException {
2928
2929        return (m_securityManager.readHistoryProject(m_context, publishTag));
2930    }
2931
2932    /**
2933     * Reads the list of all <code>{@link CmsProperty}</code> objects that belong to the given historical resource version.<p>
2934     *
2935     * @param resource the historical resource version to read the properties for
2936     *
2937     * @return the list of <code>{@link CmsProperty}</code> objects
2938     *
2939     * @throws CmsException if something goes wrong
2940     */
2941    public List<CmsProperty> readHistoryPropertyObjects(I_CmsHistoryResource resource) throws CmsException {
2942
2943        return m_securityManager.readHistoryPropertyObjects(m_context, resource);
2944    }
2945
2946    /**
2947     * This method retrieves the structure id which is mapped to a given URL name.<p>
2948     *
2949     * If there is no structure id mapped to the given name, null will be returned.<p>
2950     *
2951     * However if the parameter is a string which represents a valid uuid, it will be directly returned as a {@link CmsUUID} instance.<p>
2952     *
2953     * @param name the url name
2954     * @return the id which is mapped to the URL name
2955     *
2956     * @throws CmsException if something goes wrong
2957     */
2958    public CmsUUID readIdForUrlName(String name) throws CmsException {
2959
2960        if (CmsUUID.isValidUUID(name)) {
2961            return new CmsUUID(name);
2962        }
2963        return m_securityManager.readIdForUrlName(m_context, name);
2964    }
2965
2966    /**
2967     * Returns the project manager group of a project.<p>
2968     *
2969     * @param project the project
2970     *
2971     * @return the manager group of the project
2972     */
2973    public CmsGroup readManagerGroup(CmsProject project) {
2974
2975        return m_securityManager.readManagerGroup(m_context, project);
2976    }
2977
2978    /**
2979     * Reads the owner of a project.<p>
2980     *
2981     * @param project the project to read the owner from
2982     *
2983     * @return the owner of the project
2984     *
2985     * @throws CmsException if something goes wrong
2986     */
2987    public CmsUser readOwner(CmsProject project) throws CmsException {
2988
2989        return m_securityManager.readOwner(m_context, project);
2990    }
2991
2992    /**
2993     * Returns the parent folder to the given structure id.<p>
2994     *
2995     * @param structureId the child structure id
2996     *
2997     * @return the parent folder <code>{@link CmsResource}</code>
2998     *
2999     * @throws CmsException if something goes wrong
3000     */
3001    public CmsResource readParentFolder(CmsUUID structureId) throws CmsException {
3002
3003        return m_securityManager.readParentFolder(m_context, structureId);
3004    }
3005
3006    /**
3007     * Builds a list of resources for a given path.<p>
3008     *
3009     * @param resource the resource to read the path for
3010     * @param filter a filter object (only "includeDeleted" information is used!)
3011     *
3012     * @return list of <code>{@link CmsResource}</code>s
3013     *
3014     * @throws CmsException if something goes wrong
3015     */
3016    public List<CmsResource> readPath(CmsResource resource, CmsResourceFilter filter) throws CmsException {
3017
3018        return m_securityManager.readPath(m_context, resource.getRootPath(), filter);
3019    }
3020
3021    /**
3022     * Builds a list of resources for a given path.<p>
3023     *
3024     * @param path the requested path
3025     * @param filter a filter object (only "includeDeleted" information is used!)
3026     *
3027     * @return list of <code>{@link CmsResource}</code>s
3028     *
3029     * @throws CmsException if something goes wrong
3030     */
3031    public List<CmsResource> readPath(String path, CmsResourceFilter filter) throws CmsException {
3032
3033        return m_securityManager.readPath(m_context, addSiteRoot(path), filter);
3034    }
3035
3036    /**
3037     * Reads the project with the given id.<p>
3038     *
3039     * @param id the id of the project
3040     *
3041     * @return the project with the given id
3042     *
3043     * @throws CmsException if operation was not successful
3044     */
3045    public CmsProject readProject(CmsUUID id) throws CmsException {
3046
3047        return m_securityManager.readProject(id);
3048    }
3049
3050    /**
3051     * Reads the project with the given name.<p>
3052     *
3053     * @param name the name of the project
3054     *
3055     * @return the project with the given name
3056     *
3057     * @throws CmsException if operation was not successful
3058     */
3059    public CmsProject readProject(String name) throws CmsException {
3060
3061        return m_securityManager.readProject(name);
3062    }
3063
3064    /**
3065     * Returns the list of all resource names that define the "view" of the given project.<p>
3066     *
3067     * @param project the project to get the project resources for
3068     *
3069     * @return the list of all resource names (root paths), as <code>{@link String}</code>
3070     *              objects that define the "view" of the given project
3071     *
3072     * @throws CmsException if something goes wrong
3073     */
3074    public List<String> readProjectResources(CmsProject project) throws CmsException {
3075
3076        return m_securityManager.readProjectResources(m_context, project);
3077    }
3078
3079    /**
3080     * Reads all resources of a project that match a given state from the VFS.<p>
3081     *
3082     * Possible values for the <code>state</code> parameter are:<br>
3083     * <ul>
3084     * <li><code>{@link CmsResource#STATE_CHANGED}</code>: Read all "changed" resources in the project</li>
3085     * <li><code>{@link CmsResource#STATE_NEW}</code>: Read all "new" resources in the project</li>
3086     * <li><code>{@link CmsResource#STATE_DELETED}</code>: Read all "deleted" resources in the project</li>
3087     * <li><code>{@link CmsResource#STATE_KEEP}</code>: Read all resources either "changed", "new" or "deleted" in the project</li>
3088     * </ul><p>
3089     *
3090     * @param projectId the id of the project to read the file resources for
3091     * @param state the resource state to match
3092     *
3093     * @return all <code>{@link CmsResource}</code>s of a project that match a given criteria from the VFS
3094     *
3095     * @throws CmsException if something goes wrong
3096     */
3097    public List<CmsResource> readProjectView(CmsUUID projectId, CmsResourceState state) throws CmsException {
3098
3099        return m_securityManager.readProjectView(m_context, projectId, state);
3100    }
3101
3102    /**
3103     * Reads a property definition.<p>
3104     *
3105     * If no property definition with the given name is found,
3106     * <code>null</code> is returned.<p>
3107     *
3108     * @param name the name of the property definition to read
3109     *
3110     * @return the property definition that was read
3111     *
3112     * @throws CmsException a CmsDbEntryNotFoundException is thrown if the property definition does not exist
3113     */
3114    public CmsPropertyDefinition readPropertyDefinition(String name) throws CmsException {
3115
3116        return (m_securityManager.readPropertyDefinition(m_context, name));
3117    }
3118
3119    /**
3120     * Reads a property object from a resource specified by a property name.<p>
3121     *
3122     * Returns <code>{@link CmsProperty#getNullProperty()}</code> if the property is not found.<p>
3123     *
3124     * This method is more efficient then using <code>{@link CmsObject#readPropertyObject(String, String, boolean)}</code>
3125     * if you already have an instance of the resource to look up the property from.<p>
3126     *
3127     * @param resource the resource where the property is attached to
3128     * @param property the property name
3129     * @param search if true, the property is searched on all parent folders of the resource,
3130     *      if it's not found attached directly to the resource
3131     *
3132     * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found
3133     *
3134     * @throws CmsException if something goes wrong
3135     */
3136    public CmsProperty readPropertyObject(CmsResource resource, String property, boolean search) throws CmsException {
3137
3138        return m_securityManager.readPropertyObject(m_context, resource, property, search);
3139    }
3140
3141    /**
3142     * Reads the locale specific version of a property object from a resource specified by a property name.<p>
3143     *
3144     * Returns <code>{@link CmsProperty#getNullProperty()}</code> if the property is not found.<p>
3145     *
3146     * This method is more efficient then using <code>{@link CmsObject#readPropertyObject(String, String, boolean)}</code>
3147     * if you already have an instance of the resource to look up the property from.<p>
3148     *
3149     * @param resource the resource where the property is attached to
3150     * @param property the property name
3151     * @param search if true, the property is searched on all parent folders of the resource,
3152     *      if it's not found attached directly to the resource
3153     * @param locale the locale for which the property should be read.
3154     *
3155     * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found
3156     *
3157     * @throws CmsException if something goes wrong
3158     */
3159    public CmsProperty readPropertyObject(CmsResource resource, String property, boolean search, Locale locale)
3160    throws CmsException {
3161
3162        return m_securityManager.readPropertyObject(m_context, resource, property, search, locale);
3163    }
3164
3165    /**
3166     * Reads a property object from a resource specified by a property name.<p>
3167     *
3168     * Returns <code>{@link CmsProperty#getNullProperty()}</code> if the property is not found.<p>
3169     *
3170     * @param resourcePath the name of resource where the property is attached to
3171     * @param property the property name
3172     * @param search if true, the property is searched on all parent folders of the resource,
3173     *      if it's not found attached directly to the resource
3174     *
3175     * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found
3176     *
3177     * @throws CmsException if something goes wrong
3178     */
3179    public CmsProperty readPropertyObject(String resourcePath, String property, boolean search) throws CmsException {
3180
3181        CmsResource resource = readResource(resourcePath, CmsResourceFilter.ALL);
3182        return m_securityManager.readPropertyObject(m_context, resource, property, search);
3183    }
3184
3185    /**
3186     * Reads the locale specific version of a property object from a resource specified by a property name.<p>
3187     *
3188     * Returns <code>{@link CmsProperty#getNullProperty()}</code> if the property is not found.<p>
3189     *
3190     * @param resourcePath the name of resource where the property is attached to
3191     * @param property the property name
3192     * @param search if true, the property is searched on all parent folders of the resource,
3193     *      if it's not found attached directly to the resource
3194     * @param locale the locale for which the property should be read.
3195     *
3196     * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found
3197     *
3198     * @throws CmsException if something goes wrong
3199     */
3200    public CmsProperty readPropertyObject(String resourcePath, String property, boolean search, Locale locale)
3201    throws CmsException {
3202
3203        CmsResource resource = readResource(resourcePath, CmsResourceFilter.ALL);
3204        return m_securityManager.readPropertyObject(m_context, resource, property, search, locale);
3205    }
3206
3207    /**
3208     * Reads all property objects from a resource.<p>
3209     *
3210     * Returns an empty list if no properties are found.<p>
3211     *
3212     * This method is more efficient then using <code>{@link CmsObject#readPropertyObjects(String, boolean)}</code>
3213     * if you already have an instance of the resource to look up the property from.<p>
3214     *
3215     * If the <code>search</code> parameter is <code>true</code>, the properties of all
3216     * parent folders of the resource are also read. The results are merged with the
3217     * properties directly attached to the resource. While merging, a property
3218     * on a parent folder that has already been found will be ignored.
3219     * So e.g. if a resource has a property "Title" attached, and it's parent folder
3220     * has the same property attached but with a different value, the result list will
3221     * contain only the property with the value from the resource, not form the parent folder(s).<p>
3222     *
3223     * @param resource the resource where the property is mapped to
3224     * @param search if <code>true</code>, the properties of all parent folders of the resource
3225     *      are merged with the resource properties.
3226     *
3227     * @return a list of <code>{@link CmsProperty}</code> objects
3228     *
3229     * @throws CmsException if something goes wrong
3230     */
3231    public List<CmsProperty> readPropertyObjects(CmsResource resource, boolean search) throws CmsException {
3232
3233        return m_securityManager.readPropertyObjects(m_context, resource, search);
3234    }
3235
3236    /**
3237     * Reads all property objects from a resource.<p>
3238     *
3239     * Returns an empty list if no properties are found.<p>
3240     *
3241     * All properties in the result List will be in frozen (read only) state, so you can't change the values.<p>
3242     *
3243     * If the <code>search</code> parameter is <code>true</code>, the properties of all
3244     * parent folders of the resource are also read. The results are merged with the
3245     * properties directly attached to the resource. While merging, a property
3246     * on a parent folder that has already been found will be ignored.
3247     * So e.g. if a resource has a property "Title" attached, and it's parent folder
3248     * has the same property attached but with a different value, the result list will
3249     * contain only the property with the value from the resource, not form the parent folder(s).<p>
3250     *
3251     * @param resourcePath the name of resource where the property is mapped to
3252     * @param search if <code>true</code>, the properties of all parent folders of the resource
3253     *      are merged with the resource properties.
3254     *
3255     * @return a list of <code>{@link CmsProperty}</code> objects
3256     *
3257     * @throws CmsException if something goes wrong
3258     */
3259    public List<CmsProperty> readPropertyObjects(String resourcePath, boolean search) throws CmsException {
3260
3261        CmsResource resource = readResource(resourcePath, CmsResourceFilter.ALL);
3262        return m_securityManager.readPropertyObjects(m_context, resource, search);
3263    }
3264
3265    /**
3266     * Reads the resources that were published in a publish task for a given publish history ID.<p>
3267     *
3268     * @param publishHistoryId unique ID to identify each publish task in the publish history
3269     *
3270     * @return a list of <code>{@link org.opencms.db.CmsPublishedResource}</code> objects
3271     *
3272     * @throws CmsException if something goes wrong
3273     */
3274    public List<CmsPublishedResource> readPublishedResources(CmsUUID publishHistoryId) throws CmsException {
3275
3276        return m_securityManager.readPublishedResources(m_context, publishHistoryId);
3277    }
3278
3279    /**
3280     * Returns all relations matching the given filter.<p>
3281     *
3282     * @param filter the filter to match the relation
3283     *
3284     * @return all relations matching the given filter
3285     *
3286     * @throws CmsException if something goes wrong
3287     *
3288     * @see CmsSecurityManager#getRelationsForResource(CmsRequestContext, CmsResource, CmsRelationFilter)
3289     * @see #getRelationsForResource(CmsResource, CmsRelationFilter)
3290     */
3291    public List<CmsRelation> readRelations(CmsRelationFilter filter) throws CmsException {
3292
3293        return m_securityManager.getRelationsForResource(m_context, null, filter);
3294    }
3295
3296    /**
3297     * Reads a resource from the VFS,
3298     * using the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
3299     *
3300     * A resource may be of type <code>{@link CmsFile}</code> or
3301     * <code>{@link CmsFolder}</code>. In case of
3302     * a file, the resource will not contain the binary file content. Since reading
3303     * the binary content is a cost-expensive database operation, it's recommended
3304     * to work with resources if possible, and only read the file content when absolutely
3305     * required. To "upgrade" a resource to a file,
3306     * use <code>{@link #readFile(CmsResource)}</code>.<p>
3307     *
3308     * @param structureID the structure ID of the resource to read
3309     *
3310     * @return the resource that was read
3311     *
3312     * @throws CmsException if the resource could not be read for any reason
3313     *
3314     * @see #readFile(String)
3315     * @see #readResource(CmsUUID, CmsResourceFilter)
3316     */
3317    public CmsResource readResource(CmsUUID structureID) throws CmsException {
3318
3319        return readResource(structureID, CmsResourceFilter.DEFAULT);
3320    }
3321
3322    /**
3323     * Reads a resource from the VFS,
3324     * using the specified resource filter.<p>
3325     *
3326     * A resource may be of type <code>{@link CmsFile}</code> or
3327     * <code>{@link CmsFolder}</code>. In case of
3328     * a file, the resource will not contain the binary file content. Since reading
3329     * the binary content is a cost-expensive database operation, it's recommended
3330     * to work with resources if possible, and only read the file content when absolutely
3331     * required. To "upgrade" a resource to a file,
3332     * use <code>{@link #readFile(CmsResource)}</code>.<p>
3333     *
3334     * The specified filter controls what kind of resources should be "found"
3335     * during the read operation. This will depend on the application. For example,
3336     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
3337     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
3338     * will ignore the date release / date expired information of the resource.<p>
3339     *
3340     * @param structureID the structure ID of the resource to read
3341     * @param filter the resource filter to use while reading
3342     *
3343     * @return the resource that was read
3344     *
3345     * @throws CmsException if the resource could not be read for any reason
3346     *
3347     * @see #readFile(String, CmsResourceFilter)
3348     * @see #readFolder(String, CmsResourceFilter)
3349     */
3350    public CmsResource readResource(CmsUUID structureID, CmsResourceFilter filter) throws CmsException {
3351
3352        return m_securityManager.readResource(m_context, structureID, filter);
3353    }
3354
3355    /**
3356     * Reads the historical resource with the given version for the resource given
3357     * the given structure id.<p>
3358     *
3359     * A resource may be of type <code>{@link CmsFile}</code> or
3360     * <code>{@link CmsFolder}</code>. In case of a file, the resource will not
3361     * contain the binary file content. Since reading the binary content is a
3362     * cost-expensive database operation, it's recommended to work with resources
3363     * if possible, and only read the file content when absolutely required. To
3364     * "upgrade" a resource to a file, use
3365     * <code>{@link #readFile(CmsResource)}</code>.<p>
3366     *
3367     * Please note that historical versions are just generated during publishing,
3368     * so the first version with version number 1 is generated during publishing
3369     * of a new resource (exception is a new sibling, that may also contain some
3370     * relevant versions of already published siblings) and the last version
3371     * available is the version of the current online resource.<p>
3372     *
3373     * @param structureID the structure ID of the resource to read
3374     * @param version the version number you want to retrieve
3375     *
3376     * @return the resource that was read
3377     *
3378     * @throws CmsException if the resource could not be read for any reason
3379     * @throws CmsVfsResourceNotFoundException if the version does not exists
3380     *
3381     * @see #restoreResourceVersion(CmsUUID, int)
3382     */
3383    public I_CmsHistoryResource readResource(CmsUUID structureID, int version)
3384    throws CmsException, CmsVfsResourceNotFoundException {
3385
3386        CmsResource resource = readResource(structureID, CmsResourceFilter.ALL);
3387        return m_securityManager.readResource(m_context, resource, version);
3388    }
3389
3390    /**
3391     * Reads a resource from the VFS,
3392     * using the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p>
3393     *
3394     * A resource may be of type <code>{@link CmsFile}</code> or
3395     * <code>{@link CmsFolder}</code>. In case of
3396     * a file, the resource will not contain the binary file content. Since reading
3397     * the binary content is a cost-expensive database operation, it's recommended
3398     * to work with resources if possible, and only read the file content when absolutely
3399     * required. To "upgrade" a resource to a file,
3400     * use <code>{@link #readFile(CmsResource)}</code>.<p>
3401     *
3402     * @param resourcename the name of the resource to read (full current site relative path)
3403     *
3404     * @return the resource that was read
3405     *
3406     * @throws CmsException if the resource could not be read for any reason
3407     *
3408     * @see #readFile(String)
3409     * @see #readResource(String, CmsResourceFilter)
3410     */
3411    public CmsResource readResource(String resourcename) throws CmsException {
3412
3413        return readResource(resourcename, CmsResourceFilter.DEFAULT);
3414    }
3415
3416    /**
3417     * Reads a resource from the VFS,
3418     * using the specified resource filter.<p>
3419     *
3420     * A resource may be of type <code>{@link CmsFile}</code> or
3421     * <code>{@link CmsFolder}</code>. In case of
3422     * a file, the resource will not contain the binary file content. Since reading
3423     * the binary content is a cost-expensive database operation, it's recommended
3424     * to work with resources if possible, and only read the file content when absolutely
3425     * required. To "upgrade" a resource to a file,
3426     * use <code>{@link #readFile(CmsResource)}</code>.<p>
3427     *
3428     * The specified filter controls what kind of resources should be "found"
3429     * during the read operation. This will depend on the application. For example,
3430     * using <code>{@link CmsResourceFilter#DEFAULT}</code> will only return currently
3431     * "valid" resources, while using <code>{@link CmsResourceFilter#IGNORE_EXPIRATION}</code>
3432     * will ignore the date release / date expired information of the resource.<p>
3433     *
3434     * @param resourcename the name of the resource to read (full current site relative path)
3435     * @param filter the resource filter to use while reading
3436     *
3437     * @return the resource that was read
3438     *
3439     * @throws CmsException if the resource could not be read for any reason
3440     *
3441     * @see #readFile(String, CmsResourceFilter)
3442     * @see #readFolder(String, CmsResourceFilter)
3443     */
3444    public CmsResource readResource(String resourcename, CmsResourceFilter filter) throws CmsException {
3445
3446        return m_securityManager.readResource(m_context, addSiteRoot(resourcename), filter);
3447    }
3448
3449    /**
3450     * Reads all resources below the given resource matching the filter criteria,
3451     * including the full tree below the path only in case the <code>readTree</code>
3452     * parameter is <code>true</code>.<p>
3453     *
3454     * @param resource the parent resource
3455     * @param filter the filter
3456     * @param readTree <code>true</code> to read all sub resources
3457     *
3458     * @return a list of <code>{@link CmsResource}</code> objects matching the filter criteria
3459     *
3460     * @throws CmsException if something goes wrong
3461     */
3462    public List<CmsResource> readResources(CmsResource resource, CmsResourceFilter filter, boolean readTree)
3463    throws CmsException {
3464
3465        if (readTree) {
3466            return m_securityManager.readResources(m_context, resource, filter, readTree);
3467        } else {
3468            return m_securityManager.readChildResources(m_context, resource, filter, true, true);
3469        }
3470    }
3471
3472    /**
3473     * Reads all resources below the given path matching the filter criteria,
3474     * including the full tree below the path.<p>
3475     *
3476     * @param resourcename the parent path to read the resources from
3477     * @param filter the filter
3478     *
3479     * @return a list of <code>{@link CmsResource}</code> objects matching the filter criteria
3480     *
3481     * @throws CmsException if something goes wrong
3482     *
3483     * @see #readResources(String, CmsResourceFilter, boolean)
3484     */
3485    public List<CmsResource> readResources(String resourcename, CmsResourceFilter filter) throws CmsException {
3486
3487        return readResources(resourcename, filter, true);
3488    }
3489
3490    /**
3491     * Reads all resources below the given path matching the filter criteria,
3492     * including the full tree below the path only in case the <code>readTree</code>
3493     * parameter is <code>true</code>.<p>
3494     *
3495     * @param resourcename the parent path to read the resources from
3496     * @param filter the filter
3497     * @param readTree <code>true</code> to read all sub resources
3498     *
3499     * @return a list of <code>{@link CmsResource}</code> objects matching the filter criteria
3500     *
3501     * @throws CmsException if something goes wrong
3502     */
3503    public List<CmsResource> readResources(String resourcename, CmsResourceFilter filter, boolean readTree)
3504    throws CmsException {
3505
3506        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
3507        return m_securityManager.readResources(m_context, resource, filter, readTree);
3508    }
3509
3510    /**
3511     * Reads all resources that have a value set for the specified property.<p>
3512     *
3513     * Both individual and shared properties of a resource are checked.<p>
3514     *
3515     * Will use the {@link CmsResourceFilter#ALL} resource filter.<p>
3516     *
3517     * @param propertyDefinition the name of the property to check for
3518     *
3519     * @return a list of all <code>{@link CmsResource}</code> objects
3520     *          that have a value set for the specified property.
3521     *
3522     * @throws CmsException if something goes wrong
3523     */
3524    public List<CmsResource> readResourcesWithProperty(String propertyDefinition) throws CmsException {
3525
3526        return readResourcesWithProperty("/", propertyDefinition);
3527    }
3528
3529    /**
3530     * Reads all resources that have a value set for the specified property in the given path.<p>
3531     *
3532     * Both individual and shared properties of a resource are checked.<p>
3533     *
3534     * Will use the {@link CmsResourceFilter#ALL} resource filter.<p>
3535     *
3536     * @param path the folder to get the resources with the property from
3537     * @param propertyDefinition the name of the property to check for
3538     *
3539     * @return all <code>{@link CmsResource}</code> objects
3540     *          that have a value set for the specified property in the given path.
3541     *
3542     * @throws CmsException if something goes wrong
3543     */
3544    public List<CmsResource> readResourcesWithProperty(String path, String propertyDefinition) throws CmsException {
3545
3546        return readResourcesWithProperty(path, propertyDefinition, null);
3547    }
3548
3549    /**
3550     * Reads all resources that have a value (containing the specified value) set
3551     * for the specified property in the given path.<p>
3552     *
3553     * Both individual and shared properties of a resource are checked.<p>
3554     *
3555     * If the <code>value</code> parameter is <code>null</code>, all resources having the
3556     * given property set are returned.<p>
3557     *
3558     * Will use the {@link CmsResourceFilter#ALL} resource filter.<p>
3559     *
3560     * @param path the folder to get the resources with the property from
3561     * @param propertyDefinition the name of the property to check for
3562     * @param value the string to search in the value of the property
3563     *
3564     * @return all <code>{@link CmsResource}</code> objects
3565     *          that have a value set for the specified property in the given path.
3566     *
3567     * @throws CmsException if something goes wrong
3568     */
3569    public List<CmsResource> readResourcesWithProperty(String path, String propertyDefinition, String value)
3570    throws CmsException {
3571
3572        CmsResource resource = readResource(path, CmsResourceFilter.IGNORE_EXPIRATION);
3573        return m_securityManager.readResourcesWithProperty(
3574            m_context,
3575            resource,
3576            propertyDefinition,
3577            value,
3578            CmsResourceFilter.ALL);
3579    }
3580
3581    /**
3582     * Reads all resources that have a value (containing the specified value) set
3583     * for the specified property in the given path.<p>
3584     *
3585     * Both individual and shared properties of a resource are checked.<p>
3586     *
3587     * If the <code>value</code> parameter is <code>null</code>, all resources having the
3588     * given property set are returned.<p>
3589     *
3590     * Will use the given resource filter.<p>
3591     *
3592     * @param path the folder to get the resources with the property from
3593     * @param propertyDefinition the name of the property to check for
3594     * @param value the string to search in the value of the property
3595     * @param filter the resource filter to apply to the result set
3596     *
3597     * @return all <code>{@link CmsResource}</code> objects
3598     *          that have a value set for the specified property in the given path.
3599     *
3600     * @throws CmsException if something goes wrong
3601     */
3602    public List<CmsResource> readResourcesWithProperty(
3603        String path,
3604        String propertyDefinition,
3605        String value,
3606        CmsResourceFilter filter)
3607    throws CmsException {
3608
3609        CmsResource resource = readResource(path, CmsResourceFilter.IGNORE_EXPIRATION);
3610        return m_securityManager.readResourcesWithProperty(m_context, resource, propertyDefinition, value, filter);
3611    }
3612
3613    /**
3614     * Returns a set of principals that are responsible for a specific resource.<p>
3615     *
3616     * @param resource the resource to get the responsible principals from
3617     *
3618     * @return the set of principals that are responsible for a specific resource
3619     *
3620     * @throws CmsException if something goes wrong
3621     */
3622    public Set<I_CmsPrincipal> readResponsiblePrincipals(CmsResource resource) throws CmsException {
3623
3624        return m_securityManager.readResponsiblePrincipals(m_context, resource);
3625    }
3626
3627    /**
3628     * Returns a set of users that are responsible for a specific resource.<p>
3629     *
3630     * @param resource the resource to get the responsible users from
3631     *
3632     * @return the set of users that are responsible for a specific resource
3633     *
3634     * @throws CmsException if something goes wrong
3635     */
3636    public Set<CmsUser> readResponsibleUsers(CmsResource resource) throws CmsException {
3637
3638        return m_securityManager.readResponsibleUsers(m_context, resource);
3639    }
3640
3641    /**
3642     * Returns a list of all siblings of the specified resource,
3643     * the specified resource being always part of the result set.<p>
3644     *
3645     * @param resource the resource
3646     * @param filter a resource filter
3647     *
3648     * @return a list of <code>{@link CmsResource}</code>s that
3649     *          are siblings to the specified resource,
3650     *          including the specified resource itself.
3651     *
3652     * @throws CmsException if something goes wrong
3653     */
3654    public List<CmsResource> readSiblings(CmsResource resource, CmsResourceFilter filter) throws CmsException {
3655
3656        return m_securityManager.readSiblings(m_context, resource, filter);
3657    }
3658
3659    /**
3660     * Returns a list of all siblings of the specified resource,
3661     * the specified resource being always part of the result set.<p>
3662     *
3663     * @param resourcename the name of the specified resource
3664     * @param filter a resource filter
3665     *
3666     * @return a list of <code>{@link CmsResource}</code>s that
3667     *          are siblings to the specified resource,
3668     *          including the specified resource itself.
3669     *
3670     * @throws CmsException if something goes wrong
3671     */
3672    public List<CmsResource> readSiblings(String resourcename, CmsResourceFilter filter) throws CmsException {
3673
3674        CmsResource resource = readResource(resourcename, filter);
3675        return readSiblings(resource, filter);
3676    }
3677
3678    /**
3679     * Reads all resources with the given resource id.<p>
3680     *
3681     * @param resourceId the resource id for which we want the siblings
3682     * @param filter the resource filter used to read the resources
3683     * @return the siblings which share the given resource id
3684     *
3685     * @throws CmsException if something goes wrong
3686     */
3687    public List<CmsResource> readSiblingsForResourceId(CmsUUID resourceId, CmsResourceFilter filter)
3688    throws CmsException {
3689
3690        CmsResource pseudoResource = new CmsResource(
3691            null,
3692            resourceId,
3693            null,
3694            0,
3695            false,
3696            0,
3697            null,
3698            null,
3699            0,
3700            null,
3701            0,
3702            null,
3703            0,
3704            0,
3705            0,
3706            0,
3707            0,
3708            0);
3709        return readSiblings(pseudoResource, filter);
3710    }
3711
3712    /**
3713     * Returns the parameters of a resource in the list of all published template resources.<p>
3714     *
3715     * @param rfsName the rfs name of the resource
3716     *
3717     * @return the parameter string of the requested resource
3718     *
3719     * @throws CmsException if something goes wrong
3720     */
3721    public String readStaticExportPublishedResourceParameters(String rfsName) throws CmsException {
3722
3723        return m_securityManager.readStaticExportPublishedResourceParameters(m_context, rfsName);
3724    }
3725
3726    /**
3727     * Returns a list of all template resources which must be processed during a static export.<p>
3728     *
3729     * @param parameterResources flag for reading resources with parameters (1) or without (0)
3730     *
3731     * @param timestamp a time stamp for reading the data from the db
3732     *
3733     * @return a list of template resources as <code>{@link String}</code> objects
3734     *
3735     * @throws CmsException if something goes wrong
3736     */
3737    public List<String> readStaticExportResources(int parameterResources, long timestamp) throws CmsException {
3738
3739        return m_securityManager.readStaticExportResources(m_context, parameterResources, timestamp);
3740    }
3741
3742    /**
3743     * Reads information about where the content of a file resource is stored without loading the content bytes.<p>
3744     *
3745     * @param resource the resource to read
3746     *
3747     * @return the stored content info
3748     *
3749     * @throws CmsException if the file resource could not be read for any reason
3750     */
3751    public CmsStoredContentInfo readStoredContentInfo(CmsResource resource) throws CmsException {
3752
3753        return m_securityManager.readStoredContentInfo(m_context, resource);
3754    }
3755
3756    /**
3757     * Reads the URL name mappings matching a given filter.<p>
3758     *
3759     * @param filter the filter to match
3760     * @return the URL name mappings matching the filter
3761     *
3762     * @throws CmsException if something goes wrong
3763     */
3764    public List<CmsUrlNameMappingEntry> readUrlNameMappings(CmsUrlNameMappingFilter filter) throws CmsException {
3765
3766        return m_securityManager.readUrlNameMappings(m_context, filter);
3767    }
3768
3769    /**
3770     * Reads the URL names for all locales.<p>
3771     *
3772     * @param structureId the id of resource for which the URL names should be read
3773     * @return returns the URL names for the resource
3774     *
3775     * @throws CmsException if something goes wrong
3776     */
3777    public List<String> readUrlNamesForAllLocales(CmsUUID structureId) throws CmsException {
3778
3779        List<String> detailNames = m_securityManager.readUrlNamesForAllLocales(m_context, structureId);
3780        if (detailNames.isEmpty()) {
3781            List<String> result = new ArrayList<String>();
3782            result.add(structureId.toString());
3783            return result;
3784        }
3785        return detailNames;
3786    }
3787
3788    /**
3789     * Reads a user based on its id.<p>
3790     *
3791     * @param userId the id of the user to be read
3792     *
3793     * @return the user with the given id
3794     *
3795     * @throws CmsException if something goes wrong
3796     *
3797     * @see #readHistoryPrincipal(CmsUUID) for retrieving data of deleted users
3798     */
3799    public CmsUser readUser(CmsUUID userId) throws CmsException {
3800
3801        return m_securityManager.readUser(m_context, userId);
3802    }
3803
3804    /**
3805     * Reads a user based on its name.<p>
3806     *
3807     * @param username the name of the user to be read
3808     *
3809     * @return the user with the given name
3810     *
3811     * @throws CmsException if something goes wrong
3812     */
3813    public CmsUser readUser(String username) throws CmsException {
3814
3815        return m_securityManager.readUser(m_context, username);
3816    }
3817
3818    /**
3819     * Returns a user, if the password is correct.<p>
3820     *
3821     * If the user/pwd pair is not valid a <code>{@link CmsException}</code> is thrown.<p>
3822     *
3823     * @param username the name of the user to be returned
3824     * @param password the password of the user to be returned
3825     *
3826     * @return the validated user
3827     *
3828     * @throws CmsException if operation was not successful
3829     */
3830    public CmsUser readUser(String username, String password) throws CmsException {
3831
3832        return m_securityManager.readUser(m_context, username, password);
3833    }
3834
3835    /**
3836     * Removes a resource from the current project of the user.<p>
3837     *
3838     * This is used to reduce the current users project with the
3839     * specified resource, in case that the resource is already part of the project.
3840     * The resource is not really removed like in a regular copy operation,
3841     * it is in fact only "disabled" in the current users project.<p>
3842     *
3843     * @param resourcename the name of the resource to remove to the current project (full current site relative path)
3844     *
3845     * @throws CmsException if something goes wrong
3846     */
3847    public void removeResourceFromProject(String resourcename) throws CmsException {
3848
3849        try {
3850            CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
3851            getResourceType(resource).removeResourceFromProject(this, m_securityManager, resource);
3852        } catch (CmsVfsResourceNotFoundException e) {
3853            LOG.info(e.getLocalizedMessage(), e);
3854            CmsResourceBuilder builder = new CmsResourceBuilder();
3855            builder.setStructureId(CmsUUID.getNullUUID());
3856            builder.setResourceId(CmsUUID.getNullUUID());
3857            if (resourcename.endsWith("/")) {
3858                builder.setType(
3859                    OpenCms.getResourceManager().getResourceType(CmsResourceTypeFolder.getStaticTypeName()));
3860            } else {
3861                builder.setType(OpenCms.getResourceManager().getResourceType(CmsResourceTypePlain.getStaticTypeName()));
3862            }
3863            builder.setRootPath(addSiteRoot(resourcename));
3864            CmsResource resource = builder.buildResource();
3865            getResourceType(resource).removeResourceFromProject(this, m_securityManager, resource);
3866        }
3867    }
3868
3869    /**
3870     * Removes a user from a group.<p>
3871     *
3872     * @param username the name of the user that is to be removed from the group
3873     * @param groupname the name of the group
3874     *
3875     * @throws CmsException if operation was not successful
3876     */
3877    public void removeUserFromGroup(String username, String groupname) throws CmsException {
3878
3879        m_securityManager.removeUserFromGroup(m_context, username, groupname, false);
3880    }
3881
3882    /**
3883     * Renames a resource to the given destination name,
3884     * this is identical to a <code>move</code> operation.<p>
3885     *
3886     * @param source the name of the resource to rename (full current site relative path)
3887     * @param destination the new resource name (full path)
3888     *
3889     * @throws CmsException if something goes wrong
3890     *
3891     * @see #moveResource(String, String)
3892     */
3893    public void renameResource(String source, String destination) throws CmsException {
3894
3895        moveResource(source, destination);
3896    }
3897
3898    /**
3899     * Replaces the content, type and properties of a resource.<p>
3900     *
3901     * @param resourcename the name of the resource to replace (full current site relative path)
3902     * @param type the new type of the resource
3903     * @param content the new content of the resource
3904     * @param properties the new properties of the resource
3905     *
3906     * @throws CmsException if something goes wrong
3907     */
3908    public void replaceResource(
3909        String resourcename,
3910        I_CmsResourceType type,
3911        byte[] content,
3912        List<CmsProperty> properties)
3913    throws CmsException {
3914
3915        CmsResource resource = readResource(resourcename, CmsResourceFilter.IGNORE_EXPIRATION);
3916        getResourceType(resource).replaceResource(this, m_securityManager, resource, type, content, properties);
3917    }
3918
3919    /**
3920     * Replaces the content, type and properties of a resource.<p>
3921     *
3922     * @param resourcename the name of the resource to replace (full current site relative path)
3923     * @param type the new type of the resource
3924     * @param content the new content of the resource
3925     * @param properties the new properties of the resource
3926     *
3927     * @throws CmsException if something goes wrong
3928     *
3929     * @deprecated
3930     * Use {@link #replaceResource(String, I_CmsResourceType, byte[], List)} instead.
3931     * Resource types should always be referenced either by its type class (preferred) or by type name.
3932     * Use of int based resource type references will be discontinued in a future OpenCms release.
3933     */
3934    @Deprecated
3935    public void replaceResource(String resourcename, int type, byte[] content, List<CmsProperty> properties)
3936    throws CmsException {
3937
3938        replaceResource(resourcename, getResourceType(type), content, properties);
3939    }
3940
3941    /**
3942     * Restores a deleted resource identified by its structure id from the historical archive.<p>
3943     *
3944     * These ids can be obtained from the {@link #readDeletedResources(String, boolean)} method.<p>
3945     *
3946     * @param structureId the structure id of the resource to restore
3947     *
3948     * @throws CmsException if something goes wrong
3949     */
3950    public void restoreDeletedResource(CmsUUID structureId) throws CmsException {
3951
3952        m_securityManager.restoreDeletedResource(m_context, structureId);
3953    }
3954
3955    /**
3956     * Restores a resource in the current project with a version from the historical archive.<p>
3957     *
3958     * @param structureId the structure id of the resource to restore from the archive
3959     * @param version the desired version of the resource to be restored
3960     *
3961     * @throws CmsException if something goes wrong
3962     *
3963     * @see #readResource(CmsUUID, int)
3964     */
3965    public void restoreResourceVersion(CmsUUID structureId, int version) throws CmsException {
3966
3967        CmsResource resource = readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
3968        getResourceType(resource).restoreResource(this, m_securityManager, resource, version);
3969    }
3970
3971    /**
3972     * Removes an access control entry of a given principal from a given resource.<p>
3973     *
3974     * @param resourceName name of the resource
3975     * @param principalType the type of the principal (currently group or user)
3976     * @param principalName the name of the principal
3977     *
3978     * @throws CmsException if something goes wrong
3979     */
3980    public void rmacc(String resourceName, String principalType, String principalName) throws CmsException {
3981
3982        CmsResource res = readResource(resourceName, CmsResourceFilter.ALL);
3983
3984        if (CmsUUID.isValidUUID(principalName)) {
3985            // principal name is in fact a UUID, probably the user was already deleted
3986            m_securityManager.removeAccessControlEntry(m_context, res, new CmsUUID(principalName));
3987        } else if (CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_NAME.equals(principalName)) {
3988            m_securityManager.removeAccessControlEntry(m_context, res, CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_ID);
3989        } else if (CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_NAME.equals(principalName)) {
3990            m_securityManager.removeAccessControlEntry(
3991                m_context,
3992                res,
3993                CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID);
3994        } else {
3995            try {
3996                // principal name not a UUID, assume this is a normal group or user name
3997                I_CmsPrincipal principal = CmsPrincipal.readPrincipal(this, principalType, principalName);
3998                m_securityManager.removeAccessControlEntry(m_context, res, principal.getId());
3999            } catch (CmsDbEntryNotFoundException e) {
4000                // role case
4001                CmsRole role = CmsRole.valueOfRoleName(principalName);
4002                if (role == null) {
4003                    throw e;
4004                }
4005                m_securityManager.removeAccessControlEntry(m_context, res, role.getId());
4006            }
4007        }
4008    }
4009
4010    /**
4011     * Changes the "expire" date of a resource.<p>
4012     *
4013     * @param resource the resource to change
4014     * @param dateExpired the new expire date of the changed resource
4015     * @param recursive if this operation is to be applied recursively to all resources in a folder
4016     *
4017     * @throws CmsException if something goes wrong
4018     */
4019    public void setDateExpired(CmsResource resource, long dateExpired, boolean recursive) throws CmsException {
4020
4021        getResourceType(resource).setDateExpired(this, m_securityManager, resource, dateExpired, recursive);
4022    }
4023
4024    /**
4025     * Changes the "expire" date of a resource.<p>
4026     *
4027     * @param resourcename the name of the resource to change (full current site relative path)
4028     * @param dateExpired the new expire date of the changed resource
4029     * @param recursive if this operation is to be applied recursively to all resources in a folder
4030     *
4031     * @throws CmsException if something goes wrong
4032     */
4033    public void setDateExpired(String resourcename, long dateExpired, boolean recursive) throws CmsException {
4034
4035        CmsResource resource = readResource(resourcename, CmsResourceFilter.IGNORE_EXPIRATION);
4036        setDateExpired(resource, dateExpired, recursive);
4037    }
4038
4039    /**
4040     * Changes the "last modified" time stamp of a resource.<p>
4041     *
4042     * @param resourcename the name of the resource to change (full current site relative path)
4043     * @param dateLastModified time stamp the new time stamp of the changed resource
4044     * @param recursive if this operation is to be applied recursively to all resources in a folder
4045     *
4046     * @throws CmsException if something goes wrong
4047     */
4048    public void setDateLastModified(String resourcename, long dateLastModified, boolean recursive) throws CmsException {
4049
4050        CmsResource resource = readResource(resourcename, CmsResourceFilter.IGNORE_EXPIRATION);
4051        getResourceType(resource).setDateLastModified(this, m_securityManager, resource, dateLastModified, recursive);
4052    }
4053
4054    /**
4055     * Changes the "release" date of a resource.<p>
4056     *
4057     * @param resource the resource to change
4058     * @param dateReleased the new release date of the changed resource
4059     * @param recursive if this operation is to be applied recursively to all resources in a folder
4060     *
4061     * @throws CmsException if something goes wrong
4062     */
4063    public void setDateReleased(CmsResource resource, long dateReleased, boolean recursive) throws CmsException {
4064
4065        getResourceType(resource).setDateReleased(this, m_securityManager, resource, dateReleased, recursive);
4066    }
4067
4068    /**
4069     * Changes the "release" date of a resource.<p>
4070     *
4071     * @param resourcename the name of the resource to change (full current site relative path)
4072     * @param dateReleased the new release date of the changed resource
4073     * @param recursive if this operation is to be applied recursively to all resources in a folder
4074     *
4075     * @throws CmsException if something goes wrong
4076     */
4077    public void setDateReleased(String resourcename, long dateReleased, boolean recursive) throws CmsException {
4078
4079        CmsResource resource = readResource(resourcename, CmsResourceFilter.IGNORE_EXPIRATION);
4080        setDateReleased(resource, dateReleased, recursive);
4081    }
4082
4083    /**
4084     * Sets a new parent-group for an already existing group.<p>
4085     *
4086     * @param groupName the name of the group that should be updated
4087     * @param parentGroupName the name of the parent group to set,
4088     *                      or <code>null</code> if the parent
4089     *                      group should be deleted.
4090     *
4091     * @throws CmsException  if operation was not successful
4092     */
4093    public void setParentGroup(String groupName, String parentGroupName) throws CmsException {
4094
4095        m_securityManager.setParentGroup(m_context, groupName, parentGroupName);
4096    }
4097
4098    /**
4099     * Sets the password for a user.<p>
4100     *
4101     * @param username the name of the user
4102     * @param newPassword the new password
4103     *
4104     * @throws CmsException if operation was not successful
4105     */
4106    public void setPassword(String username, String newPassword) throws CmsException {
4107
4108        m_securityManager.setPassword(m_context, username, newPassword);
4109    }
4110
4111    /**
4112     * Sets the password for a specified user.<p>
4113     *
4114     * @param username the name of the user
4115     * @param oldPassword the old password
4116     * @param secondFactor the second factor information for 2FA
4117     * @param newPassword the new password
4118     *
4119     * @throws CmsException if the user data could not be read from the database
4120     */
4121    public void setPassword(String username, String oldPassword, CmsSecondFactorInfo secondFactor, String newPassword)
4122    throws CmsException {
4123
4124        m_securityManager.resetPassword(m_context, username, oldPassword, secondFactor, newPassword);
4125    }
4126
4127    /**
4128     * Sets the password for a specified user.<p>
4129     *
4130     * @param username the name of the user
4131     * @param oldPassword the old password
4132     * @param newPassword the new password
4133     *
4134     * @throws CmsException if the user data could not be read from the database
4135     */
4136    public void setPassword(String username, String oldPassword, String newPassword) throws CmsException {
4137
4138        m_securityManager.resetPassword(m_context, username, oldPassword, null, newPassword);
4139    }
4140
4141    /**
4142     * Sets/clears the 'restricted' status for the given resource and group.
4143     *
4144     * <p>The 'restricted' status causes files to be inaccessible to users not in the group if the file is expired or unreleased.
4145     * <p>It is implemented as an access control entry with the 'responsible' flag, but the permission check for this method is different from the chacc() methods: It doesn't require control
4146     * permissions on the target resource, but the user has to be a member of the given group and have write access to the resource.
4147     *
4148     * @param res the target resource
4149     * @param groupName a group name (current user must be a member)
4150     * @param restricted true if the restriction status should be set
4151     * @throws CmsException if something goes wrong
4152     */
4153    public void setRestricted(CmsResource res, String groupName, boolean restricted) throws CmsException {
4154
4155        m_securityManager.setRestricted(m_context, res, readGroup(groupName), restricted);
4156    }
4157
4158    /**
4159     * Helper method to temporarily change the site root in a try-with-resources statement.
4160     *
4161     * @param siteRoot the site root to switch to
4162     * @return an AutoCloseable that restores the original site root when closed
4163     */
4164    public AutoCloseable tempChangeSiteRoot(String siteRoot) {
4165
4166        final String oldSiteRoot = m_context.getSiteRoot();
4167        m_context.setSiteRoot(siteRoot);
4168        return () -> m_context.setSiteRoot(oldSiteRoot);
4169    }
4170
4171    /**
4172     * Undeletes a resource.<p>
4173     *
4174     * Only resources that have already been published once can be undeleted,
4175     * if a "new" resource is deleted it can not be undeleted.<p>
4176     *
4177     * @param resourcename the name of the resource to undelete
4178     * @param recursive if this operation is to be applied recursively to all resources in a folder
4179     *
4180     * @throws CmsException if something goes wrong
4181     *
4182     * @see CmsObject#undoChanges(String, CmsResource.CmsResourceUndoMode)
4183     */
4184    public void undeleteResource(String resourcename, boolean recursive) throws CmsException {
4185
4186        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
4187        getResourceType(resource).undelete(this, m_securityManager, resource, recursive);
4188    }
4189
4190    /**
4191     * Undoes all changes to a resource by restoring the version from the
4192     * online project to the current offline project.<p>
4193     *
4194     * @param resourcename the name of the resource to undo the changes for
4195     * @param mode the undo mode, one of the <code>{@link CmsResource.CmsResourceUndoMode}#UNDO_XXX</code> constants
4196     *
4197     * @throws CmsException if something goes wrong
4198     *
4199     * @see CmsResource#UNDO_CONTENT
4200     * @see CmsResource#UNDO_CONTENT_RECURSIVE
4201     * @see CmsResource#UNDO_MOVE_CONTENT
4202     * @see CmsResource#UNDO_MOVE_CONTENT_RECURSIVE
4203     */
4204    public void undoChanges(String resourcename, CmsResource.CmsResourceUndoMode mode) throws CmsException {
4205
4206        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
4207        getResourceType(resource).undoChanges(this, m_securityManager, resource, mode);
4208    }
4209
4210    /**
4211     * Unlocks all resources of a project.
4212     *
4213     * @param id the id of the project to be unlocked
4214     *
4215     * @throws CmsException if operation was not successful
4216     */
4217    public void unlockProject(CmsUUID id) throws CmsException {
4218
4219        m_securityManager.unlockProject(m_context, id);
4220    }
4221
4222    /**
4223     * Unlocks a resource.<p>
4224     *
4225     * @param resource the resource to unlock
4226     *
4227     * @throws CmsException if something goes wrong
4228     */
4229    public void unlockResource(CmsResource resource) throws CmsException {
4230
4231        getResourceType(resource).unlockResource(this, m_securityManager, resource);
4232    }
4233
4234    /**
4235     * Unlocks a resource.<p>
4236     *
4237     * @param resourcename the name of the resource to unlock (full current site relative path)
4238     *
4239     * @throws CmsException if something goes wrong
4240     */
4241    public void unlockResource(String resourcename) throws CmsException {
4242
4243        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
4244        getResourceType(resource).unlockResource(this, m_securityManager, resource);
4245    }
4246
4247    /**
4248     * Updates the last login date on the given user to the current time.<p>
4249     *
4250     * @param user the user to be updated
4251     *
4252     * @throws CmsRoleViolationException if the current user does not own the rule {@link CmsRole#ACCOUNT_MANAGER} for the current project
4253     * @throws CmsException if operation was not successful
4254     */
4255    public void updateLastLoginDate(CmsUser user) throws CmsRoleViolationException, CmsException {
4256
4257        m_securityManager.updateLastLoginDate(m_context, user);
4258    }
4259
4260    /**
4261     * Tests if a user is member of the given group.<p>
4262     *
4263     * @param username the name of the user to test
4264     * @param groupname the name of the group to test
4265     *
4266     * @return <code>true</code>, if the user is in the group; or <code>false</code> otherwise
4267     *
4268     * @throws CmsException if operation was not successful
4269     */
4270    public boolean userInGroup(String username, String groupname) throws CmsException {
4271
4272        return (m_securityManager.userInGroup(m_context, username, groupname));
4273    }
4274
4275    /**
4276     * This method checks if a new password follows the rules for
4277     * new passwords, which are defined by a Class implementing the
4278     * <code>{@link org.opencms.security.I_CmsPasswordHandler}</code>
4279     * interface and configured in the opencms.properties file.<p>
4280     *
4281     * If this method throws no exception the password is valid.<p>
4282     *
4283     * @param password the new password that has to be checked
4284     *
4285     * @throws CmsSecurityException if the password is not valid
4286     */
4287    public void validatePassword(String password) throws CmsSecurityException {
4288
4289        m_securityManager.validatePassword(password);
4290    }
4291
4292    /**
4293     * Writes a resource to the OpenCms VFS, including it's content.<p>
4294     *
4295     * Applies only to resources of type <code>{@link CmsFile}</code>
4296     * i.e. resources that have a binary content attached.<p>
4297     *
4298     * Certain resource types might apply content validation or transformation rules
4299     * before the resource is actually written to the VFS. The returned result
4300     * might therefore be a modified version from the provided original.<p>
4301     *
4302     * @param resource the resource to write
4303     *
4304     * @return the written resource (may have been modified)
4305     *
4306     * @throws CmsException if something goes wrong
4307     */
4308    public CmsFile writeFile(CmsFile resource) throws CmsException {
4309
4310        return CmsModificationContext.doWithModificationContext(m_context, () -> {
4311
4312            return getResourceType(resource).writeFile(this, m_securityManager, resource);
4313
4314        });
4315    }
4316
4317    /**
4318     * Writes an already existing group.<p>
4319     *
4320     * The group has to be a valid OpenCms group.<br>
4321     *
4322     * The group will be completely overridden by the given data.<p>
4323     *
4324     * @param group the group that should be written
4325     *
4326     * @throws CmsException if operation was not successful
4327     */
4328    public void writeGroup(CmsGroup group) throws CmsException {
4329
4330        m_securityManager.writeGroup(m_context, group);
4331    }
4332
4333    /**
4334     * Creates a historical entry of the current project.<p>
4335     *
4336     * @param publishTag the correlative publish tag
4337     * @param publishDate the date of publishing
4338     *
4339     * @throws CmsException if operation was not successful
4340     */
4341    public void writeHistoryProject(int publishTag, long publishDate) throws CmsException {
4342
4343        m_securityManager.writeHistoryProject(m_context, publishTag, publishDate);
4344    }
4345
4346    /**
4347     * Writes an already existing project.<p>
4348     *
4349     * The project id has to be a valid OpenCms project id.<br>
4350     *
4351     * The project with the given id will be completely overridden
4352     * by the given data.<p>
4353     *
4354     * @param project the project that should be written
4355     *
4356     * @throws CmsException if operation was not successful
4357     */
4358    public void writeProject(CmsProject project) throws CmsException {
4359
4360        m_securityManager.writeProject(m_context, project);
4361    }
4362
4363    /**
4364     * Writes the 'projectlastmodified' field of a resource record.<p>
4365     *
4366     * @param resource the resource which should be modified
4367     * @param project the project whose id should be written into the resource record
4368     *
4369     * @throws CmsException if something goes wrong
4370     */
4371    public void writeProjectLastModified(CmsResource resource, CmsProject project) throws CmsException {
4372
4373        m_securityManager.writeResourceProjectLastModified(getRequestContext(), resource, project);
4374    }
4375
4376    /**
4377     * Writes a property for a specified resource.<p>
4378     *
4379     * @param resourcename the name of resource with complete path
4380     * @param property the property to write
4381     *
4382     * @throws CmsException if something goes wrong
4383     */
4384    public void writePropertyObject(String resourcename, CmsProperty property) throws CmsException {
4385
4386        CmsResource resource = readResource(resourcename, CmsResourceFilter.IGNORE_EXPIRATION);
4387        getResourceType(resource).writePropertyObject(this, m_securityManager, resource, property);
4388    }
4389
4390    /**
4391     * Writes a list of properties for a specified resource.<p>
4392     *
4393     * Code calling this method has to ensure that the no properties
4394     * <code>a, b</code> are contained in the specified list so that <code>a.equals(b)</code>,
4395     * otherwise an exception is thrown.<p>
4396     *
4397     * @param res the resource
4398     * @param properties the list of properties to write
4399     *
4400     * @throws CmsException if something goes wrong
4401     */
4402    public void writePropertyObjects(CmsResource res, List<CmsProperty> properties) throws CmsException {
4403
4404        getResourceType(res).writePropertyObjects(this, m_securityManager, res, properties);
4405    }
4406
4407    /**
4408     * Writes a list of properties for a specified resource.<p>
4409     *
4410     * Code calling this method has to ensure that the no properties
4411     * <code>a, b</code> are contained in the specified list so that <code>a.equals(b)</code>,
4412     * otherwise an exception is thrown.<p>
4413     *
4414     * @param resourcename the name of resource with complete path
4415     * @param properties the list of properties to write
4416     *
4417     * @throws CmsException if something goes wrong
4418     */
4419    public void writePropertyObjects(String resourcename, List<CmsProperty> properties) throws CmsException {
4420
4421        CmsResource resource = readResource(resourcename, CmsResourceFilter.IGNORE_EXPIRATION);
4422        getResourceType(resource).writePropertyObjects(this, m_securityManager, resource, properties);
4423    }
4424
4425    /**
4426     * Writes a resource.<p>
4427     *
4428     * @param resource the file to write
4429     *
4430     * @throws CmsException if resource type is set to folder, or
4431     *                      if the user has not the rights to write the file header.
4432     */
4433    public void writeResource(CmsResource resource) throws CmsException {
4434
4435        m_securityManager.writeResource(m_context, resource);
4436    }
4437
4438    /**
4439     * Writes a published resource entry.<p>
4440     *
4441     * This is done during static export.<p>
4442     *
4443     * @param resourceName The name of the resource to be added to the static export
4444     * @param linkType the type of resource exported (0= non-parameter, 1=parameter)
4445     * @param linkParameter the parameters added to the resource
4446     * @param timestamp a time stamp for writing the data into the db
4447     *
4448     * @throws CmsException if something goes wrong
4449     */
4450    public void writeStaticExportPublishedResource(
4451        String resourceName,
4452        int linkType,
4453        String linkParameter,
4454        long timestamp)
4455    throws CmsException {
4456
4457        m_securityManager.writeStaticExportPublishedResource(
4458            m_context,
4459            resourceName,
4460            linkType,
4461            linkParameter,
4462            timestamp);
4463    }
4464
4465    /**
4466     * Writes a new URL name mapping for a given resource.<p>
4467     *
4468     * The first name from the given name sequence which is not already mapped to another resource will be used
4469     * for the URL name mapping.<p>
4470     *
4471     * @param nameSeq an iterator for generating names for the mapping
4472     * @param structureId the structure id to which the name should be mapped
4473     * @param locale the locale of the mapping
4474     * @param replaceOnPublish if the mapping should replace previous mappings when published
4475     *
4476     * @return the name which was actually mapped to the structure id
4477     *
4478     * @throws CmsException if something goes wrong
4479     */
4480    public String writeUrlNameMapping(
4481        Iterator<String> nameSeq,
4482        CmsUUID structureId,
4483        String locale,
4484        boolean replaceOnPublish)
4485    throws CmsException {
4486
4487        return m_securityManager.writeUrlNameMapping(m_context, nameSeq, structureId, locale, replaceOnPublish);
4488    }
4489
4490    /**
4491     * Writes a new URL name mapping for a given resource.<p>
4492     *
4493     * This method uses {@link CmsNumberSuffixNameSequence} to generate a sequence of name candidates
4494     * from the given base name.<p>
4495     *
4496     * @param name the base name for the mapping
4497     * @param structureId the structure id to which the name should be mapped
4498     * @param locale the locale of the mapping
4499     * @param replaceOnPublish mappings for which this is set will replace older mappings on publish
4500     *
4501     * @return the URL name that was actually used for the mapping
4502     *
4503     * @throws CmsException if something goes wrong
4504     */
4505    public String writeUrlNameMapping(String name, CmsUUID structureId, String locale, boolean replaceOnPublish)
4506    throws CmsException {
4507
4508        return writeUrlNameMapping(new CmsNumberSuffixNameSequence(name, false), structureId, locale, replaceOnPublish);
4509    }
4510
4511    /**
4512     * Updates the user information. <p>
4513     *
4514     * The user id has to be a valid OpenCms user id.<br>
4515     *
4516     * The user with the given id will be completely overriden
4517     * by the given data.<p>
4518     *
4519     * @param user the user to be written
4520     *
4521     * @throws CmsException if operation was not successful
4522     */
4523    public void writeUser(CmsUser user) throws CmsException {
4524
4525        m_securityManager.writeUser(m_context, user);
4526    }
4527
4528    /**
4529     * Adds a new relation to the given resource.<p>
4530     *
4531     * @param resource the source resource
4532     * @param target the target resource
4533     * @param relationType the type of the relation
4534     * @param importCase if importing relations
4535     *
4536     * @throws CmsException if something goes wrong
4537     */
4538    private void createRelation(CmsResource resource, CmsResource target, String relationType, boolean importCase)
4539    throws CmsException {
4540
4541        CmsRelationType type = CmsRelationType.valueOf(relationType);
4542        m_securityManager.addRelationToResource(m_context, resource, target, type, importCase);
4543    }
4544
4545    /**
4546     * Adds a new relation to the given resource.<p>
4547     *
4548     * @param resourceName the name of the source resource
4549     * @param targetPath the path of the target resource
4550     * @param relationType the type of the relation
4551     * @param importCase if importing relations
4552     *
4553     * @throws CmsException if something goes wrong
4554     */
4555    private void createRelation(String resourceName, String targetPath, String relationType, boolean importCase)
4556    throws CmsException {
4557
4558        CmsResource resource = readResource(resourceName, CmsResourceFilter.IGNORE_EXPIRATION);
4559        CmsResource target = readResource(targetPath, CmsResourceFilter.IGNORE_EXPIRATION);
4560        createRelation(resource, target, relationType, importCase);
4561    }
4562
4563    /**
4564     * Notify all event listeners that a particular event has occurred.<p>
4565     *
4566     * The event will be given to all registered <code>{@link I_CmsEventListener}</code>s.<p>
4567     *
4568     * @param type the type of the event
4569     * @param data a data object that contains data used by the event listeners
4570     *
4571     * @see OpenCms#addCmsEventListener(I_CmsEventListener)
4572     * @see OpenCms#addCmsEventListener(I_CmsEventListener, int[])
4573     */
4574    private void fireEvent(int type, Object data) {
4575
4576        OpenCms.fireCmsEvent(type, Collections.singletonMap("data", data));
4577    }
4578
4579    /**
4580     * Convenience method to get the initialized resource type instance for the given resource,
4581     * with a fall back to special "unknown" resource types in case the resource type is not configured.<p>
4582     *
4583     * @param resource the resource to get the type for
4584     *
4585     * @return the initialized resource type instance for the given resource
4586     *
4587     * @see org.opencms.loader.CmsResourceManager#getResourceType(int)
4588     */
4589    private I_CmsResourceType getResourceType(CmsResource resource) {
4590
4591        return OpenCms.getResourceManager().getResourceType(resource);
4592    }
4593
4594    /**
4595     * Convenience method to return the initialized resource type
4596     * instance for the given id.<p>
4597     *
4598     * @param resourceType the id of the resource type to get
4599     *
4600     * @return the initialized resource type instance for the given id
4601     *
4602     * @throws CmsException if something goes wrong
4603     *
4604     * @see org.opencms.loader.CmsResourceManager#getResourceType(int)
4605     */
4606    private I_CmsResourceType getResourceType(int resourceType) throws CmsException {
4607
4608        return OpenCms.getResourceManager().getResourceType(resourceType);
4609    }
4610
4611    /**
4612     * Initializes this <code>{@link CmsObject}</code> with the provided user context and database connection.<p>
4613     *
4614     * @param securityManager the security manager
4615     * @param context the request context that contains the user authentication
4616     */
4617    private void init(CmsSecurityManager securityManager, CmsRequestContext context) {
4618
4619        m_securityManager = securityManager;
4620        m_context = context;
4621    }
4622
4623    /**
4624     * Locks a resource.<p>
4625     *
4626     * The <code>type</code> parameter controls what kind of lock is used.<br>
4627     * Possible values for this parameter are: <br>
4628     * <ul>
4629     * <li><code>{@link org.opencms.lock.CmsLockType#EXCLUSIVE}</code></li>
4630     * <li><code>{@link org.opencms.lock.CmsLockType#TEMPORARY}</code></li>
4631     * </ul><p>
4632     *
4633     * @param resourcename the name of the resource to lock (full current site relative path)
4634     * @param type type of the lock
4635     *
4636     * @throws CmsException if something goes wrong
4637     */
4638    private void lockResource(String resourcename, CmsLockType type) throws CmsException {
4639
4640        // throw the exception if resource name is an empty string
4641        if (CmsStringUtil.isEmptyOrWhitespaceOnly(resourcename)) {
4642            throw new CmsVfsResourceNotFoundException(
4643                Messages.get().container(Messages.ERR_LOCK_RESOURCE_1, resourcename));
4644        }
4645        CmsResource resource = readResource(resourcename, CmsResourceFilter.ALL);
4646        getResourceType(resource).lockResource(this, m_securityManager, resource, type);
4647    }
4648
4649}