diff --git a/source/java/org/alfresco/cmis/CMISServices.java b/source/java/org/alfresco/cmis/CMISServices.java index 7e167f4228..30d8cf3323 100644 --- a/source/java/org/alfresco/cmis/CMISServices.java +++ b/source/java/org/alfresco/cmis/CMISServices.java @@ -188,8 +188,10 @@ public interface CMISServices * @param propertyName * the property name * @return value + * @throws CMISInvalidArgumentException + * if an argument is invalid */ - public Serializable getProperty(AssociationRef assocRef, String propertyName); + public Serializable getProperty(AssociationRef assocRef, String propertyName) throws CMISInvalidArgumentException; /** * Get all properties of a node's type. @@ -202,6 +204,17 @@ public interface CMISServices */ public Map getProperties(NodeRef nodeRef) throws CMISInvalidArgumentException; + /** + * Get all properties of an association's type. + * + * @param assocRef + * the association + * @return the properties + * @throws CMISInvalidArgumentException + * if an argument is invalid + */ + public Map getProperties(AssociationRef assocRef) throws CMISInvalidArgumentException; + /** * Get all of a node's values for the properties in the given type or aspect. * @@ -449,6 +462,17 @@ public interface CMISServices */ public CMISTypeDefinition getTypeDefinition(String typeId) throws CMISInvalidArgumentException; + /** + * Gets the type definition for a given object. + * + * @param object + * the object + * @return the type definition + * @throws CMISInvalidArgumentException + * if an argument is invalid + */ + public CMISTypeDefinition getTypeDefinition(Object object) throws CMISInvalidArgumentException; + /** * Gets the CMIS base types. * @@ -754,4 +778,94 @@ public interface CMISServices InputStream contentStream, String mimeType) throws CMISConstraintException, CMISVersioningException, CMISObjectNotFoundException, CMISContentAlreadyExistsException, CMISStreamNotSupportedException, CMISInvalidArgumentException, CMISPermissionDeniedException; + + /** + * Creates a policy object of the specified type, and optionally adds the policy to a folder. Currently no policy + * types can be created in Alfresco. + * + * @param properties + * CMIS properties + * @param folderId + * parent folder for this new policy + * @param policies + * the policies + * @return Id of the created policy object + * @throws CMISConstraintException + * if there is a problem with the supplied properties + * @throws CMISInvalidArgumentException + * if an argument is invalid + * @throws CMISRuntimeException + * on other exceptions + */ + public String createPolicy(Map properties, String folderId, List policies) + throws CMISConstraintException, CMISRuntimeException, CMISInvalidArgumentException; + + /** + * Applies a policy object to a target object. + * + * @param policyId + * policy Id + * @param objectId + * target object Id + * @throws CMISConstraintException + * if an object isn't of the right type + * @throws CMISVersioningException + * if an object's versioning state isn't as expected + * @throws CMISObjectNotFoundException + * if an object does not exist + * @throws CMISInvalidArgumentException + * if an argument is invalid + * @throws CMISPermissionDeniedException + * if access to an object is denied + */ + public void applyPolicy(String policyId, String objectId) throws CMISConstraintException, CMISVersioningException, + CMISObjectNotFoundException, CMISInvalidArgumentException, CMISPermissionDeniedException; + + /** + * Gets the list of policy objects currently applied to a target object. + * + * @param objectId + * the object id + * @param filter + * property filter + * @return the applied policies + * @throws CMISConstraintException + * if an object isn't of the right type + * @throws CMISVersioningException + * if an object's versioning state isn't as expected + * @throws CMISObjectNotFoundException + * if an object does not exist + * @throws CMISInvalidArgumentException + * if an argument is invalid + * @throws CMISPermissionDeniedException + * if access to an object is denied + * @throws CMISFilterNotValidException + * if the property filter is invalid + */ + public List getAppliedPolicies(String objectId, String filter) throws CMISConstraintException, + CMISVersioningException, CMISObjectNotFoundException, CMISInvalidArgumentException, + CMISPermissionDeniedException, CMISFilterNotValidException; + + /** + * Removes a previously applied policy from a target object. The policy object is not deleted, and may still be + * applied to other objects. + * + * @param policyId + * policy Id + * @param objectId + * target object Id. + * @throws CMISConstraintException + * if an object isn't of the right type + * @throws CMISVersioningException + * if an object's versioning state isn't as expected + * @throws CMISObjectNotFoundException + * if an object does not exist + * @throws CMISInvalidArgumentException + * if an argument is invalid + * @throws CMISPermissionDeniedException + * if access to an object is denied + */ + public void removePolicy(String policyId, String objectId) throws CMISConstraintException, CMISVersioningException, + CMISObjectNotFoundException, CMISInvalidArgumentException, CMISPermissionDeniedException; + } diff --git a/source/java/org/alfresco/cmis/PropertyFilter.java b/source/java/org/alfresco/cmis/PropertyFilter.java new file mode 100644 index 0000000000..bd6fb7b5fa --- /dev/null +++ b/source/java/org/alfresco/cmis/PropertyFilter.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2005-2010 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 . + */ +package org.alfresco.cmis; + +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + + +/** + * Property filter supporting CMIS filter expression + * + * @author Dmitry Lazurkin + * @author Dmitry Velichkevich + */ +public class PropertyFilter +{ + public static final String MATCH_ALL_FILTER = "*"; + public static final String PROPERTY_NAME_TOKENS_DELIMITER = ","; + + private static final Pattern PROPERTY_FILTER_REGEX = Pattern.compile("^([^\\s,\"'\\\\\\.\\(\\)]+)(,[^\\s,\"'\\\\\\.\\(\\)]+)*$"); + private Set properties; + + /** + * @param filter filter value (case insensitive) + * @throws FilterNotValidException if filter string isn't valid + */ + public PropertyFilter(String filter) throws CMISFilterNotValidException + { + if (filter != null) + { + if (!PROPERTY_FILTER_REGEX.matcher(filter).matches()) + { + throw new CMISFilterNotValidException("Property filter \"" + filter + "\" is invalid"); + } + + if (!filter.equals(MATCH_ALL_FILTER)) + { + String[] tokens = filter.split(PROPERTY_NAME_TOKENS_DELIMITER); + properties = new HashSet(tokens.length * 2); + for (String token : tokens) + { + properties.add(token); + } + } + } + } + + /** + * @param property property token name + * @return true returns if property is allowed by filter. In other case returns false + */ + public boolean allow(String property) + { + return properties == null || properties.contains(property); + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/cmis/PropertyFilterTest.java b/source/java/org/alfresco/cmis/PropertyFilterTest.java new file mode 100644 index 0000000000..27b7f6ef28 --- /dev/null +++ b/source/java/org/alfresco/cmis/PropertyFilterTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2005-2010 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 . + */ +package org.alfresco.cmis; + +import junit.framework.TestCase; + + +/** + * @author Dmitry Velichkevich + */ +public class PropertyFilterTest extends TestCase +{ + private static final String NAME_TOKEN = "name"; + + private static final String[] FILTER_TOKENS = new String[] { NAME_TOKEN, "objectId" }; + private static final String[] TOKENS_THAT_ARE_NOT_ALLOWED = new String[] { "ParentId", "parentId", "ParEnTiD", "IsMajorVersion", "iSmAJORvERSION" }; + + private static final String VALID_MATCHE_ALL_FILTER = "*"; + private static final String VALID_FILTER_WITH_NAME = NAME_TOKEN; + private static final String VALID_FILTER_WITH_SEVERAL_TOKENS = "name,objectId"; + private static final String LONG_VALID_FILTER_WITH_SEVERAL_TOKENS = "objectId,name,CreationDate*,Created;By"; + + private static final String INVALID_MATCHE_ALL_FILTER = "*,"; + private static final String INVALID_FILTER_WITH_NAME = "*name,"; + private static final String INVALID_FILTER_WITH_SEVERAL_TOKENS = "name,,objectId"; + private static final String LONG_INVALID_FILTER_WITH_SEVERAL_TOKENS = "objectId, name CreationDate, CreatedBy*"; + private static final String INVALID_FILTER_WITH_SEVERAL_TOKENS_WITHOUT_BREAKS = ",name,objectId,CreationDate"; + private static final String INVALID_FILTER_WITH_SEVERAL_TOKENS_AND_WITH_BREAKS_IN_SOME_PLACES = " name, objectId,CreationDate CreatedBy ModifiedBy, LastModifiedBy"; + private static final String INVALID_FILTER_WITH_FIRST_BREAK_SYMBOL = " name, objectId,CreationDate, CreatedBy, ModifiedBy, LastModifiedBy"; + private static final String INVALID_FILTER_WITH_DENIED_SYMBOL = "objectId\"name"; + private static final String INVALID_FILTER_WITH_LAST_INVALID_SYMBOL = "objectId,name\\"; + + public void testValidFilters() throws Exception + { + allTokensValidAssertion(new PropertyFilter(null)); + allTokensValidAssertion(new PropertyFilter(VALID_MATCHE_ALL_FILTER)); + + onlyNameTokensAssertionValid(new PropertyFilter(VALID_FILTER_WITH_NAME)); + + nameAndObjectIdTokensAssertionValid(new PropertyFilter(VALID_FILTER_WITH_SEVERAL_TOKENS)); + nameAndObjectIdTokensAssertionValid(new PropertyFilter(LONG_VALID_FILTER_WITH_SEVERAL_TOKENS)); + } + + public void testInvalidFilters() throws Exception + { + invalidFilterAssertion(INVALID_MATCHE_ALL_FILTER); + invalidFilterAssertion(INVALID_FILTER_WITH_NAME); + invalidFilterAssertion(INVALID_FILTER_WITH_SEVERAL_TOKENS); + invalidFilterAssertion(LONG_INVALID_FILTER_WITH_SEVERAL_TOKENS); + invalidFilterAssertion(INVALID_FILTER_WITH_SEVERAL_TOKENS_WITHOUT_BREAKS); + invalidFilterAssertion(INVALID_FILTER_WITH_SEVERAL_TOKENS_AND_WITH_BREAKS_IN_SOME_PLACES); + invalidFilterAssertion(INVALID_FILTER_WITH_FIRST_BREAK_SYMBOL); + invalidFilterAssertion(INVALID_FILTER_WITH_DENIED_SYMBOL); + invalidFilterAssertion(INVALID_FILTER_WITH_LAST_INVALID_SYMBOL); + } + + private void nameAndObjectIdTokensAssertionValid(PropertyFilter propertyFilter) + { + for (String token : FILTER_TOKENS) + { + assertTrue(token + " should be allowed", propertyFilter.allow(token)); + } + + for (String token : TOKENS_THAT_ARE_NOT_ALLOWED) + { + assertFalse(token + " should not be allowed", propertyFilter.allow(token)); + } + } + + private void onlyNameTokensAssertionValid(PropertyFilter propertyFilter) + { + for (String token : FILTER_TOKENS) + { + if (!token.equals(NAME_TOKEN)) + { + break; + } + + assertTrue(propertyFilter.allow(token)); + } + + for (String token : TOKENS_THAT_ARE_NOT_ALLOWED) + { + assertFalse(propertyFilter.allow(token)); + } + } + + private void allTokensValidAssertion(PropertyFilter propertyFilter) + { + for (String token : FILTER_TOKENS) + { + assertTrue(propertyFilter.allow(token)); + } + + for (String token : TOKENS_THAT_ARE_NOT_ALLOWED) + { + assertTrue(propertyFilter.allow(token)); + } + } + + private void invalidFilterAssertion(String filterValue) + { + try + { + new PropertyFilter(filterValue); + + fail("Invalid filter \"" + filterValue + "\" was interpreted as valid"); + } + catch (CMISFilterNotValidException e) + { + // Success + } + } + +} diff --git a/source/java/org/alfresco/cmis/mapping/CMISMapping.java b/source/java/org/alfresco/cmis/mapping/CMISMapping.java index bcd142c612..b0dcf7c991 100644 --- a/source/java/org/alfresco/cmis/mapping/CMISMapping.java +++ b/source/java/org/alfresco/cmis/mapping/CMISMapping.java @@ -232,7 +232,7 @@ public class CMISMapping implements InitializingBean registerEvaluator(CMISScope.DOCUMENT, new ParentActionEvaluator(new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_REMOVE_OBJECT_FROM_FOLDER, true))); registerEvaluator(CMISScope.DOCUMENT, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_CONTENT_STREAM, PermissionService.READ_CONTENT)); registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_APPLY_POLICY, false)); - registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_APPLIED_POLICIES, false)); + registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_APPLIED_POLICIES, true)); registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_REMOVE_POLICY, false)); registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_CREATE_RELATIONSHIP, true)); registerEvaluator(CMISScope.DOCUMENT, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_RENDITIONS, true)); @@ -250,7 +250,7 @@ public class CMISMapping implements InitializingBean // Is CAN_MOVE_OBJECT correct mapping? registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_MOVE_OBJECT, PermissionService.DELETE_NODE)); registerEvaluator(CMISScope.FOLDER, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_APPLY_POLICY, false)); - registerEvaluator(CMISScope.FOLDER, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_APPLIED_POLICIES, false)); + registerEvaluator(CMISScope.FOLDER, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_APPLIED_POLICIES, true)); registerEvaluator(CMISScope.FOLDER, new FixedValueActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_REMOVE_POLICY, false)); registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_GET_CHILDREN, PermissionService.READ_CHILDREN)); registerEvaluator(CMISScope.FOLDER, new PermissionActionEvaluator(serviceRegistry, CMISAllowedActionEnum.CAN_CREATE_DOCUMENT, PermissionService.CREATE_CHILDREN)); diff --git a/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java b/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java index 44e3e19ede..1cd8163815 100644 --- a/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java +++ b/source/java/org/alfresco/cmis/mapping/CMISServicesImpl.java @@ -60,6 +60,7 @@ import org.alfresco.cmis.CMISTypesFilterEnum; import org.alfresco.cmis.CMISUpdatabilityEnum; import org.alfresco.cmis.CMISVersioningException; import org.alfresco.cmis.CMISVersioningStateEnum; +import org.alfresco.cmis.PropertyFilter; import org.alfresco.cmis.dictionary.CMISFolderTypeDefinition; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; @@ -778,6 +779,27 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware, return typeDef; } + /* + * (non-Javadoc) + * @see org.alfresco.cmis.CMISServices#getTypeDefinition(java.lang.Object) + */ + public CMISTypeDefinition getTypeDefinition(Object object) throws CMISInvalidArgumentException + { + if (object instanceof Version) + { + return getTypeDefinition(((Version) object).getFrozenStateNodeRef()); + } + else if (object instanceof NodeRef) + { + return getTypeDefinition((NodeRef) object); + } + else if (object instanceof AssociationRef) + { + return getTypeDefinition((AssociationRef) object); + } + throw new CMISInvalidArgumentException("Invalid type " + object.getClass()); + } + /* * (non-Javadoc) * @see org.alfresco.cmis.CMISServices#getBaseTypes() @@ -789,16 +811,12 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware, /* * (non-Javadoc) - * @see org.alfresco.cmis.CMISServices#getProperty(org.alfresco.service.cmr.repository.AssociationRef, java.lang.String) + * @see org.alfresco.cmis.CMISServices#getProperty(org.alfresco.service.cmr.repository.AssociationRef, + * java.lang.String) */ - public Serializable getProperty(AssociationRef assocRef, String propertyName) + public Serializable getProperty(AssociationRef assocRef, String propertyName) throws CMISInvalidArgumentException { - QName typeQName = assocRef.getTypeQName(); - CMISTypeDefinition typeDef = cmisDictionaryService.findTypeForClass(typeQName); - if (typeDef == null) - { - throw new AlfrescoRuntimeException("Relationship Type " + typeQName + " not found in CMIS Dictionary"); - } + CMISTypeDefinition typeDef = getTypeDefinition(assocRef); CMISPropertyDefinition propDef = cmisDictionaryService.findProperty(propertyName, typeDef); if (propDef == null) { @@ -817,6 +835,22 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware, return getProperties(nodeRef, getTypeDefinition(nodeRef)); } + /* + * (non-Javadoc) + * @see org.alfresco.cmis.CMISServices#getProperties(org.alfresco.service.cmr.repository.AssociationRef) + */ + public Map getProperties(AssociationRef assocRef) throws CMISInvalidArgumentException + { + CMISTypeDefinition typeDef = getTypeDefinition(assocRef); + Map propDefs = typeDef.getPropertyDefinitions(); + Map values = new HashMap(propDefs.size() * 2); + for (CMISPropertyDefinition propDef : propDefs.values()) + { + values.put(propDef.getPropertyId().getId(), propDef.getPropertyAccessor().getValue(assocRef)); + } + return values; + } + /* * (non-Javadoc) * @see org.alfresco.cmis.CMISServices#getProperties(org.alfresco.service.cmr.repository.NodeRef, @@ -1193,6 +1227,10 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware, return (T) associationRef; } } + else + { + throw new CMISInvalidArgumentException(objectId + " is not an object ID"); + } } catch (AccessDeniedException e) { @@ -1728,6 +1766,81 @@ public class CMISServicesImpl implements CMISServices, ApplicationContextAware, } } + /* + * (non-Javadoc) + * @see org.alfresco.cmis.CMISServices#createPolicy(java.util.Map, java.lang.String, java.util.List) + */ + public String createPolicy(Map properties, String folderId, List policies) + throws CMISConstraintException, CMISRuntimeException, CMISInvalidArgumentException + { + String typeId = (String) properties.get(CMISDictionaryModel.PROP_OBJECT_TYPE_ID); + if (typeId == null) + { + throw new CMISConstraintException("Policy type ID not specified"); + } + CMISTypeDefinition typeDefinition = getTypeDefinition(typeId); + if (typeDefinition.getBaseType().getTypeId() != CMISDictionaryModel.POLICY_TYPE_ID) + { + throw new CMISConstraintException(typeId + " is not a policy type"); + } + if (!typeDefinition.isCreatable()) + { + throw new CMISConstraintException(typeId + " is not a creatable type"); + } + // Should never get here, as currently no policy types are creatable + throw new CMISRuntimeException("Internal error"); + } + + /* + * (non-Javadoc) + * @see org.alfresco.cmis.CMISServices#applyPolicy(java.lang.String, java.lang.String) + */ + public void applyPolicy(String policyId, String objectId) throws CMISConstraintException, CMISVersioningException, + CMISObjectNotFoundException, CMISInvalidArgumentException, CMISPermissionDeniedException + { + CMISTypeDefinition typeDef = getTypeDefinition(getReadableObject(objectId, Object.class)); + if (!typeDef.isControllablePolicy()) + { + throw new CMISConstraintException("Type " + typeDef.getTypeId().getId() + " does not allow policies to be applied"); + } + getReadableObject(policyId, CMISTypeDefinition.class); + // Expect exception to be throw by now + } + + /* + * (non-Javadoc) + * @see org.alfresco.cmis.CMISServices#getAppliedPolicies(java.lang.String, java.lang.String) + */ + public List getAppliedPolicies(String objectId, String filter) throws CMISConstraintException, + CMISVersioningException, CMISObjectNotFoundException, CMISInvalidArgumentException, + CMISPermissionDeniedException, CMISFilterNotValidException + { + // Get the object + getReadableObject(objectId, Object.class); + + // Parse the filter + new PropertyFilter(filter); + + // Nothing else to do + return Collections.emptyList(); + } + + /* + * (non-Javadoc) + * @see org.alfresco.cmis.CMISServices#removePolicy(java.lang.String, java.lang.String) + */ + public void removePolicy(String policyId, String objectId) throws CMISConstraintException, CMISVersioningException, + CMISObjectNotFoundException, CMISInvalidArgumentException, CMISPermissionDeniedException + { + CMISTypeDefinition typeDef = getTypeDefinition(getReadableObject(objectId, Object.class)); + if (!typeDef.isControllablePolicy()) + { + throw new CMISConstraintException("Type " + typeDef.getTypeId().getId() + " does not allow policies to be applied"); + } + getReadableObject(policyId, CMISTypeDefinition.class); + // Expect exception to be throw by now + } + /** * Validates that a node is versionable. * diff --git a/source/java/org/alfresco/repo/transaction/RetryingTransactionInterceptor.java b/source/java/org/alfresco/repo/transaction/RetryingTransactionInterceptor.java new file mode 100755 index 0000000000..6d1e4394dc --- /dev/null +++ b/source/java/org/alfresco/repo/transaction/RetryingTransactionInterceptor.java @@ -0,0 +1,81 @@ +/* +* Copyright (C) 2005-2010 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 . +*/ +package org.alfresco.repo.transaction; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.transaction.TransactionService; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.springframework.transaction.interceptor.TransactionAspectSupport; +import org.springframework.transaction.interceptor.TransactionAttribute; + +/** + * @author Dmitry Velichkevich + */ +public class RetryingTransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor +{ + private TransactionService transactionService; + + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } + + public Object invoke(final MethodInvocation target) throws Throwable + { + if ((null != target) && (null != target.getThis()) && (null != target.getMethod())) + { + final Method method = target.getMethod(); + final TransactionAttribute transactionAttribute = getTransactionAttributeSource().getTransactionAttribute(method, target.getThis().getClass()); + if (null != transactionAttribute) + { + return transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + try + { + return method.invoke(target.getThis(), target.getArguments()); + } + catch (InvocationTargetException e) + { + if (null != e.getTargetException()) + { + throw e.getTargetException(); + } + else + { + throw new AlfrescoRuntimeException(e.getMessage(), e); + } + } + } + }, transactionAttribute.isReadOnly(), (TransactionAttribute.PROPAGATION_REQUIRES_NEW == transactionAttribute.getPropagationBehavior())); + } + else + { + return method.invoke(target.getThis(), target.getArguments()); + } + } + throw new AlfrescoRuntimeException("Invalid undefined MethodInvocation instance"); + } +}