com.surevine.alfresco.esl.impl.ESCAfterInvocationProvider.java Source code

Java tutorial

Introduction

Here is the source code for com.surevine.alfresco.esl.impl.ESCAfterInvocationProvider.java

Source

/*
 * Copyright (C) 2008-2010 Surevine Limited.
 * 
 * Although intended for deployment and use alongside Alfresco this module should
 * be considered 'Not a Contribution' as defined in Alfresco'sstandard contribution agreement, see
 * http://www.alfresco.org/resource/AlfrescoContributionAgreementv2.pdf
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package com.surevine.alfresco.esl.impl;

import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.ConfigAttribute;
import net.sf.acegisecurity.ConfigAttributeDefinition;
import net.sf.acegisecurity.afterinvocation.AfterInvocationProvider;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.repo.security.permissions.impl.acegi.FilteringResultSet;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.module.org_alfresco_module_dod5015.caveat.RMCaveatConfigComponent;

import java.util.BitSet;
import java.util.Date;
import org.alfresco.service.cmr.repository.NodeService;

/**
 * After invocation provider to remove items the user can't see from results lists in searches, a la Records Management, by using FilteringResultSets
 * 
 * Copyright Surevine Ltd 2010. All rights reserved
 * 
 * @author alfresco@surevine.com
 * @author simon.white@surevine.com
 * 
 * 
 */
public class ESCAfterInvocationProvider implements AfterInvocationProvider {

    private static final Log LOGGER = LogFactory.getLog(ESCAfterInvocationProvider.class);

    /**
     * String in the Spring config identifying which methods are to be filtered
     */
    protected static final String ATTR_IDENT = "AFTER_ESC";

    private Date _nextTimeToReportMissingNodes = new Date(0l);

    private long _missingNodeReportingFrequencyMillis = 60000l;

    private RMCaveatConfigComponent _caveatComponent;

    public void setCaveatComponent(RMCaveatConfigComponent caveatComponent) {
        _caveatComponent = caveatComponent;
    }

    private NodeService _nodeService;

    public void setNodeService(NodeService nodeService) {
        _nodeService = nodeService;
    }

    public void setFrequencyOfReportingOnMissingNodesInMillis(long frequency) {
        _missingNodeReportingFrequencyMillis = frequency;
    }

    /**
     * Perform the filtering on ResultSets, and ignore everything else
     */
    public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
            Object returnedObject) throws AccessDeniedException {

        // Pass everything except ResultSets along, filter resultsets
        if (returnedObject != null && ResultSet.class.isAssignableFrom(returnedObject.getClass())) {
            return decideOnResultSet((ResultSet) returnedObject); // safe cast as per above if() statement
        }
        // else

        return returnedObject;
    }

    /**
     * Called from decide(...) this method filters the contents of the input ResultSet, returning an output ResultSet containing only those results that RMCaveatConfig allows the current user to see
     * 
     * @param unfilteredResultSet
     *            A result set to filter
     * @return ResultSet containing only those elemenets in <code>unfilteredResultSet</code> for which the Caveat Service allows access to the current user
     */
    protected ResultSet decideOnResultSet(ResultSet unfilteredResultSet) {

        boolean recordAnyMissingNodes = new Date().after(_nextTimeToReportMissingNodes);
        boolean foundMissingNodes = false;

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Entering decideOnResultSet");
        }

        // Shortcut some obvious exit conditions
        if (unfilteredResultSet == null) {
            return null;
        }
        if (unfilteredResultSet.length() == 0) {
            return unfilteredResultSet;
        }

        BitSet inclusionMask = new BitSet(unfilteredResultSet.length());
        FilteringResultSet frs = new FilteringResultSet(unfilteredResultSet, inclusionMask);

        int length = unfilteredResultSet.length();

        for (int i = 0; i < length; i++) {

            NodeRef nodeRef = unfilteredResultSet.getNodeRef(i);

            if (_nodeService.exists(nodeRef)) { // If the node exists, check whether we can see it

                if (_caveatComponent.hasAccess(nodeRef)) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Access Granted to " + nodeRef);
                    }
                    inclusionMask.set(i);
                } else if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Access forbidden to " + nodeRef);
                }
            } else {
                foundMissingNodes = true;
                if (recordAnyMissingNodes) {
                    LOGGER.warn("The node [" + nodeRef + "] was returned from a search but does not exist.");
                }
            }
        }

        if (foundMissingNodes) {
            _nextTimeToReportMissingNodes = new Date(new Date().getTime() + _missingNodeReportingFrequencyMillis);
            LOGGER.info("To preserve performance, the system will not report on further missing nodes until "
                    + _nextTimeToReportMissingNodes);
        }

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Leaving decideOnResultSet");
        }

        return frs;
    }

    public boolean supports(ConfigAttribute attribute) {

        if ((attribute.getAttribute() != null) && (attribute.getAttribute().startsWith(ATTR_IDENT))) {
            return true;
        } else {
            return false;
        }
    }

    public boolean supports(Class clazz) {
        return (MethodInvocation.class.isAssignableFrom(clazz));
    }

}