com.jaspersoft.jasperserver.api.metadata.user.service.impl.ObjectPermissionServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.jasperserver.api.metadata.user.service.impl.ObjectPermissionServiceImpl.java

Source

/*
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 *
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 *
 * This program is free software: you can redistribute it and/or  modify
 * it under the terms of the GNU Affero General Public License  as
 * published by the Free Software Foundation, either version 3 of  the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero  General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public  License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.jaspersoft.jasperserver.api.metadata.user.service.impl;

import com.jaspersoft.jasperserver.api.JSException;
import com.jaspersoft.jasperserver.api.common.domain.ExecutionContext;
import com.jaspersoft.jasperserver.api.common.util.ImportRunMonitor;
import com.jaspersoft.jasperserver.api.logging.audit.context.AuditContext;
import com.jaspersoft.jasperserver.api.logging.audit.domain.AuditEvent;
import com.jaspersoft.jasperserver.api.metadata.common.domain.Folder;
import com.jaspersoft.jasperserver.api.metadata.common.domain.InternalURI;
import com.jaspersoft.jasperserver.api.metadata.common.domain.Resource;
import com.jaspersoft.jasperserver.api.metadata.common.domain.impl.IdedObject;
import com.jaspersoft.jasperserver.api.metadata.common.service.RepositoryUnsecure;
import com.jaspersoft.jasperserver.api.metadata.common.service.ResourceFactory;
import com.jaspersoft.jasperserver.api.metadata.common.service.impl.HibernateDaoImpl;
import com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.HibernateRepositoryService;
import com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.PersistentObjectResolver;
import com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.ReferenceResolver;
import com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.persistent.RepoResource;
import com.jaspersoft.jasperserver.api.metadata.user.domain.ObjectPermission;
import com.jaspersoft.jasperserver.api.metadata.user.domain.Role;
import com.jaspersoft.jasperserver.api.metadata.user.domain.User;
import com.jaspersoft.jasperserver.api.metadata.user.domain.client.ObjectPermissionImpl;
import com.jaspersoft.jasperserver.api.metadata.user.domain.impl.ObjectPermissionRecipientIdentity;
import com.jaspersoft.jasperserver.api.metadata.user.domain.impl.hibernate.RepoObjectPermission;
import com.jaspersoft.jasperserver.api.metadata.user.service.ObjectPermissionService;
import com.jaspersoft.jasperserver.api.metadata.user.service.UserAuthorityService;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.Authentication;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.acl.AclEntry;
import org.springframework.security.acl.AclProvider;
import org.springframework.security.acl.basic.AclObjectIdentity;
import org.springframework.security.acl.basic.BasicAclDao;
import org.springframework.security.acl.basic.BasicAclEntry;
import org.springframework.security.acl.basic.BasicAclEntryCache;
import org.springframework.security.acl.basic.EffectiveAclsResolver;
import org.springframework.security.acl.basic.GrantedAuthorityEffectiveAclsResolver;
import org.springframework.security.acl.basic.SimpleAclEntry;
import org.springframework.security.acl.basic.cache.NullAclEntryCache;
import org.springframework.security.context.SecurityContextHolder;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author swood
 *
 */
public class ObjectPermissionServiceImpl extends HibernateDaoImpl
        implements BasicAclDao, AclProvider, AclService, ObjectPermissionService, ObjectPermissionServiceInternal,
        ApplicationContextAware, PersistentObjectResolver, InitializingBean {

    //

    protected static final Log log = LogFactory.getLog(ObjectPermissionServiceImpl.class);
    public static final String RECIPIENT_USED_FOR_INHERITANCE_MARKER = "___INHERITANCE_MARKER_ONLY___";

    protected static final String RESOURCE_URI_PREFIX = Resource.URI_PROTOCOL + ":";
    protected static final int RESOURCE_URI_PREFIX_LENGTH = RESOURCE_URI_PREFIX.length();

    /**
     * Marker added to the cache to indicate an AclObjectIdentity has no
     * corresponding BasicAclEntry[]s
     */
    static String RECIPIENT_FOR_CACHE_EMPTY = "RESERVED_RECIPIENT_NOBODY";

    private HibernateRepositoryService repoService;
    private UserAuthorityService userService;

    private ResourceFactory objectFactory;
    private ResourceFactory persistentClassFactory;

    private BasicAclEntryCache basicAclEntryCache = new NullAclEntryCache();
    private EffectiveAclsResolver effectiveAclsResolver = new GrantedAuthorityEffectiveAclsResolver();

    private ApplicationContext appContext;
    private AuditContext auditContext;

    /**
     * @return Returns the repoService.
     */
    public HibernateRepositoryService getRepositoryService() {
        return repoService;
    }

    /**
     * @param repoService The repoService to set.
     */
    public void setRepositoryService(HibernateRepositoryService repoService) {
        this.repoService = repoService;
    }

    /**
     * @return Returns the userService.
     */
    public UserAuthorityService getUserAuthorityService() {
        return userService;
    }

    /**
     * @param userService The userService to set.
     */
    public void setUserAuthorityService(UserAuthorityService userService) {
        this.userService = userService;
    }

    public ResourceFactory getObjectMappingFactory() {
        return objectFactory;
    }

    public void setObjectMappingFactory(ResourceFactory objectFactory) {
        this.objectFactory = objectFactory;
    }

    public ResourceFactory getPersistentClassFactory() {
        return persistentClassFactory;
    }

    public void setPersistentClassFactory(ResourceFactory persistentClassFactory) {
        this.persistentClassFactory = persistentClassFactory;
    }

    public void setBasicAclEntryCache(BasicAclEntryCache basicAclEntryCache) {
        this.basicAclEntryCache = basicAclEntryCache;
    }

    public BasicAclEntryCache getBasicAclEntryCache() {
        return basicAclEntryCache;
    }

    /**
    * @return Returns the effectiveAclsResolver.
    */
    public EffectiveAclsResolver getEffectiveAclsResolver() {
        return effectiveAclsResolver;
    }

    /**
     * @param effectiveAclsResolver The effectiveAclsResolver to set.
     */
    public void setEffectiveAclsResolver(EffectiveAclsResolver effectiveAclsResolver) {
        this.effectiveAclsResolver = effectiveAclsResolver;
    }

    /* (non-Javadoc)
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
     */
    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        // Not needed really?
        appContext = arg0;
    }

    public void setAuditContext(AuditContext auditContext) {
        this.auditContext = auditContext;
    }

    /**
     * Returns the ACLs associated with the requested
     * <code>AclObjectIdentity</code>.
     *
     * <P>
     * The {@link BasicAclEntry}s returned by this method will have
     * <code>String</code>-based recipients. This will not be a problem if you
     * are using the <code>GrantedAuthorityEffectiveAclsResolver</code>, which
     * is the default configured against <code>BasicAclProvider</code>.
     * </p>
     *
     * @param aclObjectIdentity for which ACL information is required (cannot
     *        be <code>null</code>)
     *
     * @return the ACLs that apply (without any <code>null</code>s inside the
     *         array), or <code>null</code> if not found or if an incompatible
     *         <code>AclObjectIdentity</code> was requested
     */
    public BasicAclEntry[] getAcls(String uri) {

        BasicAclEntry[] entries = checkImport(uri);
        if (entries != null)
            return entries;

        Resource res = ((RepositoryUnsecure) getRepositoryService()).getResourceLookupUnsecure(null, uri);
        if (res == null) {
            res = ((RepositoryUnsecure) getRepositoryService()).getFolderUnsecure(null, uri);
        }
        if (res != null) {
            return getAcls((InternalURI) res);
        }

        return null;
    }

    /**
      * Returns the ACLs associated with the requested
      * <code>AclObjectIdentity</code>.
      *
      * <P>
      * The {@link BasicAclEntry}s returned by this method will have
      * <code>String</code>-based recipients. This will not be a problem if you
      * are using the <code>GrantedAuthorityEffectiveAclsResolver</code>, which
      * is the default configured against <code>BasicAclProvider</code>.
      * </p>
      *
      * @param aclObjectIdentity for which ACL information is required (cannot
      *        be <code>null</code>)
      *
      * @return the ACLs that apply (without any <code>null</code>s inside the
      *         array), or <code>null</code> if not found or if an incompatible
      *         <code>AclObjectIdentity</code> was requested
      */
    public BasicAclEntry[] getAcls(InternalURI targetURI) {

        //Object obj = org.springframework.security.context.SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        //String username = "unknow";
        //if (obj instanceof org.springframework.security.userdetails.UserDetails) {
        //  username = ((org.springframework.security.userdetails.UserDetails)obj).getUsername();
        //} else {
        //  username = obj.toString();
        //}
        //logger.error("Requesting access to: " + targetURI.getURI() + " | " + targetURI.getPath() + " User: " + username);

        if (targetURI == null) {
            logger.error("getAcls(InternalURI targetURI): returning. null targetURI");
            return null;
        }

        BasicAclEntry[] entries = checkImport(targetURI.getURI());
        if (entries != null)
            return entries;

        Map map = new HashMap();

        BasicAclEntry[] instanceAclEntries = null;

        // Look in cache by targetURI.getURI for BasicAclEntry[]
        if (targetURI instanceof Resource && ((Resource) targetURI).isNew()) {
            // Look if it is really is new resouce...
            Resource res = ((RepositoryUnsecure) getRepositoryService()).getResourceLookupUnsecure(null,
                    "repo:" + targetURI.getPath());
            if (res == null) {
                res = ((RepositoryUnsecure) getRepositoryService()).getFolderUnsecure(null,
                        "repo:" + targetURI.getPath());
            }

            if (res == null) {
                // Look directly to the parent...
                instanceAclEntries = lookup(getParentURI("repo:" + targetURI.getPath()), null);
            }
        } else {
            instanceAclEntries = lookup("repo:" + targetURI.getPath(), targetURI);
        }

        // Exit if there is no ACL information or parent for this instance
        if (instanceAclEntries == null) {
            return null;
        }

        // Add the leaf objects to the Map, keyed on recipient
        for (int i = 0; i < instanceAclEntries.length; i++) {
            if (logger.isDebugEnabled()) {
                logger.debug("Explicit add: " + instanceAclEntries[i].toString());
            }

            map.put(instanceAclEntries[i].getRecipient(), instanceAclEntries[i]);
        }

        String parent = getParentURI("repo:" + targetURI.getPath());

        while (parent != null) {
            BasicAclEntry[] parentAclEntries = lookup(parent, null);

            if (logger.isDebugEnabled()) {
                logger.debug("Parent lookup: " + parent);
            }

            // Exit loop if parent couldn't be found (unexpected condition)
            if (parentAclEntries == null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Parent could not be found in ACL repository");
                }

                break;
            }

            // Now add each _NEW_ recipient to the list
            for (int i = 0; i < parentAclEntries.length; i++) {
                if (!map.containsKey(parentAclEntries[i].getRecipient())) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Added parent to map: " + parentAclEntries[i].toString() + " for recipient: "
                                + parentAclEntries[i].getRecipient());
                    }

                    map.put(parentAclEntries[i].getRecipient(), parentAclEntries[i]);
                } else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Did NOT add parent to map: " + parentAclEntries[i].toString()
                                + " for recipient: " + parentAclEntries[i].getRecipient());
                    }
                }
            }

            // Prepare for next iteration of while loop
            parent = getParentURI(parent);
        }

        Collection collection = map.values();

        return (BasicAclEntry[]) collection.toArray(new BasicAclEntry[] {});
    }

    public BasicAclEntry[] getAcls(AclObjectIdentity aclObjectIdentity) {
        if (aclObjectIdentity == null || !(aclObjectIdentity instanceof InternalURI)) {
            logger.debug("getAcls(AclObjectIdentity aclObjectIdentity): returning. invalid object for getAcls: "
                    + aclObjectIdentity);
            return null;
        }

        InternalURI targetURI = (InternalURI) aclObjectIdentity;

        return getAcls(targetURI);
    }

    public BasicAclEntry[] getAcls(AclObjectIdentity aclObjectIdentity, Object recipient) {
        if (aclObjectIdentity == null || !(aclObjectIdentity instanceof InternalURI)) {
            logger.debug(
                    "getAcls(AclObjectIdentity aclObjectIdentity, Object recipient): returning. invalid object for getAcls: "
                            + aclObjectIdentity);
            return null;
        }

        InternalURI targetURI = (InternalURI) aclObjectIdentity;
        return getAclsForRecipient(RESOURCE_URI_PREFIX + targetURI.getPath(), recipient);
    }

    private BasicAclEntry[] checkImport(String uri) {
        BasicAclEntry[] res = null;
        if (ImportRunMonitor.isImportRun()) {
            //Add special permission for current user
            //to allow updating special resources like themes etc
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            for (GrantedAuthority authority : authentication.getAuthorities()) {
                if (authority.getAuthority().equals(ObjectPermissionService.PRIVILEGED_OPERATION)) {
                    ObjectPermission permission = new ObjectPermissionImpl();
                    permission.setPermissionMask(SimpleAclEntry.ADMINISTRATION);
                    permission.setPermissionRecipient(
                            SecurityContextHolder.getContext().getAuthentication().getPrincipal());
                    res = new BasicAclEntry[] { createBasicAclEntry(uri, permission) };
                }
            }
        }
        return res;
    }

    private BasicAclEntry[] getAclsForRecipient(String targetURI, Object recipient) {
        Map map = new HashMap();

        while (targetURI != null) {
            BasicAclEntry[] entries = lookup(targetURI, null);
            if (entries != null) {

                // Add the leaf objects to the Map, keyed on recipient
                for (int i = 0; i < entries.length; i++) {

                    // Include if we are not filtering by recipients or we have matched the given
                    // recipient, and we have not seen this recipient before

                    if ((recipient == null || recipient.equals(entries[i].getRecipient()))
                            && !map.containsKey(entries[i].getRecipient())) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Added: " + entries[i].toString());
                        }

                        map.put(entries[i].getRecipient(), entries[i]);
                    } else {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Did NOT add: " + entries[i].toString());
                        }
                    }
                }
            }
            targetURI = getParentURI(targetURI);
        }

        Collection collection = map.values();
        return (BasicAclEntry[]) collection.toArray(new BasicAclEntry[] {});
        //return new ArrayList(map.values());
    }

    /**
     * Create AclEntrys from targetURI and list of ObjectPermissions
     *
     *
     * @param targetURI
     * @param permissions
     * @return
     */
    private BasicAclEntry[] getAclsFromObjectPermissions(String targetURI, List permissions) {

        if (permissions == null || permissions.size() == 0) {
            log.debug("No explicit permissions found");
            // return merely an inheritance marker (as we know about the object but it has no related ACLs)
            return new BasicAclEntry[] { createBasicAclEntry(targetURI, null) };
        } else {
            if (log.isDebugEnabled()) {
                log.debug("Found " + permissions.size() + " explicit permissions");
            }
            // return the individual ACL instances
            ObjectPermission[] aclHolders = (ObjectPermission[]) permissions.toArray(new ObjectPermission[] {});
            List toReturnAcls = new ArrayList(aclHolders.length);

            for (int i = 0; i < aclHolders.length; i++) {
                if (log.isDebugEnabled()) {
                    log.debug(aclHolders[i]);
                }
                toReturnAcls.add(createBasicAclEntry(targetURI, aclHolders[i]));
            }

            return (BasicAclEntry[]) toReturnAcls.toArray(new BasicAclEntry[] {});
        }
    }

    /**
     * Constructs an individual <code>BasicAclEntry</code> from the passed
     * <code>ObjectPermission</code> and <code>InternalURI</code>.
     *
     * <P>
     * Guarantees to never return <code>null</code> (exceptions are thrown in
     * the event of any issues).
     * </p>
     *
     * @param propertiesInformation mandatory information about which instance
     *        to create, the object identity, and the parent object identity
     *        (<code>null</code> or empty <code>String</code>s prohibited for
     *        <code>aclClass</code> and <code>aclObjectIdentity</code>
     * @param aclInformation optional information about the individual ACL
     *        record (if <code>null</code> only an "inheritence marker"
     *        instance is returned; if not <code>null</code>, it is prohibited
     *        to present <code>null</code> or an empty <code>String</code> for
     *        <code>recipient</code>)
     *
     * @return a fully populated instance suitable for use by external objects
     *
     * @throws IllegalArgumentException if the indicated ACL class could not be
     *         created
     */
    BasicAclEntry createBasicAclEntry(String targetURI, ObjectPermission aclInformation) {
        BasicAclEntry entry;

        try {
            entry = (BasicAclEntry) SimpleAclEntry.class.newInstance();
        } catch (InstantiationException ie) {
            throw new IllegalArgumentException(ie.getMessage());
        } catch (IllegalAccessException iae) {
            throw new IllegalArgumentException(iae.getMessage());
        }

        entry.setAclObjectIdentity(new URIObjectIdentity(targetURI));
        entry.setAclObjectParentIdentity(new URIObjectIdentity(getParentURI(targetURI)));

        if (aclInformation == null) {
            // this is an inheritance marker instance only
            entry.setMask(0);
            entry.setRecipient(RECIPIENT_USED_FOR_INHERITANCE_MARKER);
        } else {
            // this is an individual ACL entry
            entry.setMask(aclInformation.getPermissionMask());
            entry.setRecipient(aclInformation.getPermissionRecipient());
        }

        return entry;
    }

    /**
     * Get the parent URI of the given URI, by slicing off the last part of the path
     *
     * @param currentURI
     * @return
     */
    private String getParentURI(String currentURI) {
        if (currentURI == null || currentURI.trim().length() == 0) {
            return null;
        } else {

            // Deal with URIs that come with "repo:" on the front

            String workUri = currentURI.startsWith(RESOURCE_URI_PREFIX)
                    ? currentURI.substring(RESOURCE_URI_PREFIX_LENGTH).trim()
                    : currentURI.trim();

            /*
             * If we have a URI like "repo:/folder1/object", return "repo:/folder1".
             *
             * repo:/folder1 returns repo:/
             *
             * repo:/ returns null
             */
            int lastSeparator = workUri.lastIndexOf(Folder.SEPARATOR);

            // no separator
            if (lastSeparator < 0) {
                return null;
            } else if (lastSeparator == 0) {
                // if we are the root: no parent
                if (workUri.length() == 1) {
                    return null;
                } else {
                    return RESOURCE_URI_PREFIX + Folder.SEPARATOR;
                }
            } else {
                return RESOURCE_URI_PREFIX + workUri.substring(0, lastSeparator);
            }
        }
    }

    /**
     * Find ObjectPermissions for the object
     *
     *  (non-Javadoc)
     * @see org.springframework.security.acl.AclManager#getAcls(java.lang.Object)
     */
    public AclEntry[] getAcls(Object obj) {

        List resultList = new ArrayList();

        if (obj instanceof InternalURI) {
            return getAcls((InternalURI) obj);
        } else if (obj instanceof String) {
            String path = (String) obj;
            if (path.startsWith(RESOURCE_URI_PREFIX)) {
                path = path.substring(RESOURCE_URI_PREFIX_LENGTH);
            }
            return getAcls(new InternalURIDefinition(path));
        }

        return (BasicAclEntry[]) resultList.toArray(new BasicAclEntry[] {});
    }

    /**
     * Find ObjectPermissions for the object and Authentication (user)
     *
     *  (non-Javadoc)
     * @see org.springframework.security.acl.AclManager#getAcls(java.lang.Object, org.springframework.security.Authentication)
     */
    public AclEntry[] getAcls(Object obj, Authentication auth) {

        if (auth == null || auth.getPrincipal() == null || !(obj instanceof InternalURI || obj instanceof String)) {
            return new BasicAclEntry[] {};
        }
        AclEntry[] allAcls = (AclEntry[]) this.getAcls(obj);

        return this.effectiveAclsResolver.resolveEffectiveAcls(allAcls, auth);
    }

    private BasicAclEntry[] lookup(String targetURI, InternalURI targetObject) {
        URIObjectIdentity objIdent = new URIObjectIdentity(targetURI);

        BasicAclEntry[] result = basicAclEntryCache.getEntriesFromCache(objIdent);

        if (result != null && result.length > 0) {
            if (log.isDebugEnabled()) {
                log.debug("Found " + targetURI + " in cache");
            }
            if (result[0].getRecipient() == null || result[0].getRecipient().equals(RECIPIENT_FOR_CACHE_EMPTY)) {
                return null;
            } else {
                return result;
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("Did not find " + targetURI + " in cache");
        }

        Resource res = null;
        if (targetObject instanceof Resource) {
            res = (Resource) targetObject;

            if (log.isDebugEnabled()) {
                log.debug("Looking up permissions for resource object " + res.getURIString());
            }
        } else {
            res = ((RepositoryUnsecure) getRepositoryService()).getResourceLookupUnsecure(null, targetURI);
            if (res == null) {
                res = ((RepositoryUnsecure) getRepositoryService()).getFolderUnsecure(null, targetURI);
                if (log.isDebugEnabled()) {
                    log.debug("Did not find " + targetURI + " as resource");
                    log.debug("Did " + ((res == null) ? "not" : "") + " find " + targetURI + " as folder");
                }
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("Found " + targetURI + " as resource");
                }
            }
        }

        if (res != null) {
            List permissions = getObjectPermissionsForObject(null, res);

            result = getAclsFromObjectPermissions(targetURI, permissions);
        } else {
            if (log.isDebugEnabled()) {
                log.debug("Resource not found for permissions lookup: " + targetURI + ". Using parent permissions");
            }

            // is it a new resource? Return the parent permissions....
            return lookup(getParentURI(targetURI), null);
        }

        if (result == null) {

            if (log.isDebugEnabled()) {
                log.debug("Default entries for " + targetURI + " cached");
            }

            SimpleAclEntry[] emptyAclEntries = {
                    new SimpleAclEntry(RECIPIENT_FOR_CACHE_EMPTY, new URIObjectIdentity(targetURI), null, 0) };
            basicAclEntryCache.putEntriesInCache(emptyAclEntries);

            return null;
        }

        if (log.isDebugEnabled()) {
            log.debug(result.length + " entries for " + targetURI + " cached");
        }

        basicAclEntryCache.putEntriesInCache(result);

        return result;
    }

    public void deleteObjectPermissionForObject(ExecutionContext context, Object targetObject) {
        if (targetObject == null || !(targetObject instanceof InternalURI)) {
            return;
        }
        InternalURI res = (InternalURI) targetObject;
        deleteObjectPermissionForRepositoryPath(context, res.getPath());
    }

    public void deleteObjectPermissionForRepositoryPath(ExecutionContext context, String path) {
        if (log.isDebugEnabled()) {
            log.debug("Deleting object permissions for repository path " + path);
        }

        List permissions = getRepoObjectPermissions(context, repositoryURI(path), null);
        deleteObjectPermissions(permissions, false);
    }

    public void deleteObjectPermissionsForRecipient(ExecutionContext context, Object recipient) {
        if (log.isDebugEnabled()) {
            log.debug("Deleting object permissions for recipient " + recipient);
        }

        List permissions = getRepoObjectPermissions(context, null, recipient);
        deleteObjectPermissions(permissions);
    }

    public void deleteObjectPermissionsForRecipient(ExecutionContext context,
            ObjectPermissionRecipientIdentity recipientIdentity) {
        if (log.isDebugEnabled()) {
            log.debug("Deleting object permissions for recipient " + recipientIdentity);
        }

        List permissions = getRepoObjectPermissions(recipientIdentity);
        deleteObjectPermissions(permissions);
    }

    protected void deleteObjectPermissions(List permissions) {
        deleteObjectPermissions(permissions, true);
    }

    protected void deleteObjectPermissions(List permissions, boolean checkAdministerAccess) {
        if (permissions != null && !permissions.isEmpty()) {
            for (Iterator it = permissions.iterator(); it.hasNext();) {
                RepoObjectPermission permission = (RepoObjectPermission) it.next();
                deleteObjectPermission(permission, checkAdministerAccess);
            }
        }
    }

    /**
     * A key for the cache
     *
     * @author swood
     *
     */
    public static class URIObjectIdentity implements AclObjectIdentity {
        String uri;

        public URIObjectIdentity(String uri) {
            String fullUri = uri;

            // Catch things that do not have a protocol
            if (uri != null && uri.startsWith(Folder.SEPARATOR)) {
                fullUri = RESOURCE_URI_PREFIX + uri;
            }
            this.uri = fullUri;
        }

        public String getURI() {
            return uri;
        }

        public String toString() {
            return new ToStringBuilder(this).append("uri", getURI()).toString();
        }

        public boolean equals(Object other) {
            if (!(other instanceof URIObjectIdentity))
                return false;
            URIObjectIdentity castOther = (URIObjectIdentity) other;
            return new EqualsBuilder().append(this.getURI(), castOther.getURI()).isEquals();
        }

        public int hashCode() {
            return new HashCodeBuilder().append(getURI()).toHashCode();
        }
    }

    /**
     * We can authorize InternalURI
     *
     *  (non-Javadoc)
     * @see org.springframework.security.acl.AclProvider#supports(java.lang.Object)
     */
    public boolean supports(Object obj) {
        return obj instanceof InternalURI || obj instanceof String;
    }

    /* (non-Javadoc)
     * @see com.jaspersoft.jasperserver.api.metadata.user.service.ObjectPermissionService#newObjectPermission(com.jaspersoft.jasperserver.api.common.domain.ExecutionContext)
     */
    public ObjectPermission newObjectPermission(ExecutionContext context) {
        return (ObjectPermission) getObjectMappingFactory().newObject(ObjectPermission.class);
    }

    private void addParamsToSetPermissionAuditEvent(final ExecutionContext context,
            final ObjectPermission objPermission, final int previousPermissionValue) {
        String[] eventNames = new String[] { "createPermission", "updatePermission", "deletePermission" };
        auditContext.doInAuditContext(eventNames, new AuditContext.AuditContextCallbackWithEvent() {
            public void execute(AuditEvent auditEvent) {
                Resource resource = repoService.getResource(context, objPermission.getURI());
                if (resource != null) {
                    auditContext.setResourceTypeToAuditEvent(resource.getResourceType(), auditEvent);
                } else {
                    auditContext.setResourceTypeToAuditEvent(Folder.class.getName(), auditEvent);
                }
                auditEvent.setResourceUri(objPermission.getURI());
                String recipientType = "UNKNOWN";
                String recipientName = null;
                String recipientTenantId = null;
                if (objPermission.getPermissionRecipient() instanceof User) {
                    recipientType = "USER";
                    recipientName = ((User) objPermission.getPermissionRecipient()).getUsername();
                    recipientTenantId = ((User) objPermission.getPermissionRecipient()).getTenantId();
                } else if (objPermission.getPermissionRecipient() instanceof Role) {
                    recipientType = "ROLE";
                    recipientName = ((Role) objPermission.getPermissionRecipient()).getRoleName();
                    recipientTenantId = ((Role) objPermission.getPermissionRecipient()).getTenantId();
                }
                auditContext.addPropertyToAuditEvent("recipientType", recipientType, auditEvent);
                auditContext.addPropertyToAuditEvent("recipientName", recipientName, auditEvent);
                auditContext.addPropertyToAuditEvent("recipientTenantId", recipientTenantId, auditEvent);
                if ("updatePermission".equals(auditEvent.getEventType())) {
                    auditContext.addPropertyToAuditEvent("previousPermissionValue", previousPermissionValue,
                            auditEvent);
                }
                auditContext.addPropertyToAuditEvent("permissionValue", objPermission.getPermissionMask(),
                        auditEvent);
            }
        });
    }

    /* (non-Javadoc)
    * @see com.jaspersoft.jasperserver.api.metadata.user.service.ObjectPermissionService#putObjectPermission(com.jaspersoft.jasperserver.api.common.domain.ExecutionContext, com.jaspersoft.jasperserver.api.metadata.user.domain.ObjectPermission)
    */
    public void putObjectPermission(ExecutionContext context, ObjectPermission objPermission)
            throws IllegalArgumentException {
        if (objPermission == null) {
            throw new IllegalArgumentException("Permission can't be null");
        }
        // checking administrative access
        boolean privileged = (context != null && context.getAttributes() != null
                && context.getAttributes().contains(PRIVILEGED_OPERATION)) ? true : false;
        if (!privileged && !isObjectAdministrable(context, objPermission.getURI())) {
            throw new AccessDeniedException("Access is denied");
        }
        final Object permissionRecipient = objPermission.getPermissionRecipient();
        if (permissionRecipient == null) {
            throw new IllegalArgumentException("Permission recipient can't be null");
        }
        if (permissionRecipient instanceof User) {
            final User user = (User) permissionRecipient;
            final String username = user.getUsername();
            if (username == null || username.isEmpty()) {
                throw new IllegalArgumentException("User name can't be null");
            }

            Set<String> tenantSet = new HashSet<String>(1);
            tenantSet.add(user.getTenantId());
            final List tenantUsers = userService.getTenantUsers(null, tenantSet, username);
            if (tenantUsers == null || tenantUsers.isEmpty()) {
                throw new IllegalArgumentException("User '" + username
                        + "' doesn't exists and can't be used as permissionRecipient for permission");
            }
        } else if (permissionRecipient instanceof Role) {
            final Role role = (Role) permissionRecipient;
            final String roleName = role.getRoleName();
            if (roleName == null || roleName.isEmpty()) {
                throw new IllegalArgumentException("Role name can't be null");
            }
            Set<String> tenantSet = new HashSet<String>();
            tenantSet.add(role.getTenantId());
            final List roles = userService.getTenantRoles(null, tenantSet, roleName);
            if (roles == null || roles.isEmpty()) {
                throw new IllegalArgumentException("Role '" + roleName
                        + "' doesn't exists and can't be used as permissionRecipient for permission");
            }
        } else {
            throw new IllegalArgumentException("Unknown type of permissionRecipient. Invalid permissionRecipient: "
                    + permissionRecipient.toString());
        }
        // Given the object and the recipient, find the permission
        RepoObjectPermission existingPerm = getRepoObjectPermission(context, objPermission);
        if (existingPerm == null) {
            existingPerm = (RepoObjectPermission) getPersistentClassFactory().newObject(ObjectPermission.class);
        }

        addParamsToSetPermissionAuditEvent(context, objPermission, existingPerm.getPermissionMask());

        existingPerm.copyFromClient(objPermission, this);
        getHibernateTemplate().saveOrUpdate(existingPerm);

        clearAclEntriesCache(objPermission.getURI());
    }

    public void deleteObjectPermission(ExecutionContext context, ObjectPermission objPermission) {
        // Given the object and the recipient, find the permission
        RepoObjectPermission existingPerm = getRepoObjectPermission(context, objPermission);
        if (existingPerm == null) {
            throw new JSException("jsexception.no.such.object.permission");
        }
        // and delete
        addParamsToSetPermissionAuditEvent(context, objPermission, existingPerm.getPermissionMask());
        deleteObjectPermission(existingPerm);
    }

    protected void deleteObjectPermission(RepoObjectPermission permission) {
        deleteObjectPermission(permission, true);
    }

    protected void deleteObjectPermission(RepoObjectPermission permission, boolean checkAdministerAccess) {
        // checking administrable access
        if (checkAdministerAccess && !isObjectAdministrable(null, permission.getURI())) {
            throw new AccessDeniedException("Access is denied");
        }
        getHibernateTemplate().delete(permission);
        clearAclEntriesCache(permission.getURI());
    }

    public ObjectPermission getObjectPermission(ExecutionContext context, ObjectPermission objPermission) {
        // Given the object and the recipient, find the permission
        RepoObjectPermission existingPerm = getRepoObjectPermission(context, objPermission);
        if (existingPerm == null) {
            return null;
        } else {
            return (ObjectPermission) existingPerm.toClient(getObjectMappingFactory());
        }
    }

    /*
       private List getRepoObjectPermissions(ExecutionContext context, InternalURI targetURI, Object recipient) {
          return getRepoObjectPermissions(context, targetURI.getURI(), recipient);
       }
    */
    private List getRepoObjectPermissions(ExecutionContext context, final String uri, Object recipient) {
        // Given the object and the recipient, find the permission
        final IdedObject recipientObject = (IdedObject) getPersistentObject(recipient);

        final String objPermissionClassName = getPersistentClassFactory()
                .getImplementationClassName(ObjectPermission.class);
        final Class recipientObjectClassName = recipient == null ? null
                : getPersistentClassFactory().getImplementationClass(recipient.getClass());

        List objList = null;

        if (uri == null && recipientObject == null) {
            //throw new JSException("jsexception.no.uri.or.recipient.given");
            // this is to get all permissions
            final String queryString = "from " + objPermissionClassName;

            objList = getHibernateTemplate().executeFind(new HibernateCallback() {
                public Object doInHibernate(Session session) throws HibernateException {
                    Query query = session.createQuery(queryString);
                    return query.list();
                }
            });
        }

        if (uri != null && recipientObject != null) {
            // Select on both identity and recipient
            final String queryString = "from " + objPermissionClassName + " as objPermission "
                    + "where objPermission.URI = ? and "
                    + "      objPermission.permissionRecipient.id = ? and objPermission.permissionRecipient.class = ?";

            objList = getHibernateTemplate().executeFind(new HibernateCallback() {
                public Object doInHibernate(Session session) throws HibernateException {
                    Query query = session.createQuery(queryString);
                    query.setParameter(0, uri, Hibernate.STRING);
                    query.setParameter(1, new Long(recipientObject.getId()), Hibernate.LONG);
                    query.setParameter(2, recipientObjectClassName, Hibernate.CLASS);
                    return query.list();
                }
            });
        } else if (uri != null) {
            // Select on identity
            final String queryString = "from " + objPermissionClassName + " as objPermission "
                    + "where objPermission.URI = ?";

            objList = getHibernateTemplate().executeFind(new HibernateCallback() {
                public Object doInHibernate(Session session) throws HibernateException {
                    Query query = session.createQuery(queryString);
                    query.setParameter(0, uri, Hibernate.STRING);
                    return query.list();
                }
            });
        } else if (recipientObject != null) {
            // Select on recipient
            ObjectPermissionRecipientIdentity recipientIdentity = new ObjectPermissionRecipientIdentity(
                    recipientObject);
            objList = getRepoObjectPermissions(recipientIdentity);

        }
        return objList;
    }

    protected List getRepoObjectPermissions(final ObjectPermissionRecipientIdentity recipientIdentity) {
        final String objPermissionClassName = getPersistentClassFactory()
                .getImplementationClassName(ObjectPermission.class);

        final String queryString = "from " + objPermissionClassName + " as objPermission "
                + "where objPermission.permissionRecipient.id = ? and objPermission.permissionRecipient.class = ?";

        List objList = getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException {
                Query query = session.createQuery(queryString);
                query.setParameter(0, new Long(recipientIdentity.getId()), Hibernate.LONG);
                query.setParameter(1, recipientIdentity.getRecipientClass(), Hibernate.CLASS);
                return query.list();
            }
        });
        return objList;
    }

    private List getRepoObjectPermissions(ExecutionContext context, ObjectPermission objPermission) {
        // Given the object and parent, find the objectIdentity
        return getRepoObjectPermissions(context, objPermission.getURI(), objPermission.getPermissionRecipient());
    }

    private RepoObjectPermission getRepoObjectPermission(ExecutionContext context, ObjectPermission objPermission) {
        List objList = getRepoObjectPermissions(context, objPermission);
        RepoObjectPermission objPerm = null;
        if (objList == null || objList.isEmpty()) {
            log.debug("ObjectPermission not found with object \"" + objPermission.getURI() + "\", recipient \""
                    + objPermission.getPermissionRecipient() + "\"");
        } else {
            if (log.isDebugEnabled()) {
                log.debug("ObjectPermission FOUND with object \"" + objPermission.getURI() + "\", recipient \""
                        + objPermission.getPermissionRecipient() + "\"");
                log.debug("Size: " + objList.size());
            }
            objPerm = (RepoObjectPermission) objList.get(0);
        }
        return objPerm;

    }

    /* (non-Javadoc)
     * @see com.jaspersoft.jasperserver.api.metadata.user.service.ObjectPermissionService#getObjectPermissionsForObject(com.jaspersoft.jasperserver.api.common.domain.ExecutionContext, java.lang.Object)
     */
    public List getObjectPermissionsForObject(ExecutionContext context, Object targetObject) {
        if (targetObject == null || !(targetObject instanceof InternalURI)) {
            return new ArrayList();
        }
        InternalURI res = (InternalURI) targetObject;
        List objList = getRepoObjectPermissions(context, "repo:" + res.getPath(), null);
        return makeObjectPermissionClientList("repo:" + res.getPath(), objList);
    }

    @Override
    public List<ObjectPermission> getEffectivePermissionsForObject(ExecutionContext context, Object targetObject) {
        List<ObjectPermission> result;
        BasicAclEntry[] acls = (BasicAclEntry[]) getAcls(targetObject);
        if (acls != null) {
            result = new ArrayList<ObjectPermission>(acls.length);

            for (BasicAclEntry entry : acls) {
                if (!(entry.getRecipient() instanceof String)) {
                    ObjectPermission permission = new ObjectPermissionImpl();
                    permission.setPermissionRecipient(entry.getRecipient());
                    permission.setPermissionMask(entry.getMask());
                    permission.setURI(((ObjectPermissionServiceImpl.URIObjectIdentity) entry.getAclObjectIdentity())
                            .getURI());
                    result.add(permission);
                }
            }
        } else {
            result = Collections.EMPTY_LIST;
        }
        return result;
    }

    /* (non-Javadoc)
      * @see com.jaspersoft.jasperserver.api.metadata.user.service.ObjectPermissionService#getObjectPermissionsForRecipient(com.jaspersoft.jasperserver.api.common.domain.ExecutionContext, java.lang.Object)
      */
    public List getObjectPermissionsForRecipient(ExecutionContext context, Object recipient) {
        List objList = getRepoObjectPermissions(context, null, recipient);
        return makeObjectPermissionClientList(null, objList);
    }

    /* (non-Javadoc)
     * @see com.jaspersoft.jasperserver.api.metadata.user.service.ObjectPermissionService#getObjectPermissionsForObjectAndRecipient(com.jaspersoft.jasperserver.api.common.domain.ExecutionContext, java.lang.Object, java.lang.Object)
     */
    public List getObjectPermissionsForObjectAndRecipient(ExecutionContext context, Object targetObject,
            Object recipient) {
        if (!(targetObject instanceof InternalURI)) {
            return new ArrayList();
        }
        InternalURI res = (InternalURI) targetObject;
        List objList = getRepoObjectPermissions(context, RESOURCE_URI_PREFIX + res.getPath(), recipient);
        return makeObjectPermissionClientList(RESOURCE_URI_PREFIX + res.getPath(), objList);
    }

    /* (non-Javadoc)
     * @see com.jaspersoft.jasperserver.api.metadata.user.service.ObjectPermissionService#isObjectAdministrable(com.jaspersoft.jasperserver.api.common.domain.ExecutionContext, java.lang.Object)
     */
    public boolean isObjectAdministrable(ExecutionContext context, Object targetObject) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if ((targetObject == null) || (auth == null)) {
            return true;
        }
        BasicAclEntry[] allAcls = (BasicAclEntry[]) effectiveAclsResolver
                .resolveEffectiveAcls(getAcls(targetObject), auth);
        if (allAcls != null) {
            for (int i = 0; i < allAcls.length; i++) {
                BasicAclEntry aclEntry = allAcls[i];
                if (aclEntry.getMask() == SimpleAclEntry.ADMINISTRATION) {
                    return true;
                }
            }
        }
        return false;
    }

    private List makeObjectPermissionClientList(String uri, List objList) {
        List resultList = new ArrayList(objList.size());
        /*
              if ((objList == null || objList.isEmpty()) && uri != null && uri.length() > 0) {
                 // Deal with default inheritance: return an object with a URI only
                 RepoObjectPermission repoPerm = new RepoObjectPermission();
                 repoPerm.setURI(uri);
                 if (objList == null) {
        objList = new ArrayList();
                 }
                 objList.add(repoPerm);
              }
        */
        for (Iterator it = objList.iterator(); !objList.isEmpty() && it.hasNext();) {
            RepoObjectPermission repoPerm = (RepoObjectPermission) it.next();
            ObjectPermission clientPermission = (ObjectPermission) repoPerm.toClient(getObjectMappingFactory());
            resultList.add(clientPermission);
        }
        return resultList;
    }

    /* (non-Javadoc)
     * @see com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.PersistentObjectResolver#getPersistentObject(java.lang.Object)
     */
    public Object getPersistentObject(Object clientObject) {
        // If already persisted, just return it
        if (clientObject == null) {
            return null;
        } else if (clientObject instanceof IdedObject) {
            return clientObject;
        } else if (clientObject instanceof Role || clientObject instanceof User) {
            return ((PersistentObjectResolver) userService).getPersistentObject(clientObject);
        } else if (clientObject instanceof Resource) {
            // TODO Hack! Make it an interface!
            String uri = ((Resource) clientObject).getPath();
            return repoService.findByURI(RepoResource.class, uri, false);
        } else if (clientObject instanceof ObjectPermission) {
            return getRepoObjectPermission(null, (ObjectPermission) clientObject);
        }
        return null;
    }

    /* (non-Javadoc)
     * @see com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.ReferenceResolver#getExternalReference(java.lang.String, java.lang.Class)
     */
    public RepoResource getExternalReference(String uri, Class persistentReferenceClass) {
        return ((ReferenceResolver) repoService).getExternalReference(uri, persistentReferenceClass);
    }

    /* (non-Javadoc)
     * @see com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.ReferenceResolver#getReference(com.jaspersoft.jasperserver.api.metadata.common.service.impl.hibernate.persistent.RepoResource, com.jaspersoft.jasperserver.api.metadata.common.domain.Resource, java.lang.Class)
     */
    public RepoResource getReference(RepoResource owner, Resource resource, Class persistentReferenceClass) {
        return ((ReferenceResolver) repoService).getReference(owner, resource, persistentReferenceClass);
    }

    protected String repositoryURI(String repositoryPath) {
        return RESOURCE_URI_PREFIX + repositoryPath;
    }

    protected void clearAclEntriesCache(String uri) {
        URIObjectIdentity objId = new URIObjectIdentity(uri);
        if (log.isDebugEnabled()) {
            log.debug("Removing " + objId + " from permissions");
        }
        basicAclEntryCache.removeEntriesFromCache(objId);
    }

    public void updateObjectPermissionRepositoryPath(String oldPath, String newPath) {
        String oldURI = repositoryURI(oldPath);
        String newURI = repositoryURI(newPath);

        List permissions = getRepoObjectPermissions(null, oldURI, null);
        if (permissions != null && !permissions.isEmpty()) {
            for (Iterator it = permissions.iterator(); it.hasNext();) {
                RepoObjectPermission permission = (RepoObjectPermission) it.next();
                permission.setURI(newURI);
                getHibernateTemplate().update(permission);

                if (log.isDebugEnabled()) {
                    log.debug("Updated URI of permission for " + oldURI + " and "
                            + permission.getPermissionRecipient() + " to " + newURI);
                }
            }
        }

        clearAclEntriesCache(oldURI);
    }

    public int getInheritedObjectPermissionMask(ExecutionContext context, Object targetObject, Object recipient) {
        if (!(targetObject instanceof InternalURI)) {
            if (log.isDebugEnabled()) {
                log.debug("Requested inherited permission non InternalURI object " + targetObject);
            }

            return SimpleAclEntry.NOTHING;
        }

        InternalURI resource = (InternalURI) targetObject;
        int permissionMask = SimpleAclEntry.NOTHING;

        String folderURI = getParentURI(resource.getPath());
        while (folderURI != null) {
            List permissions = getRepoObjectPermissions(context, folderURI, recipient);
            if (permissions != null && !permissions.isEmpty()) {
                RepoObjectPermission permissionObject = (RepoObjectPermission) permissions.get(0);
                permissionMask = permissionObject.getPermissionMask();
                break;
            }

            folderURI = getParentURI(folderURI);
        }

        if (log.isDebugEnabled()) {
            if (folderURI == null) {
                log.debug("No inherited permission found for object " + resource.getPath() + " and recipient "
                        + recipient);
            } else {
                log.debug("Inherited permission " + permissionMask + " found at " + folderURI + " for object "
                        + resource.getPath() + " and recipient " + recipient);
            }
        }

        return permissionMask;
    }

}