/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/urm/org/apache/slide/urm/accesscontroler/impl/semantic/firstmatch/URMFirstMatchSemantic.java,v 1.5 2005/03/02 10:53:34 eckehard Exp $
 * $Revision: 1.5 $
 * $Date: 2005/03/02 10:53:34 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * This class implements the URMSematic interface with the first-match semanic.
 * An ACL is evaluated to determine wether or not access will be granted for a
 * request. ACEs are maintained in a particular order, and are evaluted until
 * all of the permissions required by the current request have been granted, at
 * which point the ACL evaluation is terminated and access is granted.
 *
 * @author eckehard.hermann@softwareag.com
 * @author dieter.kessler@softwareag.com
 * @author zsolt.sasvarie@softwareag.com
 * @see URMSemantic
 */

package org.apache.slide.urm.accesscontroler.impl.semantic.firstmatch;

import org.apache.slide.urm.accesscontroler.*;
import java.util.*;

import org.apache.slide.urm.URMException;
import org.apache.slide.urm.accesscontroler.impl.URMAceImpl;
import org.apache.slide.urm.accesscontroler.impl.URMPermissionResultImpl;
import org.apache.slide.urm.authenticator.URMAdministrator;
import org.apache.slide.urm.authenticator.URMSubject;
import org.apache.slide.urm.authenticator.rolemanager.URMRole;
import org.apache.slide.urm.authenticator.userdb.URMGroup;
import org.apache.slide.urm.authenticator.userdb.URMUser;
import org.apache.slide.urm.common.URMConstants;
import org.apache.slide.urm.common.URMInternalServerException;
import org.apache.slide.urm.common.URMPrincipal;
import org.apache.slide.urm.utils.URMSemanticUtils;
import org.apache.slide.urm.utils.messagelogger.MessageLogger;
import org.apache.slide.urm.utils.validatorcache.URMValidatorCache;

public class URMFirstMatchSemantic extends URMSemanticUtils implements URMSemantic {

    URMValidatorCache validatorCache = URMValidatorCache.getCache();
    
    /**
     * Constructor
     *
     */
    public URMFirstMatchSemantic() {
    }
    
    /**
     * Constructor
     *
     * @param    preActionSemantic   defines the Pre-Defined Action Semantic:
     *                               DenyOverGrant (default), GrantOverDeny
     *
     */
    public URMFirstMatchSemantic(String preActionSemantic) {
        if (preActionSemantic == null) this.denyOverGrant = true;
        else if (preActionSemantic.equals(URMConstants.GRANT_OVER_DENY)) this.denyOverGrant = false;
        else if (preActionSemantic.equals(URMConstants.DENY_OVER_GRANT)) this.denyOverGrant = true;
    }
    
    private static org.apache.log4j.Logger msLogger =
        org.apache.log4j.Logger.getLogger(URMAclValidator.class.getName());
    
    /** Processes an access check of a URMPrincipal.
     *
     * @param principal the principal of the authenticated user.
     * @param resource List of resourceids in the order they should be validated
     * @param action the required action.
     * @return One of the predefined values URMPermit, URMDeny,
     *              URMIndeterminable, URMNotApplicable.
     *
     * @throws URMAccessCheckException if the access check fails.
     *
     * @see URMAclValidator
     */
    public int checkPermission(URMPrincipal principal, List resource, String action)
        throws URMAccessCheckException {
        boolean deny = false;
        boolean grant = false;
        URMPermissionResultImpl _permission = null;
        try {
            if ((principal == null) || (resource == null) || (action == null) || (action.equals("")) || (resource.isEmpty())) {
                return URMAclValidator.URMNotApplicable;
            }
            
            // check if a active role has been defined
            URMRole activeRole = null;
            try {
                 activeRole= principal.getActiveRole();
            } catch (Exception e) {}
            // active role has been defined check the permission of the active role
            if (activeRole != null) return checkPermission(principal, activeRole, resource, action);
            
            // check if requested validation has already been done and cached
            String subjectCacheId = null;
            if (principal.getDomain() != null) {
                subjectCacheId = "user:" + principal.getDomain() + "/" + principal.getName();
            } else {
                subjectCacheId = "user:" + principal.getName();
            }
            
            String resourceid = null;
            Iterator resourceIter = resource.iterator();
            while (resourceIter.hasNext()) {
                if (resourceid == null) resourceid = (String) resourceIter.next();
                else resourceid = resourceid + "/" + (String) resourceIter.next();
            }
            URMPermissionResult permission = validatorCache.checkPermission(resourceid, subjectCacheId, action);
            if (permission != null) return permission.getPermission();
            
            // if active role as not been defined check the permission of the principal
            URMAclAdministrator aclAdmin = principal.getURMAclAdministrator();
            List aclList = aclAdmin.getAclPath(resource);
            Iterator aclListIter = aclList.iterator();
            URMAcl acl = null;
            
            // after loaded the acl, check again against cache. Maybe some acls are null and url is known
            String aclid = null;
            while (aclListIter.hasNext()) {
                if (aclid == null) aclid = ((URMAcl) aclListIter.next()).getId();
                else aclid = aclid + "/" + ((URMAcl) aclListIter.next()).getId();
            }
            permission = validatorCache.checkPermission(aclid, subjectCacheId, action);
            if (permission != null) {
                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                return permission.getPermission();
            }
            
            aclListIter = aclList.iterator();
            // resolve action into base actions
            HashMap actionMap = new HashMap();
            URMAction urmAction = aclAdmin.getAction(action);
            if (urmAction == null) throw new URMAccessCheckException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038",action));
            resolveActionMapping(aclAdmin, urmAction, actionMap);
            
            // resolve predefined actions
            int preActionResult = resolvePredefinedActions(principal, aclAdmin, actionMap);
            if (preActionResult == URMAclValidator.URMDeny) deny = true;
            if (preActionResult == URMAclValidator.URMPermit) grant = true;
            if (!grant) grant = verifyGrant(actionMap);
            
            // iterate through the ACL List
            while (!deny && !grant && aclListIter.hasNext()) {
                acl = (URMAcl) aclListIter.next();
                List aceList = acl.getAllAces();
                Iterator aceListIter = aceList.iterator();
                URMAce ace = null;
                
                // iterate through the ACEs of the current resources ACL
                while (!deny && !grant && aceListIter.hasNext()) {
                    ace = (URMAce) aceListIter.next();
                    
                    // check if the current ACE is inverted
                    if (ace.getInvert()) {
                        // if inverted, create to helper ACEs one for the current
                        // subject with inverted action and one for all subjects
                        // with the not inverted action
                        URMAce ace1 = new URMAceImpl (ace, !ace.getInvert());
                        URMAce aceAll = new URMAceImpl (ace, principal.getURMAdministrator().getALLSubject());
                        List invertAces = new ArrayList();
                        invertAces.add(ace1);
                        invertAces.add(aceAll);
                        Iterator invertAcesIter = invertAces.iterator();
                        while (!deny && !grant && invertAcesIter.hasNext()) {
                            URMAce currentAce = (URMAce) invertAcesIter.next();
                            // validate if the ACE matches the principal
                            int aceMatch = validateAce(principal, currentAce, aclAdmin, actionMap);
                                      
                            if (aceMatch == URMAclValidator.URMPermit) {
                                grant = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMDeny) {
                                deny = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMNotApplicable) {
                                _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                                return aceMatch;
                            }
                        }
                    } else {
                        // if not inverted,
                        // validate if the ACE matches the principal
                        int aceMatch = validateAce(principal, ace, aclAdmin, actionMap);
                                      
                        if (aceMatch == URMAclValidator.URMPermit) {
                            grant = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMDeny) {
                            deny = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMNotApplicable) {
                            _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                            validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                            return aceMatch;
                        }
                    }
                    
                }
            }
                        
            if ((!deny) && (grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMPermit);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return URMAclValidator.URMPermit;
            }
            else if ((deny) && (!grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMDeny);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return URMAclValidator.URMDeny;
            }
            else {
                _permission = new URMPermissionResultImpl(URMAclValidator.URMIndeterminate, null, null);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return URMAclValidator.URMIndeterminate;
            }
            
        } catch (URMException e) {
            throw new URMAccessCheckException(msLogger, "E", e);
        }
    }

    /** Processes an access check of a URMRole.
     *
     * @param principal the principal of the authenticated user.
     * @param role URMRole whose access right should be checked
     * @param resource List of resourceids in the order they should be validated
     * @param action the required action.
     * @return One of the predefined values URMPermit, URMDeny,
     *              URMIndeterminable, URMNotApplicable.
     *
     * @throws URMAccessCheckException if the access check fails.
     *
     * @see URMAclValidator
     */
    public int checkPermission(URMPrincipal principal, URMRole role, List resource, String action)
        throws URMAccessCheckException {
        return checkPermissionResult(principal, role, resource, action).getPermission();
    }
    /** Processes an access check of a URMRole.
     *
     * @param principal the principal of the authenticated user.
     * @param role URMRole whose access right should be checked
     * @param resource List of resourceids in the order they should be validated
     * @param action the required action.
     * @return URMPermissionResult
     *
     * @throws URMAccessCheckException if the access check fails.
     *
     * @see URMAclValidator
     */
    public URMPermissionResult checkPermissionResult(URMPrincipal principal, URMRole role, List resource, String action)
        throws URMAccessCheckException
    {
        boolean deny = false;
        boolean grant = false;
        URMPermissionResultImpl _permission = null;
        try {
            if ((principal == null) || (resource == null) || (role == null) || (action == null) || (action.equals("")) || (resource.isEmpty())) {
                return _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, null, null);
            }
            
            // check if the role has URMRoot rights
            grant = isRoot(role);
            
            // check if requested validation has already been done and cached
            String subjectCacheId = "role:" + role.getName();
            
            String resourceid = null;
            Iterator resourceIter = resource.iterator();
            while (resourceIter.hasNext()) {
                if (resourceid == null) resourceid = (String) resourceIter.next();
                else resourceid = resourceid + "/" + (String) resourceIter.next();
            }
  
            URMPermissionResult permission = validatorCache.checkPermission(resourceid, subjectCacheId, action);
            if (permission != null) return permission;
            
            URMAclAdministrator aclAdmin = principal.getURMAclAdministrator();
            List aclList = aclAdmin.getAclPath(resource);
            Iterator aclListIter = aclList.iterator();
            URMAcl acl = null;
            
            // after loaded the acl, check again against cache. Maybe some acls are null and url is known
            String aclid = null;
            while (aclListIter.hasNext()) {
                if (aclid == null) aclid = ((URMAcl) aclListIter.next()).getId();
                else aclid = aclid + "/" + ((URMAcl) aclListIter.next()).getId();
            }
            permission = validatorCache.checkPermission(aclid, subjectCacheId, action);
            if (permission != null) {
                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                return permission;
            }
            
            aclListIter = aclList.iterator();
            // resolve action into base actions
            HashMap actionMap = new HashMap();
            URMAction urmAction = aclAdmin.getAction(action);
            if (urmAction == null) throw new URMAccessCheckException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038"));
            resolveActionMapping(aclAdmin, urmAction, actionMap);

            // resolve predefined actions
            int preActionResult = resolvePredefinedActions(role, aclAdmin, actionMap);
            if (preActionResult == URMAclValidator.URMDeny) deny = true;
            if (preActionResult == URMAclValidator.URMPermit) grant = true;
            if (!grant) grant = verifyGrant(actionMap);
            
            // iterate through the ACL List
            while (!deny && !grant && aclListIter.hasNext()) {
                acl = (URMAcl) aclListIter.next();
                List aceList = acl.getAllAces();
                Iterator aceListIter = aceList.iterator();
                URMAce ace = null;
        
                while (!deny && !grant && aceListIter.hasNext()) {
                    ace = (URMAce) aceListIter.next();
                    
                    // check if the current ACE is inverted
                    if (ace.getInvert()) {
                        // if inverted, create to helper ACEs one for the current
                        // subject with inverted action and one for all subjects
                        // with the not inverted action
                        URMAce ace1 = new URMAceImpl (ace, !ace.getInvert());
                        URMAce aceAll = new URMAceImpl (ace, principal.getURMAdministrator().getALLSubject());
                        List invertAces = new ArrayList();
                        invertAces.add(ace1);
                        invertAces.add(aceAll);
                        Iterator invertAcesIter = invertAces.iterator();
                        while (!deny && !grant && invertAcesIter.hasNext()) {
                            URMAce currentAce = (URMAce) invertAcesIter.next();
                            // validate if the ACE matches the principal
                            int aceMatch = validateAce(role, currentAce, aclAdmin, actionMap);
                                      
                            if (aceMatch == URMAclValidator.URMPermit) {
                                grant = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMDeny) {
                                deny = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMNotApplicable) {
                                _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                            validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                            return _permission;
                            }
                        }
                    } else {
                        // if not inverted,
                        // validate if the ACE matches the principal
                        int aceMatch = validateAce(role, ace, aclAdmin, actionMap);
                                      
                        if (aceMatch == URMAclValidator.URMPermit) {
                            grant = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMDeny) {
                            deny = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMNotApplicable) {
                            _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                            validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                            return _permission;
                        }
                    }
                }
            }
            
            if ((!deny) && (grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMPermit);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return _permission;
            }
            else if ((deny) && (!grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMDeny);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return _permission;
            }
            else {
                _permission = new URMPermissionResultImpl(URMAclValidator.URMIndeterminate, null, null);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return _permission;
            }
            
        } catch (URMException e) {
            throw new URMAccessCheckException(msLogger, "E", e);
        }
    }

    /** Processes an access check of a URMSubject.
     *
     * @param principal the principal of the authenticated user.
     * @param subject whose access right should be checked
     * @param resource the resourceid for that the validation should be done.
     * @param action the required action.
     * @return One of the predefined values URMPermit, URMDeny,
     *              URMIndeterminable, URMNotApplicable.
     *
     * @throws URMAccessCheckException if the access check fails.
     *
     * @see URMAclValidator
     */
    public int subjectPermissionReport(URMPrincipal principal, URMSubject subject, List resource, String action)
        throws URMAccessCheckException {
        try {
            if (subject != null) {
                switch (subject.getType()) {
                    case URMConstants.ROLE:
                        return checkPermission (principal, (URMRole) subject, resource, action);
                    case URMConstants.USER:
                        return checkUserPermission(principal, subject.getName(), subject.getDomain(), resource, action);
                    case URMConstants.GROUP:
                        return checkGroupPermission(principal, subject.getName(), subject.getDomain(), resource, action);
                }
            }
            return URMAclValidator.URMNotApplicable;
        } catch (URMException e) {
            throw new URMAccessCheckException(msLogger, "E", e);
        }
    }
    
    /** Processes an access check of a URMRole.
     *
     * @param principal the principal of the authenticated user.
     * @param role URMRole whose access right should be checked
     * @param resource the resourceid for that the validation should be done.
     * @param action the required action.
     * @return URMPermissionResult
     *
     * @throws URMAccessCheckException if the access check fails.
     *
     * @see URMAclValidator
     */
    public URMPermissionResult checkRolePermissionResult(URMPrincipal principal, URMRole role, List resource, String action)
        throws URMAccessCheckException {
        try {
            return checkPermissionResult (principal, role, resource, action);
        } catch (URMException e) {
            throw new URMAccessCheckException(msLogger, "E", e);
        }
    }
    
    /** Processes an access check.
     *
     * @param principal the principal of the authenticated user.
     * @param user user whose access right should be checked
     * @param domain users domain, has to be null if the underlying userdb does
     *        not support domains.
     * @param resource the resourceid for that the validation should be done.
     * @param action the required action.
     * @return One of the predefined values URMPermit, URMDeny,
     *              URMIndeterminable, URMNotApplicable.
     *
     * @throws URMAccessCheckException if the access check fails.
     *
     * @see URMAclValidator
     */
    public int checkUserPermission(URMPrincipal principal, String user, String domain, List resource, String action)
        throws URMAccessCheckException
    {
        boolean deny = false;
        boolean grant = false;
        URMPermissionResultImpl _permission = null;
        try {
            if ((principal == null) || (resource == null) || (action == null) || (action.equals("")) || (resource.isEmpty())|| (user == null) || (user.equals("")) ) {
                return URMAclValidator.URMNotApplicable;
            }
            
            // check if requested validation has already been done and cached
            String subjectCacheId = null;
            if (domain != null) {
                subjectCacheId = "user:" + domain + "/" + user;
            } else {
                subjectCacheId = "user:" + user;
            }
            
            String resourceid = null;
            Iterator resourceIter = resource.iterator();
            while (resourceIter.hasNext()) {
                if (resourceid == null) resourceid = (String) resourceIter.next();
                else resourceid = resourceid + "/" + (String) resourceIter.next();
            }
            
            URMPermissionResult permission = validatorCache.checkPermission(resourceid, subjectCacheId, action);
            if (permission != null) return permission.getPermission();
            
            URMAdministrator urmAdmin = principal.getURMAdministrator();
            URMAclAdministrator aclAdmin = principal.getURMAclAdministrator();
            List aclList = aclAdmin.getAclPath(resource);
            Iterator aclListIter = aclList.iterator();
            URMAcl acl = null;
            
            // after loaded the acl, check again against cache. Maybe some acls are null and url is known
            String aclid = null;
            while (aclListIter.hasNext()) {
                if (aclid == null) aclid = ((URMAcl) aclListIter.next()).getId();
                else aclid = aclid + "/" + ((URMAcl) aclListIter.next()).getId();
            }
            permission = validatorCache.checkPermission(aclid, subjectCacheId, action);
            if (permission != null) {
                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                return permission.getPermission();
            }
            
            aclListIter = aclList.iterator();
            // resolve action into base actions
            HashMap actionMap = new HashMap();
            URMAction urmAction = aclAdmin.getAction(action);
            if (urmAction == null) throw new URMAccessCheckException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038"));
            resolveActionMapping(aclAdmin, urmAction, actionMap);

            URMUser urmUser = urmAdmin.getUser(user, domain);
            if (urmUser == null) return URMAclValidator.URMNotApplicable;
                    
            // iterate through the ACL List
            while (!deny && !grant && aclListIter.hasNext()) {
                acl = (URMAcl) aclListIter.next();
                List aceList = acl.getAllAces();
                Iterator aceListIter = aceList.iterator();
                URMAce ace = null;
                
                // iterate through the ACEs of the current resources ACL
                while (!deny && !grant && aceListIter.hasNext()) {
                    ace = (URMAce) aceListIter.next();
                    
                    // check if the current ACE is inverted
                    if (ace.getInvert()) {
                        // if inverted, create to helper ACEs one for the current
                        // subject with inverted action and one for all subjects
                        // with the not inverted action
                        URMAce ace1 = new URMAceImpl (ace, !ace.getInvert());
                        URMAce aceAll = new URMAceImpl (ace, principal.getURMAdministrator().getALLSubject());
                        List invertAces = new ArrayList();
                        invertAces.add(ace1);
                        invertAces.add(aceAll);
                        Iterator invertAcesIter = invertAces.iterator();
                        while (!deny && !grant && invertAcesIter.hasNext()) {
                            URMAce currentAce = (URMAce) invertAcesIter.next();
                            // validate if the ACE matches the principal
                            int aceMatch = validateAce(urmUser, currentAce, urmAdmin, aclAdmin, actionMap);
                                      
                            if (aceMatch == URMAclValidator.URMPermit) {
                                grant = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMDeny) {
                                deny = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMNotApplicable) {
                                _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                                return aceMatch;
                            }
                        }
                    } else {
                        // if not inverted,
                        // validate if the ACE matches the principal
                        int aceMatch = validateAce(urmUser, ace, urmAdmin, aclAdmin, actionMap);
                                      
                        if (aceMatch == URMAclValidator.URMPermit) {
                            grant = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMDeny) {
                            deny = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMNotApplicable) {
                            _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                            validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                            return aceMatch;
                        }
                    }
                }
            }
                        
            if ((!deny) && (grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMPermit);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return URMAclValidator.URMPermit;
            }
            else if ((deny) && (!grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMDeny);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return URMAclValidator.URMDeny;
            }
            else {
                _permission = new URMPermissionResultImpl(URMAclValidator.URMIndeterminate, null, null);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return URMAclValidator.URMIndeterminate;
            }
            
        } catch (URMException e) {
            throw new URMAccessCheckException(msLogger, "E", e);
        }
    }
    
        /** Processes an access check.
     *
     * @param principal the principal of the authenticated user.
     * @param user user whose access right should be checked
     * @param domain users domain, has to be null if the underlying userdb does
     *        not support domains.
     * @param resource the resourceid for that the validation should be done.
     * @param action the required action.
     * @return One of the predefined values URMPermit, URMDeny,
     *              URMIndeterminable, URMNotApplicable.
     *
     * @throws URMAccessCheckException if the access check fails.
     *
     * @see URMAclValidator
     */
    public URMPermissionResult checkUserPermissionResult(URMPrincipal principal, String user, String domain, List resource, String action)
        throws URMAccessCheckException
    {
        boolean deny = false;
        boolean grant = false;
        URMPermissionResultImpl _permission = null;
        try {
            if ((principal == null) || (resource == null) || (action == null) || (action.equals("")) || (resource.isEmpty())|| (user == null) || (user.equals("")) ) {
                return new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, null, null);
            }
            
            // check if requested validation has already been done and cached
            String subjectCacheId = null;
            if (domain != null) {
                subjectCacheId = "user:" + domain + "/" + user;
            } else {
                subjectCacheId = "user:" + user;
            }
            
            String resourceid = null;
            Iterator resourceIter = resource.iterator();
            while (resourceIter.hasNext()) {
                if (resourceid == null) resourceid = (String) resourceIter.next();
                else resourceid = resourceid + "/" + (String) resourceIter.next();
            }
            
            URMPermissionResult permission = validatorCache.checkPermission(resourceid, subjectCacheId, action);
            if (permission != null) return permission;
            
            URMAdministrator urmAdmin = principal.getURMAdministrator();
            URMAclAdministrator aclAdmin = principal.getURMAclAdministrator();
            List aclList = aclAdmin.getAclPath(resource);
            Iterator aclListIter = aclList.iterator();
            URMAcl acl = null;
            
            // after loaded the acl, check again against cache. Maybe some acls are null and url is known
            String aclid = null;
            while (aclListIter.hasNext()) {
                if (aclid == null) aclid = ((URMAcl) aclListIter.next()).getId();
                else aclid = aclid + "/" + ((URMAcl) aclListIter.next()).getId();
            }
            permission = validatorCache.checkPermission(aclid, subjectCacheId, action);
            if (permission != null) {
                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                return permission;
            }
            
            aclListIter = aclList.iterator();
            // resolve action into base actions
            HashMap actionMap = new HashMap();
            URMAction urmAction = aclAdmin.getAction(action);
            if (urmAction == null) throw new URMAccessCheckException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038"));
            resolveActionMapping(aclAdmin, urmAction, actionMap);

            URMUser urmUser = urmAdmin.getUser(user, domain);
            if (urmUser == null) return new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, null, null);
                    
            // iterate through the ACL List
            while (!deny && !grant && aclListIter.hasNext()) {
                acl = (URMAcl) aclListIter.next();
                List aceList = acl.getAllAces();
                Iterator aceListIter = aceList.iterator();
                URMAce ace = null;
                
                // iterate through the ACEs of the current resources ACL
                while (!deny && !grant && aceListIter.hasNext()) {
                    ace = (URMAce) aceListIter.next();
                    
                    // check if the current ACE is inverted
                    if (ace.getInvert()) {
                        // if inverted, create to helper ACEs one for the current
                        // subject with inverted action and one for all subjects
                        // with the not inverted action
                        URMAce ace1 = new URMAceImpl (ace, !ace.getInvert());
                        URMAce aceAll = new URMAceImpl (ace, principal.getURMAdministrator().getALLSubject());
                        List invertAces = new ArrayList();
                        invertAces.add(ace1);
                        invertAces.add(aceAll);
                        Iterator invertAcesIter = invertAces.iterator();
                        while (!deny && !grant && invertAcesIter.hasNext()) {
                            URMAce currentAce = (URMAce) invertAcesIter.next();
                            // validate if the ACE matches the principal
                            int aceMatch = validateAce(urmUser, currentAce, urmAdmin, aclAdmin, actionMap);
                                      
                            if (aceMatch == URMAclValidator.URMPermit) {
                                grant = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMDeny) {
                                deny = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMNotApplicable) {
                                _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                                return _permission;
                            }
                        }
                    } else {
                        // if not inverted,
                        // validate if the ACE matches the principal
                        int aceMatch = validateAce(urmUser, ace, urmAdmin, aclAdmin, actionMap);
                                      
                        if (aceMatch == URMAclValidator.URMPermit) {
                            grant = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMDeny) {
                            deny = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMNotApplicable) {
                            _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                            validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                            return _permission;
                        }
                    }
                }
            }
                        
            if ((!deny) && (grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMPermit);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return _permission;
            }
            else if ((deny) && (!grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMDeny);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return _permission;
            }
            else {
                _permission = new URMPermissionResultImpl(URMAclValidator.URMIndeterminate, null, null);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return _permission;
            }
            
        } catch (URMException e) {
            throw new URMAccessCheckException(msLogger, "E", e);
        }
    }
    
    /** Processes an access check.
     *
     * @param principal the principal of the authenticated user.
     * @param group group whose access right should be checked
     * @param domain group domain, has to be null if the underlying userdb does
     *        not support domains.
     * @param resource the resourceid for that the validation should be done.
     * @param action the required action.
     * @return One of the predefined values URMPermit, URMDeny,
     *              URMIndeterminable, URMNotApplicable.
     *
     * @throws URMAccessCheckException if the access check fails.
     *
     * @see URMAclValidator
     */
    public int checkGroupPermission(URMPrincipal principal, String group, String domain, List resource, String action)
        throws URMAccessCheckException
    {
        boolean deny = false;
        boolean grant = false;
        URMPermissionResultImpl _permission = null;
        try {
            if ((principal == null) || (resource == null) || (action == null) || (action.equals("")) || (resource.isEmpty())|| (group == null) || (group.equals("")) ) {
                return URMAclValidator.URMNotApplicable;
            }
            
            // check if requested validation has already been done and cached
            String subjectCacheId = null;
            if (domain != null) {
                subjectCacheId = "group:" + domain + "/" + group;
            } else {
                subjectCacheId = "group:" + group;
            }
            
            String resourceid = null;
            Iterator resourceIter = resource.iterator();
            while (resourceIter.hasNext()) {
                if (resourceid == null) resourceid = (String) resourceIter.next();
                else resourceid = resourceid + "/" + (String) resourceIter.next();
            }
            
            URMPermissionResult permission = validatorCache.checkPermission(resourceid, subjectCacheId, action);
            if (permission != null) return permission.getPermission();
            
            URMAdministrator urmAdmin = principal.getURMAdministrator();
            URMAclAdministrator aclAdmin = principal.getURMAclAdministrator();
            List aclList = aclAdmin.getAclPath(resource);
            Iterator aclListIter = aclList.iterator();
            URMAcl acl = null;
            
            // after loaded the acl, check again against cache. Maybe some acls are null and url is known
            String aclid = null;
            while (aclListIter.hasNext()) {
                if (aclid == null) aclid = ((URMAcl) aclListIter.next()).getId();
                else aclid = aclid + "/" + ((URMAcl) aclListIter.next()).getId();
            }
            permission = validatorCache.checkPermission(aclid, subjectCacheId, action);
            if (permission != null) {
                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                return permission.getPermission();
            }
            
            aclListIter = aclList.iterator();
            // resolve action into base actions
            HashMap actionMap = new HashMap();
            URMAction urmAction = aclAdmin.getAction(action);
            if (urmAction == null) throw new URMAccessCheckException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038"));
            resolveActionMapping(aclAdmin, urmAction, actionMap);

            URMGroup urmGroup = urmAdmin.getGroup(group, domain);
            if (urmGroup == null) return URMAclValidator.URMNotApplicable;
                    
            // iterate through the ACL List
            while (!deny && !grant && aclListIter.hasNext()) {
                acl = (URMAcl) aclListIter.next();
                List aceList = acl.getAllAces();
                Iterator aceListIter = aceList.iterator();
                URMAce ace = null;
                
                // iterate through the ACEs of the current resources ACL
                while (!deny && !grant && aceListIter.hasNext()) {
                    ace = (URMAce) aceListIter.next();
                    
                    // check if the current ACE is inverted
                    if (ace.getInvert()) {
                        // if inverted, create to helper ACEs one for the current
                        // subject with inverted action and one for all subjects
                        // with the not inverted action
                        URMAce ace1 = new URMAceImpl (ace, !ace.getInvert());
                        URMAce aceAll = new URMAceImpl (ace, principal.getURMAdministrator().getALLSubject());
                        List invertAces = new ArrayList();
                        invertAces.add(ace1);
                        invertAces.add(aceAll);
                        Iterator invertAcesIter = invertAces.iterator();
                        while (!deny && !grant && invertAcesIter.hasNext()) {
                            URMAce currentAce = (URMAce) invertAcesIter.next();
                            // validate if the ACE matches the principal
                            int aceMatch = validateAce(urmGroup, currentAce, urmAdmin, aclAdmin, actionMap);
                                      
                            if (aceMatch == URMAclValidator.URMPermit) {
                                grant = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMDeny) {
                                deny = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMNotApplicable) {
                                _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                                return aceMatch;
                            }
                        }
                    } else {
                        // if not inverted,
                        // validate if the ACE matches the principal
                        int aceMatch = validateAce(urmGroup, ace, urmAdmin, aclAdmin, actionMap);
                                      
                        if (aceMatch == URMAclValidator.URMPermit) {
                            grant = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMDeny) {
                            deny = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMNotApplicable) {
                            _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                            validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                            return aceMatch;
                        }
                    }
                }
            }
                        
            if ((!deny) && (grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMPermit);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return URMAclValidator.URMPermit;
            }
            else if ((deny) && (!grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMDeny);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return URMAclValidator.URMDeny;
            }
            else {
                _permission = new URMPermissionResultImpl(URMAclValidator.URMIndeterminate, null, null);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return URMAclValidator.URMIndeterminate;
            }
            
        } catch (URMException e) {
            throw new URMAccessCheckException(msLogger, "E", e);
        }
    }
    
    /** Processes an access check.
     *
     * @param principal the principal of the authenticated user.
     * @param group group whose access right should be checked
     * @param domain group domain, has to be null if the underlying userdb does
     *        not support domains.
     * @param resource the resourceid for that the validation should be done.
     * @param action the required action.
     * @return One of the predefined values URMPermit, URMDeny,
     *              URMIndeterminable, URMNotApplicable.
     *
     * @throws URMAccessCheckException if the access check fails.
     *
     * @see URMAclValidator
     */
    public URMPermissionResult checkGroupPermissionResult(URMPrincipal principal, String group, String domain, List resource, String action)
        throws URMAccessCheckException
    {
        boolean deny = false;
        boolean grant = false;
        URMPermissionResultImpl _permission = null;
        try {
            if ((principal == null) || (resource == null) || (action == null) || (action.equals("")) || (resource.isEmpty())|| (group == null) || (group.equals("")) ) {
                return new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, null, null);
            }
            
            // check if requested validation has already been done and cached
            String subjectCacheId = null;
            if (domain != null) {
                subjectCacheId = "group:" + domain + "/" + group;
            } else {
                subjectCacheId = "group:" + group;
            }
            
            String resourceid = null;
            Iterator resourceIter = resource.iterator();
            while (resourceIter.hasNext()) {
                if (resourceid == null) resourceid = (String) resourceIter.next();
                else resourceid = resourceid + "/" + (String) resourceIter.next();
            }
            
            URMPermissionResult permission = validatorCache.checkPermission(resourceid, subjectCacheId, action);
            if (permission != null) return permission;
            
            URMAdministrator urmAdmin = principal.getURMAdministrator();
            URMAclAdministrator aclAdmin = principal.getURMAclAdministrator();
            List aclList = aclAdmin.getAclPath(resource);
            Iterator aclListIter = aclList.iterator();
            URMAcl acl = null;
            
            // after loaded the acl, check again against cache. Maybe some acls are null and url is known
            String aclid = null;
            while (aclListIter.hasNext()) {
                if (aclid == null) aclid = ((URMAcl) aclListIter.next()).getId();
                else aclid = aclid + "/" + ((URMAcl) aclListIter.next()).getId();
            }
            permission = validatorCache.checkPermission(aclid, subjectCacheId, action);
            if (permission != null) {
                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                return permission;
            }
            
            aclListIter = aclList.iterator();
            
            // resolve action into base actions
            HashMap actionMap = new HashMap();
            URMAction urmAction = aclAdmin.getAction(action);
            if (urmAction == null) throw new URMAccessCheckException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038"));
            resolveActionMapping(aclAdmin, urmAction, actionMap);

            URMGroup urmGroup = urmAdmin.getGroup(group, domain);
            if (urmGroup == null) return new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, null, null);
                    
            // iterate through the ACL List
            while (!deny && !grant && aclListIter.hasNext()) {
                acl = (URMAcl) aclListIter.next();
                List aceList = acl.getAllAces();
                Iterator aceListIter = aceList.iterator();
                URMAce ace = null;
                
                // iterate through the ACEs of the current resources ACL
                while (!deny && !grant && aceListIter.hasNext()) {
                    ace = (URMAce) aceListIter.next();
                    
                    // check if the current ACE is inverted
                    if (ace.getInvert()) {
                        // if inverted, create to helper ACEs one for the current
                        // subject with inverted action and one for all subjects
                        // with the not inverted action
                        URMAce ace1 = new URMAceImpl (ace, !ace.getInvert());
                        URMAce aceAll = new URMAceImpl (ace, principal.getURMAdministrator().getALLSubject());
                        List invertAces = new ArrayList();
                        invertAces.add(ace1);
                        invertAces.add(aceAll);
                        Iterator invertAcesIter = invertAces.iterator();
                        while (!deny && !grant && invertAcesIter.hasNext()) {
                            URMAce currentAce = (URMAce) invertAcesIter.next();
                            // validate if the ACE matches the principal
                            int aceMatch = validateAce(urmGroup, currentAce, urmAdmin, aclAdmin, actionMap);
                                      
                            if (aceMatch == URMAclValidator.URMPermit) {
                                grant = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMDeny) {
                                deny = true;
                                _permission = new URMPermissionResultImpl(ace, acl.getId());
                            }
                            else if (aceMatch == URMAclValidator.URMNotApplicable) {
                                _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                                validatorCache.addPermission(resource, subjectCacheId, action, permission);
                                return _permission;
                            }
                        }
                    } else {
                        // if not inverted,
                        // validate if the ACE matches the principal
                        int aceMatch = validateAce(urmGroup, ace, urmAdmin, aclAdmin, actionMap);
                                      
                        if (aceMatch == URMAclValidator.URMPermit) {
                            grant = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMDeny) {
                            deny = true;
                            _permission = new URMPermissionResultImpl(ace, acl.getId());
                        }
                        else if (aceMatch == URMAclValidator.URMNotApplicable) {
                            _permission = new URMPermissionResultImpl(URMAclValidator.URMNotApplicable, ace, acl.getId());
                            validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                            return _permission;
                        }
                    }
                }
            }
                        
            if ((!deny) && (grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMPermit);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return _permission;
            }
            else if ((deny) && (!grant)) {
                if (_permission == null) _permission = new URMPermissionResultImpl(null, URMConstants.PREDEFINED_ACTION);
                _permission.setPermission(URMAclValidator.URMDeny);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return _permission;
            }
            else {
                _permission = new URMPermissionResultImpl(URMAclValidator.URMIndeterminate, null, null);
                validatorCache.addPermission(resource, subjectCacheId, action, _permission);
                return _permission;
            }
            
        } catch (URMException e) {
            throw new URMAccessCheckException(msLogger, "E", e);
        }
    }
    
    /**
     * Returns a set of URMUsers that are allowed to execute the specified action
     * at the passed resource.
     *
     * @param principal authenticated user who invokes this report method
     * @param action the action against the validation should be done.
     * @param resource the resourceid for that the validation should be done.
     *
     * @return the Set of URMUsers that are allowed to execute the passed action
     *         at the specified resource. If the action is not allowed for any user,
     *         the Set will be empty
     *
     * @throws URMInternalServerException if any error occures
     **/
    public Set userWithPermissionReport(URMPrincipal principal, String action, List resource)
        throws URMInternalServerException
    {
        Set grantedUsersSet = new HashSet();
        Set deniedUsesSet = new HashSet();
        URMAclAdministrator aclAdmin = null;
        try {
            if ((principal == null) || (resource == null) || (action == null) || (action.equals("")) || (resource.isEmpty())) {
                return grantedUsersSet;
            }
            aclAdmin = principal.getURMAclAdministrator();
            
            String resourceid = null;
            Iterator resourceIter = resource.iterator();
            while (resourceIter.hasNext()) {
                if (resourceid == null) resourceid = (String) resourceIter.next();
                else resourceid = resourceid + "/" + (String) resourceIter.next();
            }
            
            // resolve action into base actions
            HashMap actionMap = new HashMap();
            URMAction urmAction = aclAdmin.getAction(action);
            if (urmAction == null) throw new URMAccessCheckException(MessageLogger.getAndLogMessage(msLogger, "URMCOE0038"));
            resolveActionMapping(aclAdmin, urmAction, actionMap);
            List actions = new ArrayList(actionMap.keySet());
            actions.add(action);
            List acls = aclAdmin.getAclsWithSpecificAction(resource, actions);
            Iterator aclIter = acls.iterator();
            while (aclIter.hasNext()) {
                URMAcl acl = (URMAcl) aclIter.next();
                Iterator aceIter = acl.getAllAces().iterator();
                while (aceIter.hasNext()) {
                    URMAce ace = (URMAce) aceIter.next();
                    URMSubject subject = ace.getSubject();
                    
                    // check if ACE is inverted
                    if (ace.getInvert()) {
                        // if inverted
                        if (ace.getType() == URMConstants.GRANT) {
                            resolveSubjectToUser(principal, subject, grantedUsersSet, deniedUsesSet, false);
                            resolveSubjectToUser(principal, principal.getURMAdministrator().getALLSubject(), grantedUsersSet, deniedUsesSet, true);
                        } else {
                            resolveSubjectToUser(principal, subject, grantedUsersSet, deniedUsesSet, true);
                            resolveSubjectToUser(principal, principal.getURMAdministrator().getALLSubject(), grantedUsersSet, deniedUsesSet, false);
                        }
                    } else {
                        // if not inverted
                        if (ace.getType() == URMConstants.GRANT) resolveSubjectToUser(principal, subject, grantedUsersSet, deniedUsesSet, true);
                        else resolveSubjectToUser(principal, subject, grantedUsersSet, deniedUsesSet, false);
                    }
                }
            }
            return grantedUsersSet;
        } catch (URMException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }
    
    /**
     * Returns a map of names (key) and Boolean (value) containing the actions
     * that are specified for the passed subject at the resource. If the value is
     * 'true' the action is granted, if false the action is denied. Inherited
     * actions are considered as well.
     *
     * @param principal authenticated user who invokes this report method
     * @param subject whose rights should be returned
     * @param resource the resourceid for that the validation should be done.
     *
     * @return names and value of the URMActions that are defined for the user at
     *         the resource.
     *
     * @throws URMInternalServerException if any error occures
     **/
    public Map subjectPermissionSetReport(URMPrincipal principal, URMSubject subject, List resource)
        throws URMAccessCheckException {
        try {
            if (subject != null) {
                switch (subject.getType()) {
                    case URMConstants.ROLE:
                        return rolePermissionReport (principal, (URMRole) subject, resource);
                    case URMConstants.USER:
                        return userPermissionReport(principal, subject.getName(), subject.getDomain(), resource);
                    case URMConstants.GROUP:
                        return groupPermissionReport(principal, subject.getName(), subject.getDomain(), resource);
                }
            }
            return new HashMap();
        } catch (URMException e) {
            throw new URMAccessCheckException(msLogger, "E", e);
        }
    }
    
    /**
     * Returns a map of names (key) and Boolean (value) containing the actions
     * that are specified for the passed user at the resource. If the value is
     * 'true' the action is granted, if false the action is denied. Inherited
     * actions are considered as well.
     *
     * @param principal, authenticated user who invokes this report method
     * @param user, the user whose rights should be returned
     * @param domain, users domain, has to be null if the underlying userdb does
     *        not support domains.
     * @param resource, the resourceid for that the validation should be done.
     *
     * @return names and value of the URMActions that are defined for the user at
     *         the resource.
     *
     * @throws URMInternalServerException if any error occures
     **/
    private Map userPermissionReport(URMPrincipal principal, String user, String domain, List resource)
        throws URMInternalServerException
    {
        try {
            Set uncheckedActions = null;
            Map userActions = new HashMap();
            URMAclAdministrator aclAdmin = principal.getURMAclAdministrator();
            
            // get all actions that have to be validated for the user at the resource
            uncheckedActions = aclAdmin.getAllActions();
            Iterator uncheckedActionsIter = uncheckedActions.iterator();
            while (uncheckedActionsIter.hasNext()) {
                URMAction currentAction = (URMAction) uncheckedActionsIter.next();
                String action = currentAction.getName();
                URMPermissionResult result = checkUserPermissionResult(principal, user, domain, resource, action);
                if ((result.getPermission() == URMAclValidator.URMDeny) || (result.getPermission() == URMAclValidator.URMPermit)) userActions.put(action ,result);
             }
            return userActions;
        } catch (URMException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }
    
    /**
     * Returns a map of names (key) and Boolean (value) containing the actions
     * that are specifies for the passed user at the resource. If the value is
     * 'true' the action is granted, if false the action is denied. Inherited
     * actions are considered as well.
     *
     * @param principal, authenticated user who invokes this report method
     * @param group, the group whose rights should be returned
     * @param domain, groups domain, has to be null if the underlying userdb does
     *        not support domains.
     * @param resource, the resourceid for that the validation should be done.
     *
     * @return names and value of the URMActions that are defined for the user at
     *         the resource.
     *
     * @throws URMInternalServerException if any error occures
     **/
    private Map groupPermissionReport(URMPrincipal principal, String group, String domain, List resource)
        throws URMInternalServerException
    {
        try {
            Set uncheckedActions = null;
            Map userActions = new HashMap();
            URMAclAdministrator aclAdmin = principal.getURMAclAdministrator();
            
            // get all actions that have to be validated for the user at the resource
            uncheckedActions = aclAdmin.getAllActions();
            Iterator uncheckedActionsIter = uncheckedActions.iterator();
            while (uncheckedActionsIter.hasNext()) {
                URMAction currentAction = (URMAction) uncheckedActionsIter.next();
                String action = currentAction.getName();
                URMPermissionResult result = checkGroupPermissionResult(principal, group, domain, resource, action);
                if ((result.getPermission() == URMAclValidator.URMDeny) || (result.getPermission() == URMAclValidator.URMPermit)) userActions.put(action ,result);
            }
            return userActions;
        } catch (URMException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }
    
    /**
     * Returns a map of names (key) and Boolean (value) containing the actions
     * that are specifies for the passed role at the resource. If the value is
     * 'true' the action is granted, if false the action is denied. Inherited
     * actions are considered as well.
     *
     * @param principal, authenticated user who invokes this report method
     * @param role, the role whose rights should be returned
     * @param resource, the resourceid for that the validation should be done.
     *
     * @return names and value of the URMActions that are defined for the user at
     *         the resource.
     *
     * @throws URMInternalServerException if any error occures
     **/
    private Map rolePermissionReport(URMPrincipal principal, URMRole role, List resource)
        throws URMInternalServerException
    {
        try {
            Set uncheckedActions = null;
            Map userActions = new HashMap();
            URMAclAdministrator aclAdmin = principal.getURMAclAdministrator();
            
            // get all actions that have to be validated for the user at the resource
            uncheckedActions = aclAdmin.getAllActions();
            Iterator uncheckedActionsIter = uncheckedActions.iterator();
            while (uncheckedActionsIter.hasNext()) {
                URMAction currentAction = (URMAction) uncheckedActionsIter.next();
                String action = currentAction.getName();
                URMPermissionResult result = checkRolePermissionResult (principal, role, resource, action);
                if ((result.getPermission() == URMAclValidator.URMDeny) || (result.getPermission() == URMAclValidator.URMPermit)) userActions.put(action ,result);
            }
            return userActions;
        } catch (URMException e) {
            throw new URMInternalServerException(msLogger, "E", e);
        }
    }
    
    /**
     * Verifies, if the ACE denies or grants the requested action
     *
     * @param    ace                 an URMAce
     * @param    aclAdmin            an URMAclAdministrator
     * @param    actionMap           a  Map
     *
     * @return   an int, URMAclValidator.URMNotApplicable, URMAclValidator.URMPermit, URMAclValidator.URMDeny
     *
     * @throws   URMInternalServerException
     *
     */
    private int resolveAceActionMapping(URMAce ace, URMAclAdministrator aclAdmin, Map actionMap) throws URMInternalServerException{
        
        int result = URMAclValidator.URMIndeterminate;
        boolean deny = false;
        boolean grant = false;
        URMAction aceAction = ace.getAction();
        
        if (aceAction.getName().equals(URMConstants.URM_ALL_ACTION)){
            if (ace.getType() == URMConstants.DENY) deny = true;
            else if (ace.getType() == URMConstants.GRANT) grant = true;
            else return URMAclValidator.URMNotApplicable;
        }else {
            Set aceBaseActions = new HashSet();
            resolveActionMapping(aclAdmin, aceAction, aceBaseActions);
            Iterator aceBaseActionsIter = aceBaseActions.iterator();
                            
            if (ace.getType() == URMConstants.DENY) {
                // ace is denied
                while ((!deny && aceBaseActionsIter.hasNext())) {
                    String currentAction = (String) aceBaseActionsIter.next();
                    if ((((actionMap.containsKey(currentAction))) && !(((Boolean) actionMap.get(currentAction)).booleanValue()))
                        || (((actionMap.containsKey(URMConstants.URM_ALL_ACTION))) && !(((Boolean) actionMap.get(URMConstants.URM_ALL_ACTION)).booleanValue())))
                        deny = true;
                }
                                
            } else if (ace.getType() == URMConstants.GRANT){
                // ace is granted
                while ((!grant && aceBaseActionsIter.hasNext())) {
                    String currentAction = (String) aceBaseActionsIter.next();
                    if (actionMap.containsKey(currentAction)) {
                        actionMap.put(currentAction, new Boolean(true));
                        grant = verifyGrant(actionMap);
                    }
                }
                                
            } else return URMAclValidator.URMNotApplicable;
        }
    
        if ((!deny) && (grant)) result =  URMAclValidator.URMPermit;
        else if ((deny) && (!grant)) result = URMAclValidator.URMDeny;
        return result;
    }

    private int validateAce (URMPrincipal principal,URMAce ace, URMAclAdministrator aclAdmin, Map actionMap) throws URMException, URMInternalServerException {
        boolean subjectMatch = false;
        // analyse the ACE Subject
        URMSubject subject = ace.getSubject();
        // check if the principal is represented by the subject
        subjectMatch = isSubject(principal, subject);
        if (subjectMatch) {
            // if the subject matches, verify if the ace denies or grants the requested action
            return (resolveAceActionMapping(ace, aclAdmin, actionMap));
        } else {
            return (URMAclValidator.URMIndeterminate);
        }
    }
    
    private int validateAce (URMUser urmUser,URMAce ace, URMAdministrator urmAdmin, URMAclAdministrator aclAdmin, Map actionMap) throws URMException, URMInternalServerException {
        boolean subjectMatch = false;
        // analyse the ACE Subject
        URMSubject subject = ace.getSubject();
        // check if the principal is represented by the subject
        subjectMatch = isSubject(urmAdmin, urmUser, subject);
        if (subjectMatch) {
            // if the subject matches, verify if the ace denies or grants the requested action
            return (resolveAceActionMapping(ace, aclAdmin, actionMap));
        } else {
            return (URMAclValidator.URMIndeterminate);
        }
    }
    
    private int validateAce (URMGroup urmGroup,URMAce ace, URMAdministrator urmAdmin, URMAclAdministrator aclAdmin, Map actionMap) throws URMException, URMInternalServerException {
        boolean subjectMatch = false;
        // analyse the ACE Subject
        URMSubject subject = ace.getSubject();
        // check if the principal is represented by the subject
        subjectMatch = isSubject(urmAdmin, urmGroup, subject);
        if (subjectMatch) {
            // if the subject matches, verify if the ace denies or grants the requested action
            return (resolveAceActionMapping(ace, aclAdmin, actionMap));
        } else {
            return (URMAclValidator.URMIndeterminate);
        }
    }
    
    private int validateAce (URMRole role,URMAce ace, URMAclAdministrator aclAdmin, Map actionMap) throws URMException, URMInternalServerException {
        boolean subjectMatch = false;
        // analyse the ACE Subject
        URMSubject subject = ace.getSubject();
        // check if the principal is represented by the subject
        subjectMatch = isSubject(role, subject);
        if (subjectMatch) {
            // if the subject matches, verify if the ace denies or grants the requested action
            return (resolveAceActionMapping(ace, aclAdmin, actionMap));
        } else {
            return (URMAclValidator.URMIndeterminate);
        }
    }
    
        /**
     * resolves the subject to the users, associated with the subject and adds this user to
     * the grantedUsersSet if grant=true or to the deniedUsesSet if grant=false
     */
    protected void resolveSubjectToUser(URMPrincipal principal, URMSubject subject, Set grantedUsersSet, Set deniedUsesSet, boolean grant)
        throws URMException    {
        int subjectType = subject.getType();
        URMAdministrator urmAdmin = principal.getURMAdministrator();
        if (subjectType == URMConstants.USER) {
            URMUser user = urmAdmin.getUser(subject.getName(), subject.getDomain());
            if (grant) {
                if (!deniedUsesSet.contains(user)) grantedUsersSet.add(user);
            } else {
                if (!deniedUsesSet.contains(user)) deniedUsesSet.add(user);
            }
                
        } else if (subjectType == URMConstants.GROUP){
            URMGroup group = urmAdmin.getGroup(subject.getName(), subject.getDomain());
            Set members = group.getGroupMembers();
            Iterator memberIter = members.iterator();
            while (memberIter.hasNext()) {
                resolveSubjectToUser (principal, (URMSubject) memberIter.next(), grantedUsersSet, deniedUsesSet, grant);
            }
            
        } else if (subjectType == URMConstants.ROLE){
            URMRole role = urmAdmin.getRole(subject.getName());
            Set users = null;
            Set roles = null;
            Set groups = null;
            if (role.getName().equals(URMConstants.URM_GUEST_ROLE)) {
                users = new HashSet();
                roles = new HashSet();
                groups = new HashSet();
            } else  {
                users = role.getUserMapping();
                roles = role.getRolesOfAncestor();
                groups = role.getGroupMapping();
            }
            Iterator userIter = users.iterator();
            if (subject.getName().equals(URMConstants.URM_ROOT_ROLE)) grant = true;
            while (userIter.hasNext()) {
                
                URMUser user = (URMUser)userIter.next();
                resolveSubjectToUser (principal, user, grantedUsersSet, deniedUsesSet, grant);
            }
            
            Iterator groupIter = groups.iterator();
            while (groupIter.hasNext()) {
                URMGroup group = (URMGroup)groupIter.next();
                resolveSubjectToUser (principal, group, grantedUsersSet, deniedUsesSet, grant);
            }
            
            Iterator roleIter = roles.iterator();
            while (roleIter.hasNext()) {
                URMRole currentrole = (URMRole) roleIter.next();
                resolveSubjectToUser (principal, currentrole, grantedUsersSet, deniedUsesSet, grant);
            }
        }
    }
}
