RM-2130 (Check classification after method execution, filtering results where appropriate)

+review RM-94

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/DEV/ENFORCE@106639 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Tuna Aksoy
2015-06-20 18:42:32 +00:00
parent e79b4a9d8f
commit 3772764f8e
11 changed files with 407 additions and 339 deletions

View File

@@ -35,24 +35,30 @@
<!-- Classification Method Interceptor --> <!-- Classification Method Interceptor -->
<bean id="preMethodInvocationProcessor"
class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PreMethodInvocationProcessor">
</bean>
<bean id="postMethodInvocationProcessor"
class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PostMethodInvocationProcessor">
</bean>
<bean id="classificationMethodInterceptor" <bean id="classificationMethodInterceptor"
class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor"> class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor">
<property name="preMethodInvocationProcessor" ref="preMethodInvocationProcessor" />
<property name="postMethodInvocationProcessor" ref="postMethodInvocationProcessor" />
</bean> </bean>
<bean id="classificationMethodInterceptorPostProcessor" <bean id="classificationMethodInterceptorPostProcessor"
class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptorPostProcessor" /> class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptorPostProcessor" />
<bean id="postMethodInvocationProcessorRegistry"
class="org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PostMethodInvocationProcessorRegistry" />
<bean id="basePostMethodInvocationProcessor" <bean id="basePostMethodInvocationProcessor"
abstract="true" abstract="true"
init-method="register"> init-method="register">
<property name="classificationMethodInterceptor" ref="classificationMethodInterceptor" />
<property name="nodeService" ref="NodeService" /> <property name="nodeService" ref="NodeService" />
<property name="dictionaryService" ref="DictionaryService" /> <property name="dictionaryService" ref="DictionaryService" />
<property name="contentClassificationService" ref="ContentClassificationService" /> <property name="contentClassificationService" ref="ContentClassificationService" />
<property name="postMethodInvocationProcessorRegistry" ref="postMethodInvocationProcessorRegistry" /> <property name="postMethodInvocationProcessor" ref="postMethodInvocationProcessor" />
</bean> </bean>
<bean id="abstractPostMethodInvocationProcessor" <bean id="abstractPostMethodInvocationProcessor"

View File

@@ -88,7 +88,7 @@ public class SecurityClearanceServiceImpl extends ServiceBaseImpl implements Sec
*/ */
private SecurityClearance getUserSecurityClearance(final String userName) private SecurityClearance getUserSecurityClearance(final String userName)
{ {
final NodeRef personNode = personService.getPerson(userName, true); final NodeRef personNode = personService.getPerson(userName, false);
final PersonInfo personInfo = personService.getPerson(personNode); final PersonInfo personInfo = personService.getPerson(personNode);
ClearanceLevel clearanceLevel = ClearanceLevelManager.NO_CLEARANCE; ClearanceLevel clearanceLevel = ClearanceLevelManager.NO_CLEARANCE;

View File

@@ -1,246 +1,129 @@
/* /*
* Copyright (C) 2005-2015 Alfresco Software Limited. * Copyright (C) 2005-2015 Alfresco Software Limited.
* *
* This file is part of Alfresco * This file is part of Alfresco
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.alfresco.module.org_alfresco_module_rm.classification.interceptor; package org.alfresco.module.org_alfresco_module_rm.classification.interceptor;
import static org.alfresco.model.ContentModel.TYPE_CONTENT; import static org.alfresco.repo.security.authentication.AuthenticationUtil.getFullyAuthenticatedUser;
import static org.codehaus.plexus.util.StringUtils.isNotBlank; import static org.alfresco.repo.security.authentication.AuthenticationUtil.isRunAsUserTheSystemUser;
import static org.alfresco.util.ParameterCheck.mandatory;
import java.lang.reflect.Method; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import org.alfresco.jlan.server.filesys.AccessDeniedException; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PostMethodInvocationProcessor;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceBootstrap; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PreMethodInvocationProcessor;
import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.aopalliance.intercept.MethodInterceptor;
import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor; import org.aopalliance.intercept.MethodInvocation;
import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.PostMethodInvocationProcessorRegistry;
import org.alfresco.module.org_alfresco_module_rm.util.AlfrescoTransactionSupport; /**
import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil; * Classification method interceptor
import org.alfresco.repo.transaction.RetryingTransactionHelper; *
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; * @author Roy Wetherall
import org.alfresco.service.cmr.dictionary.DictionaryService; * @author Tuna Aksoy
import org.alfresco.service.cmr.repository.NodeRef; * @since 3.0
import org.alfresco.service.cmr.repository.NodeService; */
import org.alfresco.service.transaction.TransactionService; public class ClassificationMethodInterceptor implements MethodInterceptor
import org.alfresco.util.GUID; {
import org.aopalliance.intercept.MethodInterceptor; /** Pre method invocation processor */
import org.aopalliance.intercept.MethodInvocation; private PreMethodInvocationProcessor preMethodInvocationProcessor;
import org.apache.log4j.Logger;
import org.springframework.beans.BeansException; /** Post method invocation processor */
import org.springframework.context.ApplicationContext; private PostMethodInvocationProcessor postMethodInvocationProcessor;
import org.springframework.context.ApplicationContextAware;
/**
/** * @return the preMethodInvocationProcessor
* Classification method interceptor */
* protected PreMethodInvocationProcessor getPreMethodInvocationProcessor()
* @author Roy Wetherall {
* @since 3.0 return this.preMethodInvocationProcessor;
*/ }
public class ClassificationMethodInterceptor implements MethodInterceptor, ApplicationContextAware
{ /**
/** Logger */ * @return the postMethodInvocationProcessor
private static Logger LOG = Logger.getLogger(ClassificationMethodInterceptor.class); */
protected PostMethodInvocationProcessor getPostMethodInvocationProcessor()
private static final String KEY_PROCESSING = GUID.generate(); {
return this.postMethodInvocationProcessor;
/** application context */ }
private ApplicationContext applicationContext;
/**
/** * @param postMethodInvocationProcessor the postMethodInvocationProcessor to set
* @param applicationContext application context */
* @throws BeansException public void setPostMethodInvocationProcessor(PostMethodInvocationProcessor postMethodInvocationProcessor)
*/ {
@Override this.postMethodInvocationProcessor = postMethodInvocationProcessor;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException }
{
this.applicationContext = applicationContext; /**
} * @param preMethodInvocationProcessor the preMethodInvocationProcessor to set
*/
protected AuthenticationUtil getAuthenticationUtil() public void setPreMethodInvocationProcessor(PreMethodInvocationProcessor preMethodInvocationProcessor)
{ {
return (AuthenticationUtil)applicationContext.getBean("rm.authenticationUtil"); this.preMethodInvocationProcessor = preMethodInvocationProcessor;
} }
/** /**
* @return {@link ContentClassificationService} content classification service * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/ */
protected ContentClassificationService getContentClassificationService() @Override
{ public Object invoke(MethodInvocation invocation) throws Throwable
return (ContentClassificationService)applicationContext.getBean("contentClassificationService"); {
} mandatory("invocation", invocation);
protected AlfrescoTransactionSupport getAlfrescoTransactionSupport() Object result = null;
{
return (AlfrescoTransactionSupport)applicationContext.getBean("rm.alfrescoTransactionSupport"); boolean canProceed = true;
} boolean isUserValid = isUserValid();
protected RetryingTransactionHelper getRetryingTransactionHelper() if (isUserValid)
{ {
return ((TransactionService)applicationContext.getBean("transactionService")).getRetryingTransactionHelper(); //FIXME!!!
} // Pre method invocation processing
//canProceed = getPreMethodInvocationProcessor().process(invocation);
protected ClassificationServiceBootstrap getClassificationServiceBootstrap() }
{
return (ClassificationServiceBootstrap)applicationContext.getBean("classificationServiceBootstrap"); if (canProceed)
} {
// Method invocation
protected NodeService getNodeService() result = invocation.proceed();
{
return (NodeService)applicationContext.getBean("dbNodeService"); // Post method invocation processing
} if (isUserValid && result != null)
{
protected DictionaryService getDictionaryService() result = getPostMethodInvocationProcessor().process(result);
{ }
return (DictionaryService)applicationContext.getBean("dictionaryService"); }
}
return result;
protected PostMethodInvocationProcessorRegistry getPostMethodInvocationProcessorRegistry() }
{
return (PostMethodInvocationProcessorRegistry)applicationContext.getBean("postMethodInvocationProcessorRegistry"); /**
} * Checks if we have an authenticated user and that they aren't "System"
*
/** * @return <code>true</code> if we have an authenticated user and that they aren't "System", <code>false</code> otherwise.
* Check that the current user is cleared to see the items passed as parameters to the current */
* method invocation. private boolean isUserValid()
* {
* @param invocation method invocation boolean result = false;
*/
@SuppressWarnings("rawtypes") if (isNotBlank(getFullyAuthenticatedUser()) && !isRunAsUserTheSystemUser())
public NodeRef checkClassification(final MethodInvocation invocation) {
{ result = true;
// do in transaction }
return getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<NodeRef>()
{ return result;
public NodeRef execute() throws Throwable }
{ }
NodeRef result = null;
// ensure classification service has been bootstrapped
if (getClassificationServiceBootstrap().isInitialised())
{
// check that we are not already processing a classification check
Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING);
if (value == null)
{
Method method = invocation.getMethod();
Class[] params = method.getParameterTypes();
int position = 0;
for (Class param : params)
{
// if the param is a node reference
if (NodeRef.class.isAssignableFrom(param))
{
// mark the transaction as processing a classification check
getAlfrescoTransactionSupport().bindResource(KEY_PROCESSING, Boolean.TRUE);
try
{
// get the value of the parameter
NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position];
// if node exists then see if the current user has clearance
result = checkNode(testNodeRef);
}
finally
{
// clear the transaction as processed a classification check
getAlfrescoTransactionSupport().unbindResource(KEY_PROCESSING);
}
}
position++;
}
}
}
return result;
}
}, true);
}
private boolean isUserValid()
{
boolean result = false;
// check that we have an authenticated user and that they aren't "system"
if (isNotBlank(getAuthenticationUtil().getFullyAuthenticatedUser()) &&
!getAuthenticationUtil().isRunAsUserTheSystemUser())
{
result = true;
}
return result;
}
private NodeRef checkNode(NodeRef testNodeRef) throws AccessDeniedException
{
NodeRef result = testNodeRef;
if (getNodeService().exists(testNodeRef) &&
getDictionaryService().isSubClass(getNodeService().getType(testNodeRef), TYPE_CONTENT) &&
!getContentClassificationService().hasClearance(testNodeRef))
{
// FIXME
result = null;
//throw new AccessDeniedException("You do not have clearance!");
}
return result;
}
/**
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable
{
// FIXME
//NodeRef preInvocation = null;
Object postInvocation = null;
boolean isUserValid = isUserValid();
// pre method invocation check
if (isUserValid)
{
// FIXME
//preInvocation = checkClassification(invocation);
//checkClassification(invocation);
}
// method proceed
postInvocation = invocation.proceed();
// post method invocation processing
if (isUserValid && postInvocation != null)
{
Class<? extends Object> clazz = postInvocation.getClass();
BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessorRegistry().getProcessor(clazz);
if (processor != null)
{
postInvocation = processor.process(postInvocation);
}
else
{
LOG.debug("No post method invocation processor found for '" + clazz + "'.");
}
}
return postInvocation;
}
}

View File

@@ -32,17 +32,17 @@ import org.springframework.beans.factory.support.ManagedList;
* <p> * <p>
* Bean factory post processor that inspects available beans and adds the classification method interceptor * Bean factory post processor that inspects available beans and adds the classification method interceptor
* to all public services. * to all public services.
* *
* @author Roy Wetherall * @author Roy Wetherall
* @since 3.0.a * @since 3.0.a
*/ */
public class ClassificationMethodInterceptorPostProcessor implements BeanFactoryPostProcessor public class ClassificationMethodInterceptorPostProcessor implements BeanFactoryPostProcessor
{ {
private static final String PROP_INTERCEPTOR_NAMES = "interceptorNames"; private static final String PROP_INTERCEPTOR_NAMES = "interceptorNames";
private static final String TYPE_PROXY_FACTORY_BEAN = "ProxyFactoryBean"; private static final String TYPE_PROXY_FACTORY_BEAN = "ProxyFactoryBean";
private static final String POSTFIX_SERVICE = "Service"; private static final String POSTFIX_SERVICE = "Service";
private static final String BEAN_NAME_CLASSIFICATION_METHOD_INTERCEPTOR = "classificationMethodInterceptor"; private static final String BEAN_NAME_CLASSIFICATION_METHOD_INTERCEPTOR = "classificationMethodInterceptor";
/** /**
* @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
*/ */
@@ -56,27 +56,27 @@ public class ClassificationMethodInterceptorPostProcessor implements BeanFactory
{ {
// get bean definition // get bean definition
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(bean); BeanDefinition beanDefinition = beanFactory.getBeanDefinition(bean);
// only modify proxy factory beans that follow the public service naming postfix convention // only modify proxy factory beans that follow the public service naming postfix convention
if (beanDefinition.getBeanClassName() != null && if (beanDefinition.getBeanClassName() != null &&
beanDefinition.getBeanClassName().endsWith(TYPE_PROXY_FACTORY_BEAN) && beanDefinition.getBeanClassName().endsWith(TYPE_PROXY_FACTORY_BEAN) &&
bean.endsWith(POSTFIX_SERVICE)) bean.endsWith(POSTFIX_SERVICE))
{ {
// get the property values for the bean definition // get the property values for the bean definition
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
if (propertyValues.contains(PROP_INTERCEPTOR_NAMES)) if (propertyValues.contains(PROP_INTERCEPTOR_NAMES))
{ {
// get the current list of interceptor names // get the current list of interceptor names
PropertyValue value = propertyValues.getPropertyValue(PROP_INTERCEPTOR_NAMES); PropertyValue value = propertyValues.getPropertyValue(PROP_INTERCEPTOR_NAMES);
ManagedList<RuntimeBeanNameReference> list = (ManagedList<RuntimeBeanNameReference>)value.getValue(); ManagedList<RuntimeBeanNameReference> list = (ManagedList<RuntimeBeanNameReference>)value.getValue();
if (!list.isEmpty()) if (!list.isEmpty())
{ {
// add reference to classification method interceptor // add reference to classification method interceptor
RuntimeBeanNameReference beanReference = new RuntimeBeanNameReference(BEAN_NAME_CLASSIFICATION_METHOD_INTERCEPTOR); RuntimeBeanNameReference beanReference = new RuntimeBeanNameReference(BEAN_NAME_CLASSIFICATION_METHOD_INTERCEPTOR);
list.add(beanReference); list.add(beanReference);
} }
} }
} }
} }
} }
} }

View File

@@ -18,8 +18,6 @@
*/ */
package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor;
import static org.alfresco.util.ParameterCheck.mandatory;
import java.util.Collection; import java.util.Collection;
/** /**
@@ -54,23 +52,24 @@ public abstract class AbstractPostMethodInvocationProcessor extends BasePostMeth
@Override @Override
public <T> T process(T object) public <T> T process(T object)
{ {
mandatory("object", object); T result = object;
T result = null; if (result != null)
if (isCollection(object))
{ {
Collection collection = ((Collection) object); if (isCollection(result))
if (!collection.isEmpty())
{ {
checkObjectClass(collection.iterator().next()); Collection collection = ((Collection) result);
result = (T) processCollection(collection); if (!collection.isEmpty())
{
checkObjectClass(collection.iterator().next());
result = (T) processCollection(collection);
}
}
else
{
checkObjectClass(result);
result = processSingleElement(result);
} }
}
else
{
checkObjectClass(object);
result = (T) processSingleElement(object);
} }
return result; return result;

View File

@@ -23,7 +23,6 @@ import static org.alfresco.model.ContentModel.TYPE_CONTENT;
import java.util.Collection; import java.util.Collection;
import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService; import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService;
import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.ClassificationMethodInterceptor;
import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ClassificationPostMethodInvocationException.NotSupportedClassTypeException; import org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.ClassificationPostMethodInvocationException.NotSupportedClassTypeException;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -37,9 +36,6 @@ import org.alfresco.service.cmr.repository.NodeService;
*/ */
public abstract class BasePostMethodInvocationProcessor public abstract class BasePostMethodInvocationProcessor
{ {
/** Classification method interceptor */
private ClassificationMethodInterceptor classificationMethodInterceptor;
/** Node service */ /** Node service */
private NodeService nodeService; private NodeService nodeService;
@@ -49,16 +45,8 @@ public abstract class BasePostMethodInvocationProcessor
/** Content classification service */ /** Content classification service */
private ContentClassificationService contentClassificationService; private ContentClassificationService contentClassificationService;
/** Post method invocation processor registry */ /** Post method invocation processor */
private PostMethodInvocationProcessorRegistry postMethodInvocationProcessorRegistry; private PostMethodInvocationProcessor postMethodInvocationProcessor;
/**
* @return the classificationMethodInterceptor
*/
protected ClassificationMethodInterceptor getClassificationMethodInterceptor()
{
return this.classificationMethodInterceptor;
}
/** /**
* @return the nodeService * @return the nodeService
@@ -85,19 +73,11 @@ public abstract class BasePostMethodInvocationProcessor
} }
/** /**
* @return the postMethodInvocationProcessorRegistry * @return the postMethodInvocationProcessor
*/ */
protected PostMethodInvocationProcessorRegistry getPostMethodInvocationProcessorRegistry() protected PostMethodInvocationProcessor getPostMethodInvocationProcessor()
{ {
return this.postMethodInvocationProcessorRegistry; return this.postMethodInvocationProcessor;
}
/**
* @param classificationMethodInterceptor the classificationMethodInterceptor to set
*/
public void setClassificationMethodInterceptor(ClassificationMethodInterceptor classificationMethodInterceptor)
{
this.classificationMethodInterceptor = classificationMethodInterceptor;
} }
/** /**
@@ -125,11 +105,11 @@ public abstract class BasePostMethodInvocationProcessor
} }
/** /**
* @param postMethodInvocationProcessorRegistry the postMethodInvocationProcessorRegistry to set * @param postMethodInvocationProcessor the postMethodInvocationProcessor to set
*/ */
public void setPostMethodInvocationProcessorRegistry(PostMethodInvocationProcessorRegistry postMethodInvocationProcessorRegistry) public void setPostMethodInvocationProcessor(PostMethodInvocationProcessor postMethodInvocationProcessor)
{ {
this.postMethodInvocationProcessorRegistry = postMethodInvocationProcessorRegistry; this.postMethodInvocationProcessor = postMethodInvocationProcessor;
} }
/** /**
@@ -152,7 +132,7 @@ public abstract class BasePostMethodInvocationProcessor
*/ */
public void register() public void register()
{ {
getPostMethodInvocationProcessorRegistry().register(this); getPostMethodInvocationProcessor().register(this);
} }
/** /**

View File

@@ -71,7 +71,7 @@ public class ChildAssociationRefPostMethodInvocationProcessor extends AbstractPo
@Override @Override
public Boolean apply(ChildAssociationRef childAssociationRef) public Boolean apply(ChildAssociationRef childAssociationRef)
{ {
return process(childAssociationRef) != null; return processSingleElement(childAssociationRef) != null;
} }
}); });
} }

View File

@@ -18,8 +18,6 @@
*/ */
package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor; package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor;
import static org.alfresco.util.ParameterCheck.mandatory;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
@@ -34,29 +32,29 @@ public abstract class CollectionPostMethodInvocationProcessor extends BasePostMe
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object) * @see org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor.BasePostMethodInvocationProcessor#process(java.lang.Object)
*/ */
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "rawtypes" })
@Override @Override
public <T> T process(T object) public <T> T process(T object)
{ {
mandatory("object", object); T result = object;
Object result = object; if (result != null)
Collection collection = ((Collection) object);
if (!collection.isEmpty())
{ {
Iterator iterator = collection.iterator(); Collection collection = ((Collection) result);
if (iterator.hasNext()) if (!collection.isEmpty())
{ {
Class<? extends Object> clazz = iterator.next().getClass(); Iterator iterator = collection.iterator();
BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessorRegistry().getProcessor(clazz); if (iterator.hasNext())
if (processor != null)
{ {
result = processor.process(object); BasePostMethodInvocationProcessor processor = getPostMethodInvocationProcessor().getProcessor(iterator.next());
if (processor != null)
{
result = processor.process(object);
}
} }
} }
} }
return (T) result; return result;
} }
} }

View File

@@ -22,6 +22,10 @@ import static org.alfresco.util.ParameterCheck.mandatory;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.log4j.Logger;
/** /**
* Registry for post method invocation processors * Registry for post method invocation processors
@@ -29,8 +33,11 @@ import java.util.Map;
* @author Tuna Aksoy * @author Tuna Aksoy
* @since 3.0 * @since 3.0
*/ */
public class PostMethodInvocationProcessorRegistry public class PostMethodInvocationProcessor
{ {
/** Logger */
private static Logger LOG = Logger.getLogger(PostMethodInvocationProcessor.class);
/** Post method invocation processors */ /** Post method invocation processors */
private Map<Class<?>, BasePostMethodInvocationProcessor> processors = new HashMap<Class<?>, BasePostMethodInvocationProcessor>(); private Map<Class<?>, BasePostMethodInvocationProcessor> processors = new HashMap<Class<?>, BasePostMethodInvocationProcessor>();
@@ -51,7 +58,7 @@ public class PostMethodInvocationProcessorRegistry
* *
* @return the processors Available processors * @return the processors Available processors
*/ */
public Map<Class<?>, BasePostMethodInvocationProcessor> getProcessors() private Map<Class<?>, BasePostMethodInvocationProcessor> getProcessors()
{ {
return this.processors; return this.processors;
} }
@@ -59,24 +66,52 @@ public class PostMethodInvocationProcessorRegistry
/** /**
* Gets the processor from the available processors * Gets the processor from the available processors
* *
* @param clazz The runtime class of the post invocation object * @param object The post invocation object
* @return The suitable processor for the given class * @return The suitable processor for the given class
*/ */
public BasePostMethodInvocationProcessor getProcessor(Class<? extends Object> clazz) protected BasePostMethodInvocationProcessor getProcessor(Object object)
{ {
mandatory("clazz", clazz); mandatory("object", object);
BasePostMethodInvocationProcessor result = null; BasePostMethodInvocationProcessor result = null;
Class<? extends Object> clazz = object.getClass();
for (Map.Entry<Class<?>, BasePostMethodInvocationProcessor> processor : getProcessors().entrySet()) Set<Entry<Class<?>, BasePostMethodInvocationProcessor>> processorsEntrySet = getProcessors().entrySet();
for (Map.Entry<Class<?>, BasePostMethodInvocationProcessor> processorEntry : processorsEntrySet)
{ {
if (processor.getKey().isAssignableFrom(clazz)) if (processorEntry.getKey().isAssignableFrom(clazz))
{ {
result = processor.getValue(); result = processorEntry.getValue();
break; break;
} }
} }
return result; return result;
} }
/**
* Processes the given object
*
* @param object The object to process
* @return The processed object
*/
public <T> T process(T object)
{
T result = object;
if (result != null)
{
BasePostMethodInvocationProcessor processor = getProcessor(result);
if (processor != null)
{
result = processor.process(result);
}
else
{
LOG.debug("No processor found for '" + result + "'.");
}
}
return result;
}
} }

View File

@@ -0,0 +1,173 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.module.org_alfresco_module_rm.classification.interceptor.processor;
import static java.lang.Boolean.TRUE;
import static org.alfresco.model.ContentModel.TYPE_CONTENT;
import static org.alfresco.util.GUID.generate;
import static org.alfresco.util.ParameterCheck.mandatory;
import java.lang.reflect.Method;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationServiceBootstrap;
import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService;
import org.alfresco.module.org_alfresco_module_rm.util.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.transaction.TransactionService;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* Pre method invocation processor
*
* @author Roy Wetherall
* @author Tuna Aksoy
* @since 3.0
*/
public class PreMethodInvocationProcessor implements ApplicationContextAware
{
private static final String KEY_PROCESSING = generate();
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
protected ContentClassificationService getContentClassificationService()
{
return (ContentClassificationService)applicationContext.getBean("contentClassificationService");
}
protected AlfrescoTransactionSupport getAlfrescoTransactionSupport()
{
return (AlfrescoTransactionSupport)applicationContext.getBean("rm.alfrescoTransactionSupport");
}
protected RetryingTransactionHelper getRetryingTransactionHelper()
{
return ((TransactionService)applicationContext.getBean("transactionService")).getRetryingTransactionHelper();
}
protected ClassificationServiceBootstrap getClassificationServiceBootstrap()
{
return (ClassificationServiceBootstrap)applicationContext.getBean("classificationServiceBootstrap");
}
protected NodeService getNodeService()
{
return (NodeService)applicationContext.getBean("dbNodeService");
}
protected DictionaryService getDictionaryService()
{
return (DictionaryService)applicationContext.getBean("dictionaryService");
}
/**
* Checks if the current user is cleared to see the items
* passed as parameters to the current method invocation.
*
* @param invocation The current method invocation
* @return <code>true</code> if the user is cleared to see the items, <code>false</code> otherwise
*/
public boolean process(final MethodInvocation invocation)
{
mandatory("invocation", invocation);
// do in transaction
return getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Boolean>()
{
@SuppressWarnings("rawtypes")
public Boolean execute() throws Throwable
{
Boolean result = true;
// ensure classification service has been bootstrapped
if (getClassificationServiceBootstrap().isInitialised())
{
// check that we are not already processing a classification check
Object value = getAlfrescoTransactionSupport().getResource(KEY_PROCESSING);
if (value == null)
{
Method method = invocation.getMethod();
Class[] params = method.getParameterTypes();
int position = 0;
for (Class param : params)
{
// if the param is a node reference
if (NodeRef.class.isAssignableFrom(param))
{
// mark the transaction as processing a classification check
getAlfrescoTransactionSupport().bindResource(KEY_PROCESSING, TRUE);
try
{
// get the value of the parameter
NodeRef testNodeRef = (NodeRef) invocation.getArguments()[position];
// if node exists then see if the current user has clearance
result = isNodeCleared(testNodeRef);
}
finally
{
// clear the transaction as processed a classification check
getAlfrescoTransactionSupport().unbindResource(KEY_PROCESSING);
}
}
position++;
}
}
}
return result;
}
}, true);
}
/**
* Checks if the given node exists, if it is a content and if
* the currently logged in user is cleared to see it.
*
* @param nodeRef Node reference to check
* @return <code>true</code> if the node passes the checks, <code>false</code> otherwise
*/
private boolean isNodeCleared(NodeRef nodeRef)
{
boolean result = true;
if (getNodeService().exists(nodeRef) &&
getDictionaryService().isSubClass(getNodeService().getType(nodeRef), TYPE_CONTENT) &&
!getContentClassificationService().hasClearance(nodeRef))
{
result = false;
}
return result;
}
}

View File

@@ -46,12 +46,6 @@ public class NodeRefPostMethodInvocationProcessorUnitTest extends BaseUnitTest
@InjectMocks private NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor; @InjectMocks private NodeRefPostMethodInvocationProcessor nodeRefPostMethodInvocationProcessor;
@Mock private ContentClassificationService mockedContentClassificationService; @Mock private ContentClassificationService mockedContentClassificationService;
@Test (expected = IllegalArgumentException.class)
public void testProcessingNull()
{
nodeRefPostMethodInvocationProcessor.process(null);
}
@Test (expected = NotSupportedClassTypeException.class) @Test (expected = NotSupportedClassTypeException.class)
public void testProccessingAnotherClassType() public void testProccessingAnotherClassType()
{ {