split aspectj management; refactored

This commit is contained in:
Brian Long 2023-04-04 16:49:16 -04:00
parent 85ff365031
commit 5728b2a92b
33 changed files with 1419 additions and 134 deletions

15
pom.xml
View File

@ -36,6 +36,8 @@
<alfresco.sdk.version>4.2.0</alfresco.sdk.version>
<alfresco.platform.version>6.2.0-ga</alfresco.platform.version>
<aspectj.version>1.9.4</aspectj.version>
<acs-platform.tomcat.opts>-javaagent:/var/lib/tomcat/dev/lib/aspectjweaver-${aspectj.version}.jar</acs-platform.tomcat.opts>
</properties>
<dependencyManagement>
@ -58,6 +60,11 @@
<artifactId>alfresco-repository</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.inteligr8.alfresco</groupId>
<artifactId>aspectj-platform-module</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
@ -65,16 +72,16 @@
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.26</version>
<version>2.33</version>
<extensions>true</extensions>
<configuration>
<tiles>
<!-- Documentation: https://bitbucket.org/inteligr8/ootbee-beedk/src/stable/beedk-acs-platform-self-rad-tile -->
<tile>com.inteligr8.ootbee:beedk-acs-platform-self-rad-tile:[1.0.0,2.0.0)</tile>
<tile>com.inteligr8.ootbee:beedk-acs-platform-self-rad-tile:[1.0.0,1.1.0)</tile>
<!-- Documentation: https://bitbucket.org/inteligr8/ootbee-beedk/src/stable/beedk-acs-platform-module-tile -->
<tile>com.inteligr8.ootbee:beedk-acs-platform-module-tile:[1.0.0,2.0.0)</tile>
<tile>com.inteligr8.ootbee:beedk-acs-platform-module-tile:[1.0.0,1.1.0)</tile>
<!-- Documentation: https://bitbucket.org/inteligr8/ootbee-beedk/src/stable/beedk-acs-platform-self-it-tile -->
<tile>com.inteligr8.ootbee:beedk-acs-platform-self-it-tile:[1.0.0,2.0.0)</tile>
<tile>com.inteligr8.ootbee:beedk-acs-platform-self-it-tile:[1.0.0,1.1.0)</tile>
</tiles>
</configuration>
</plugin>

6
rad.sh
View File

@ -6,17 +6,17 @@ discoverArtifactId() {
rebuild() {
echo "Rebuilding project ..."
mvn process-classes
mvn process-test-classes
}
start() {
echo "Rebuilding project and starting Docker containers to support rapid application development ..."
mvn -Drad process-classes
mvn -Drad process-test-classes
}
start_log() {
echo "Rebuilding project and starting Docker containers to support rapid application development ..."
mvn -Drad -Ddocker.showLogs process-classes
mvn -Drad -Ddocker.showLogs process-test-classes
}
stop() {

View File

@ -10,7 +10,7 @@ import java.lang.annotation.Target;
ElementType.METHOD,
ElementType.PARAMETER
})
public @interface IfAspect {
public @interface IfNodeHasAspect {
String aspect() default "";

View File

@ -10,7 +10,7 @@ import java.lang.annotation.Target;
ElementType.METHOD,
ElementType.PARAMETER
})
public @interface IfNodeType {
public @interface IfNodeOfType {
String type() default "";

View File

@ -11,7 +11,7 @@ import org.alfresco.service.namespace.QNamePattern;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.springframework.beans.factory.BeanNameAware;
public interface AspectConstrainable extends BeanNameAware {
public interface NodeAspectConstrainable extends BeanNameAware {
String getBeanName();

View File

@ -4,15 +4,14 @@ import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.inteligr8.alfresco.annotations.service.AsyncService;
@Aspect
@Component
public class AsyncAspect {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@ -20,18 +19,23 @@ public class AsyncAspect {
@Autowired
private AsyncService asyncService;
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.Asynchronous)")
public void asyncMethod() {
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.Asynchronous) && execution(* *(..))")
public void isAsyncAnnotated() {
}
@Around("asyncMethod()")
public void async(ProceedingJoinPoint joinPoint) throws Throwable {
@Around("isAsyncAnnotated()")
public Object async(ProceedingJoinPoint joinPoint) throws Throwable {
if (this.asyncService.isCurrentThreadAsynchronous()) {
this.logger.trace("Intercepted an @Async method call while already asynchronous; executing synchronously");
joinPoint.proceed();
return joinPoint.proceed();
} else {
this.logger.trace("Intercepted an @Async method call; redirecting to Async service");
this.asyncService.push(joinPoint);
MethodSignature methodSig = (MethodSignature) joinPoint.getSignature();
if (!Void.class.equals(methodSig.getReturnType()))
this.logger.warn("An @Asynchronous method returns a value, which is not expected/allowed: {}", methodSig.getMethod());
return null;
}
}

View File

@ -14,35 +14,38 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.inteligr8.alfresco.annotations.Authorizable;
import com.inteligr8.alfresco.annotations.Authorized;
import com.inteligr8.alfresco.annotations.AuthorizedAsSystem;
import com.inteligr8.alfresco.annotations.Authorizable;
@Aspect
@Order(Ordered.HIGHEST_PRECEDENCE + Short.MAX_VALUE)
@Component
public class AuthorizedAspect {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.Authorized || com.inteligr8.alfresco.annotations.AuthorizedAsSystem)")
public void runAsableMethod() {
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.Authorized) && execution(* *(..))")
public void isAuthorizedAnnotated() {
}
@Around("runAsableMethod()")
public void runAs(ProceedingJoinPoint joinPoint) throws Throwable {
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.AuthorizedAsSystem) && execution(* *(..))")
public void isAuthorizedAsSystemAnnotated() {
}
@Around("isAuthorizedAnnotated() || isAuthorizedAsSystemAnnotated()")
public Object runAs(ProceedingJoinPoint joinPoint) throws Throwable {
this.logger.trace("runAs({})", joinPoint);
String runAsUser = this.getRunAsUser(joinPoint);
String currentRunAsUser = AuthenticationUtil.getRunAsUser();
if (currentRunAsUser != null && currentRunAsUser.equals(runAsUser)) {
this.logger.trace("The current context is already running as the specified user: {}", currentRunAsUser);
joinPoint.proceed();
return joinPoint.proceed();
} else {
this.logger.debug("Changing runAs context: {} => {}", currentRunAsUser, runAsUser);
this.runAs(joinPoint, runAsUser);
return this.runAs(joinPoint, runAsUser);
}
}
@ -54,28 +57,31 @@ public class AuthorizedAspect {
Method method = methodSig.getMethod();
if (method.getAnnotation(AuthorizedAsSystem.class) != null) {
String runAs = AuthenticationUtil.getSystemUserName();
this.logger.trace("The @AuthorizedAsSystem method {}#{} will run as: {}", joinPoint.getThis().getClass(), method, runAs);
this.logger.trace("The @AuthorizedAsSystem method '{}' will run as: {}", method, runAs);
return runAs;
}
if (joinPoint.getThis() instanceof Authorizable) {
String runAs = StringUtils.trimToNull(((Authorizable) joinPoint.getThis()).authorizeAsUser());
this.logger.trace("The @Authorized method {}#{} is Authorizable: {}", joinPoint.getThis().getClass(), method, runAs);
if (runAs == null)
throw new IllegalArgumentException("A 'null' value is allowed from authorizeAsUser()");
this.logger.trace("The @Authorized method '{}' is Authorizable: {}", method, runAs);
return runAs;
}
Authorized runAsAnnotation = method.getAnnotation(Authorized.class);
String runAs = StringUtils.trimToNull(runAsAnnotation.value());
if (runAs != null) {
this.logger.trace("The @Authorized method {}#{} must run as: {}", joinPoint.getThis().getClass(), method, runAs);
this.logger.trace("The @Authorized method '{}' must run as: {}", method, runAs);
return runAs;
}
this.logger.trace("The @Authorized method {}#{} must run as system", joinPoint.getThis().getClass(), method);
this.logger.trace("The @Authorized method '{}' must run as system", method);
return AuthenticationUtil.getSystemUserName();
}
private void runAs(final ProceedingJoinPoint joinPoint, String runAsUser) throws Throwable {
private Object runAs(final ProceedingJoinPoint joinPoint, String runAsUser) throws Throwable {
RunAsWork<Object> work = new RunAsWork<Object>() {
public Object doWork() throws Exception {
try {
@ -89,7 +95,7 @@ public class AuthorizedAspect {
};
try {
AuthenticationUtil.runAs(work, runAsUser);
return AuthenticationUtil.runAs(work, runAsUser);
} catch (RuntimeException re) {
// attempt to unwrap the exception
if (re.getMessage() != null && re.getMessage().equals("Error during run as.")) {

View File

@ -11,13 +11,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.inteligr8.alfresco.annotations.IfChildAssociationIsPrimary;
@Aspect
@Order(Ordered.HIGHEST_PRECEDENCE + 100) // ordering before transaction/authorized
@Component
@Order(Ordered.HIGHEST_PRECEDENCE + Byte.MAX_VALUE) // ordering before transaction/authorized
public class ChildIsPrimaryAspect extends MethodOrParameterAspect<IfChildAssociationIsPrimary> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@ -27,13 +25,19 @@ public class ChildIsPrimaryAspect extends MethodOrParameterAspect<IfChildAssocia
return IfChildAssociationIsPrimary.class;
}
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.IfChildAssociationIsPrimary)")
public void isChildAssocPrimaryMethod() {
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.IfChildAssociationIsPrimary) && execution(* *(..))")
public void isIfChildAssociationIsPrimaryMethodAnnotated() {
}
@Pointcut("execution(* *(@com.inteligr8.alfresco.annotations.IfChildAssociationIsPrimary (*), ..))")
public void isIfChildAssociationIsPrimaryParamAnnotated() {
}
@Around("isChildAssocPrimaryMethod() or execution(* *(@com.inteligr8.alfresco.annotations.IfChildAssociationIsPrimary (*), ..))")
public void isChildAssocPrimary(ProceedingJoinPoint joinPoint) throws Throwable {
this.checkParameters(joinPoint, new ApplicableParameterCallback<IfChildAssociationIsPrimary>() {
@Around("isIfChildAssociationIsPrimaryMethodAnnotated() || isIfChildAssociationIsPrimaryParamAnnotated()")
public Object isChildAssocPrimary(ProceedingJoinPoint joinPoint) throws Throwable {
this.logger.trace("isChildAssocPrimary({})", joinPoint);
return this.checkParameters(joinPoint, new ApplicableParameterCallback<IfChildAssociationIsPrimary>() {
@Override
public boolean checkParameter(ProceedingJoinPoint joinPoint, Method method, IfChildAssociationIsPrimary annotation, int parameterIndex) {
Object arg = joinPoint.getArgs()[parameterIndex];

View File

@ -14,7 +14,7 @@ public abstract class MethodOrParameterAspect<T extends Annotation> {
public abstract Class<T> getAnnotationClass();
public void checkParameters(ProceedingJoinPoint joinPoint, ApplicableParameterCallback<T> callback) throws Throwable {
public Object checkParameters(ProceedingJoinPoint joinPoint, ApplicableParameterCallback<T> callback) throws Throwable {
MethodSignature methodSig = (MethodSignature) joinPoint.getSignature();
Method method = methodSig.getMethod();
T methodAnnotation = method.getAnnotation(this.getAnnotationClass());
@ -26,12 +26,12 @@ public abstract class MethodOrParameterAspect<T extends Annotation> {
if (annotation != null) {
if (!callback.checkParameter(joinPoint, method, annotation, p)) {
this.logger.debug("The parameter '{}' condition is false; skipping method: {}", method.getParameters()[p].getName(), method);
return;
return null;
}
}
}
joinPoint.proceed();
return joinPoint.proceed();
}
}

View File

@ -23,14 +23,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.inteligr8.alfresco.annotations.AspectConstrainable;
import com.inteligr8.alfresco.annotations.IfAspect;
import com.inteligr8.alfresco.annotations.NodeAspectConstrainable;
import com.inteligr8.alfresco.annotations.IfNodeHasAspect;
@Aspect
@Component
public class AspectAspect extends QNameBasedAspect<IfAspect> {
public class NodeAspectAspect extends QNameBasedAspect<IfNodeHasAspect> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@ -40,7 +38,7 @@ public class AspectAspect extends QNameBasedAspect<IfAspect> {
@Autowired
private NodeService nodeService;
@Value("${inteligr8.cache.aspectConstrainable.maxBeans}")
@Value("${inteligr8.cache.nodeAspectConstrainable.maxBeans}")
private int maxBeans;
@Override
@ -49,43 +47,49 @@ public class AspectAspect extends QNameBasedAspect<IfAspect> {
}
@Override
public Class<IfAspect> getAnnotationClass() {
return IfAspect.class;
public Class<IfNodeHasAspect> getAnnotationClass() {
return IfNodeHasAspect.class;
}
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.IfAspect)")
public void isAspectMethod() {
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.IfNodeHasAspect) && execution(* *(..))")
public void isIfAspectAnnotated() {
}
@Pointcut("execution(* *(@com.inteligr8.alfresco.annotations.IfNodeHasAspect (*), ..))")
public void isIfAspectParamAnnotated() {
}
@Around("isAspectMethod() or execution(* *(@com.inteligr8.alfresco.annotations.IfAspect (*), ..))")
public void isAspect(ProceedingJoinPoint joinPoint) throws Throwable {
this.checkParameters(joinPoint, new ApplicableParameterCallback<IfAspect>() {
@Around("isIfAspectAnnotated() || isIfAspectParamAnnotated()")
public Object isNodeAspect(ProceedingJoinPoint joinPoint) throws Throwable {
this.logger.trace("isNodeAspect({})", joinPoint);
return this.checkParameters(joinPoint, new ApplicableParameterCallback<IfNodeHasAspect>() {
@Override
public boolean checkParameter(ProceedingJoinPoint joinPoint, Method method, IfAspect annotation, int parameterIndex) {
public boolean checkParameter(ProceedingJoinPoint joinPoint, Method method, IfNodeHasAspect annotation, int parameterIndex) {
Object arg = joinPoint.getArgs()[parameterIndex];
Collection<NodeRef> nodeRefs = extractNodeRefs(arg);
if (nodeRefs == null)
return true;
QNameBasedCallback<IfAspect> callback = new QNameBasedCallback<IfAspect>() {
QNameBasedCallback<IfNodeHasAspect> callback = new QNameBasedCallback<IfNodeHasAspect>() {
@Override
public boolean isConstrained() {
return joinPoint.getThis() instanceof AspectConstrainable;
return joinPoint.getThis() instanceof NodeAspectConstrainable;
}
@Override
public String getConstrainableClassSimpleName() {
return AspectConstrainable.class.getSimpleName();
return NodeAspectConstrainable.class.getSimpleName();
}
@Override
public String getBeanName() {
return ((AspectConstrainable) joinPoint.getThis()).getBeanName();
return ((NodeAspectConstrainable) joinPoint.getThis()).getBeanName();
}
@Override
public Collection<? extends QNamePattern> constrainedQNames() {
return ((AspectConstrainable) joinPoint.getThis()).constrainedAspects();
return ((NodeAspectConstrainable) joinPoint.getThis()).constrainedAspects();
}
@Override
@ -103,7 +107,7 @@ public class AspectAspect extends QNameBasedAspect<IfAspect> {
}
@Override
public String getAnnotationValue(IfAspect annotation) {
public String getAnnotationValue(IfNodeHasAspect annotation) {
return annotation.aspect();
}
};
@ -134,8 +138,19 @@ public class AspectAspect extends QNameBasedAspect<IfAspect> {
return Arrays.asList(assocRef.getSourceRef(), assocRef.getTargetRef());
} else if (obj instanceof Collection<?>) {
Set<NodeRef> nodeRefs = new LinkedHashSet<>();
for (Object o : ((Collection<?>) obj))
nodeRefs.addAll(this.extractNodeRefs(o));
for (Object o : ((Collection<?>) obj)) {
Collection<NodeRef> subNodeRefs = this.extractNodeRefs(o);
if (subNodeRefs != null)
nodeRefs.addAll(subNodeRefs);
}
return nodeRefs;
} else if (obj instanceof Object[]) {
Set<NodeRef> nodeRefs = new LinkedHashSet<>();
for (Object o : ((Object[]) obj)) {
Collection<NodeRef> subNodeRefs = this.extractNodeRefs(o);
if (subNodeRefs != null)
nodeRefs.addAll(subNodeRefs);
}
return nodeRefs;
} else {
return null;

View File

@ -23,14 +23,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.inteligr8.alfresco.annotations.IfNodeType;
import com.inteligr8.alfresco.annotations.IfNodeOfType;
import com.inteligr8.alfresco.annotations.NodeTypeConstrainable;
@Aspect
@Component
public class NodeTypeAspect extends QNameBasedAspect<IfNodeType> {
public class NodeTypeAspect extends QNameBasedAspect<IfNodeOfType> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@ -49,28 +47,34 @@ public class NodeTypeAspect extends QNameBasedAspect<IfNodeType> {
}
@Override
public Class<IfNodeType> getAnnotationClass() {
return IfNodeType.class;
public Class<IfNodeOfType> getAnnotationClass() {
return IfNodeOfType.class;
}
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.IfNodeType)")
public void isNodeTypeMethod() {
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.IfNodeOfType) && execution(* *(..))")
public void isIfNodeTypeAnnotated() {
}
@Pointcut("execution(* *(@com.inteligr8.alfresco.annotations.IfNodeOfType (*), ..))")
public void isIfNodeTypeParamAnnotated() {
}
@Around("isNodeTypeMethod() or execution(* *(@com.inteligr8.alfresco.annotations.IfNodeType (*), ..))")
public void isNodeType(ProceedingJoinPoint joinPoint) throws Throwable {
this.checkParameters(joinPoint, new ApplicableParameterCallback<IfNodeType>() {
@Around("isIfNodeTypeAnnotated() || isIfNodeTypeParamAnnotated()")
public Object isNodeType(ProceedingJoinPoint joinPoint) throws Throwable {
this.logger.trace("isNodeType({})", joinPoint);
return this.checkParameters(joinPoint, new ApplicableParameterCallback<IfNodeOfType>() {
@Override
public boolean checkParameter(ProceedingJoinPoint joinPoint, Method method, IfNodeType annotation, int parameterIndex) {
public boolean checkParameter(ProceedingJoinPoint joinPoint, Method method, IfNodeOfType annotation, int parameterIndex) {
Object arg = joinPoint.getArgs()[parameterIndex];
Collection<NodeRef> nodeRefs = extractNodeRefs(arg);
if (nodeRefs == null)
return true;
QNameBasedCallback<IfNodeType> callback = new QNameBasedCallback<IfNodeType>() {
QNameBasedCallback<IfNodeOfType> callback = new QNameBasedCallback<IfNodeOfType>() {
@Override
public boolean isConstrained() {
return joinPoint.getThis() instanceof NodeTypeConstrainable;
return joinPoint.getTarget() instanceof NodeTypeConstrainable;
}
@Override
@ -80,12 +84,12 @@ public class NodeTypeAspect extends QNameBasedAspect<IfNodeType> {
@Override
public String getBeanName() {
return ((NodeTypeConstrainable) joinPoint.getThis()).getBeanName();
return ((NodeTypeConstrainable) joinPoint.getTarget()).getBeanName();
}
@Override
public Collection<? extends QNamePattern> constrainedQNames() {
return ((NodeTypeConstrainable) joinPoint.getThis()).constrainedNodeTypes();
return ((NodeTypeConstrainable) joinPoint.getTarget()).constrainedNodeTypes();
}
@Override
@ -103,7 +107,7 @@ public class NodeTypeAspect extends QNameBasedAspect<IfNodeType> {
}
@Override
public String getAnnotationValue(IfNodeType annotation) {
public String getAnnotationValue(IfNodeOfType annotation) {
return annotation.type();
}
};
@ -134,8 +138,19 @@ public class NodeTypeAspect extends QNameBasedAspect<IfNodeType> {
return Arrays.asList(assocRef.getSourceRef(), assocRef.getTargetRef());
} else if (obj instanceof Collection<?>) {
Set<NodeRef> nodeRefs = new LinkedHashSet<>();
for (Object o : ((Collection<?>) obj))
nodeRefs.addAll(this.extractNodeRefs(o));
for (Object o : ((Collection<?>) obj)) {
Collection<NodeRef> subNodeRefs = this.extractNodeRefs(o);
if (subNodeRefs != null)
nodeRefs.addAll(subNodeRefs);
}
return nodeRefs;
} else if (obj instanceof Object[]) {
Set<NodeRef> nodeRefs = new LinkedHashSet<>();
for (Object o : ((Object[]) obj)) {
Collection<NodeRef> subNodeRefs = this.extractNodeRefs(o);
if (subNodeRefs != null)
nodeRefs.addAll(subNodeRefs);
}
return nodeRefs;
} else {
return null;

View File

@ -0,0 +1,42 @@
package com.inteligr8.alfresco.annotations.aspect;
import java.lang.reflect.Method;
import javax.annotation.Nonnull;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
@Aspect
@Order(Ordered.HIGHEST_PRECEDENCE + 64)
public class NotNullAspect {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Pointcut("execution(* *(@javax.annotation.Nonnull (*), ..))")
public void isNonnullAnnotated() {
}
@Around("isNonnullAnnotated()")
public Object isNotNull(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSig = (MethodSignature) joinPoint.getSignature();
Method method = methodSig.getMethod();
for (int p = 0; p < method.getParameterCount(); p++) {
if (joinPoint.getArgs()[p] == null && method.getParameters()[p].isAnnotationPresent(Nonnull.class)) {
this.logger.debug("A @Nonnull parameter is `null`; skipping method: {}", method);
return null;
}
}
return joinPoint.proceed();
}
}

View File

@ -18,12 +18,10 @@ import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.inteligr8.alfresco.annotations.IfNodeExists;
@Aspect
@Component
public class OperableNodeAspect extends MethodOrParameterAspect<IfNodeExists> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@ -36,19 +34,25 @@ public class OperableNodeAspect extends MethodOrParameterAspect<IfNodeExists> {
return IfNodeExists.class;
}
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.IfNodeExists)")
public void isNodeOperableMethod() {
@Pointcut("@annotation(com.inteligr8.alfresco.annotations.IfNodeExists) && execution(* *(..))")
public void isIfNodeExistsAnnotated() {
}
@Pointcut("execution(* *(@com.inteligr8.alfresco.annotations.IfNodeExists (*), ..))")
public void isIfNodeExistsParamAnnotated() {
}
@Around("isNodeOperableMethod() or execution(* *(@com.inteligr8.alfresco.annotations.IfNodeExists (*), ..))")
public void isNodeOperable(ProceedingJoinPoint joinPoint) throws Throwable {
this.checkParameters(joinPoint, new ApplicableParameterCallback<IfNodeExists>() {
@Around("isIfNodeExistsAnnotated() || isIfNodeExistsParamAnnotated()")
public Object isNodeOperable(ProceedingJoinPoint joinPoint) throws Throwable {
return this.checkParameters(joinPoint, new ApplicableParameterCallback<IfNodeExists>() {
@Override
public boolean checkParameter(ProceedingJoinPoint joinPoint, Method method, IfNodeExists annotation, int parameterIndex) {
Object arg = joinPoint.getArgs()[parameterIndex];
Collection<NodeRef> nodeRefs = extractNodeRefs(arg);
if (nodeRefs == null)
return true;
logger.trace("Checking if nodes are operable: {}", nodeRefs);
for (NodeRef nodeRef : nodeRefs) {
if (!isOperableNode(nodeRef)) {
@ -74,8 +78,19 @@ public class OperableNodeAspect extends MethodOrParameterAspect<IfNodeExists> {
return Arrays.asList(assocRef.getSourceRef(), assocRef.getTargetRef());
} else if (obj instanceof Collection<?>) {
Set<NodeRef> nodeRefs = new LinkedHashSet<>();
for (Object o : ((Collection<?>) obj))
nodeRefs.addAll(this.extractNodeRefs(o));
for (Object o : ((Collection<?>) obj)) {
Collection<NodeRef> subNodeRefs = this.extractNodeRefs(o);
if (subNodeRefs != null)
nodeRefs.addAll(subNodeRefs);
}
return nodeRefs;
} else if (obj instanceof Object[]) {
Set<NodeRef> nodeRefs = new LinkedHashSet<>();
for (Object o : ((Object[]) obj)) {
Collection<NodeRef> subNodeRefs = this.extractNodeRefs(o);
if (subNodeRefs != null)
nodeRefs.addAll(subNodeRefs);
}
return nodeRefs;
} else {
return null;

View File

@ -61,7 +61,7 @@ public abstract class QNameBasedAspect<T extends Annotation> extends MethodOrPar
} else if (callback.getAnnotationValue(annotation).length() > 0) {
Set<QName> qnames = this.qnameCache.get(joinPoint.getThis().getClass().getName());
if (qnames != null) {
this.logger.trace("Using cache of qnames for bean: {}", callback.getBeanName());
this.logger.trace("Using cache of qnames for bean: {}", joinPoint.getThis().getClass());
return qnames;
}

View File

@ -1,40 +1,52 @@
package com.inteligr8.alfresco.annotations.aspect;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.transaction.TransactionService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.inteligr8.alfresco.annotations.TransactionalRetryable;
@Aspect
@Order(Ordered.LOWEST_PRECEDENCE - Short.MAX_VALUE)
@Component
//@Component
public class RetryingTransactionAspect {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
public void transactionalMethod() {
private final Set<String> warned = new HashSet<>();
@Autowired
private TransactionService txService;
@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional) && execution(* *(..))")
public void isTransactionalAnnotated() {
}
@Around("transactionalMethod()")
public void retryingTransactional(ProceedingJoinPoint joinPoint) throws Throwable {
this.logger.trace("tx: {}", AlfrescoTransactionSupport.getTransactionId());
@Pointcut("@annotation(org.springframework.transaction.annotation.TransactionalRetryable) && execution(* *(..))")
public void isTransactionalRetryableAnnotated() {
}
@Around("isTransactionalAnnotated()")
public Object retryingTransactional(ProceedingJoinPoint joinPoint) throws Throwable {
this.logger.trace("retryingTransactional({})", joinPoint);
Method method = this.getMethod(joinPoint);
Transactional txl = method.getAnnotation(Transactional.class);
@ -43,10 +55,18 @@ public class RetryingTransactionAspect {
TransactionalRetryable txtry = method.getAnnotation(TransactionalRetryable.class);
this.logger.debug("Changing TX context: {} => [ro: {}, new: {}]", AlfrescoTransactionSupport.getTransactionReadState(), txl.readOnly(), txl.propagation());
this.execute(joinPoint, txl, txtry);
return this.execute(joinPoint, txl, txtry);
} else {
return joinPoint.proceed();
}
}
@Before("isTransactionalRetryableAnnotated() && !isTransactionalAnnotated()")
public void warn(ProceedingJoinPoint joinPoint) throws Throwable {
if (this.warned.add(joinPoint.toLongString()))
this.logger.warn("A @TransactionalRetryable annotation was found without a @Transactional annotation; it will be ignored: {}", joinPoint);
}
private Method getMethod(ProceedingJoinPoint joinPoint) {
if (!(joinPoint.getSignature() instanceof MethodSignature))
throw new IllegalStateException("The @Transactional or @TransactionalRetryable annotations must be on methods");
@ -56,16 +76,18 @@ public class RetryingTransactionAspect {
}
private boolean isReadStateChange(Transactional txl) {
switch (txl.propagation()) {
case NEVER:
case NOT_SUPPORTED:
case SUPPORTS:
// do not force because of a read-state change
return false;
default:
}
switch (AlfrescoTransactionSupport.getTransactionReadState()) {
case TXN_NONE:
switch (txl.propagation()) {
case NEVER:
case NOT_SUPPORTED:
case SUPPORTS:
return false;
default:
return true;
}
return true;
case TXN_READ_ONLY:
return !txl.readOnly();
case TXN_READ_WRITE:
@ -88,10 +110,15 @@ public class RetryingTransactionAspect {
switch (AlfrescoTransactionSupport.getTransactionReadState()) {
case TXN_NONE:
throw new IllegalTransactionStateException("A transaction does not exist where one is mandatory");
default:
return false;
case TXN_READ_ONLY:
if (!txl.readOnly())
throw new IllegalTransactionStateException("A read-only transaction exists where a read/write one is mandatory");
case TXN_READ_WRITE:
if (txl.readOnly())
throw new IllegalTransactionStateException("A read/write transaction exists where a read-only one is mandatory");
}
case SUPPORTS:
//case NOT_SUPPORTED: not supported; we would have to create another thread to simulate
return false;
case REQUIRED:
switch (AlfrescoTransactionSupport.getTransactionReadState()) {
@ -103,15 +130,15 @@ public class RetryingTransactionAspect {
case REQUIRES_NEW:
return true;
default:
throw new UnsupportedOperationException();
throw new IllegalTransactionStateException("The transactional propagation is not supported: " + txl.propagation());
}
}
private void execute(final ProceedingJoinPoint joinPoint, Transactional txl, TransactionalRetryable txtry) throws Throwable {
private Object execute(final ProceedingJoinPoint joinPoint, Transactional txl, TransactionalRetryable txtry) throws Throwable {
RetryingTransactionCallback<Object> rtcallback = new RetryingTransactionCallback<Object>() {
@Override
public Object execute() throws Throwable {
logger.trace("tx: {}", AlfrescoTransactionSupport.getTransactionId());
logger.debug("entering tx: {}", AlfrescoTransactionSupport.getTransactionId());
try {
return joinPoint.proceed();
@ -119,24 +146,30 @@ public class RetryingTransactionAspect {
throw e;
} catch (Throwable t) {
throw new RuntimeException("This should never happen", t);
} finally {
logger.trace("leaving tx: {}", AlfrescoTransactionSupport.getTransactionId());
}
}
};
RetryingTransactionHelper rthelper = new RetryingTransactionHelper();
if (txtry.maxRetries() > 0)
rthelper.setMaxRetries(txtry.maxRetries());
if (txtry.minRetryWaitInMillis() > 0)
rthelper.setMinRetryWaitMs(txtry.minRetryWaitInMillis());
if (txtry.maxRetryWaitInMillis() > 0)
rthelper.setMaxRetryWaitMs(txtry.maxRetryWaitInMillis());
if (txtry.incRetryWaitInMillis() > 0)
rthelper.setRetryWaitIncrementMs(txtry.incRetryWaitInMillis());
rthelper.setTransactionService(this.txService);
if (txtry != null) {
if (txtry.maxRetries() > 0)
rthelper.setMaxRetries(txtry.maxRetries());
if (txtry.minRetryWaitInMillis() > 0)
rthelper.setMinRetryWaitMs(txtry.minRetryWaitInMillis());
if (txtry.maxRetryWaitInMillis() > 0)
rthelper.setMaxRetryWaitMs(txtry.maxRetryWaitInMillis());
if (txtry.incRetryWaitInMillis() > 0)
rthelper.setRetryWaitIncrementMs(txtry.incRetryWaitInMillis());
}
if (txl.timeout() > 0)
rthelper.setMaxExecutionMs(txl.timeout() * 1000L);
try {
rthelper.doInTransaction(rtcallback, txl.readOnly(), txl.propagation().equals(Propagation.REQUIRES_NEW));
this.logger.trace("source tx: {}", AlfrescoTransactionSupport.getTransactionId());
return rthelper.doInTransaction(rtcallback, txl.readOnly(), true);
} catch (RuntimeException re) {
// attempt to unwrap the exception
if (re.getMessage() == null) {
@ -148,6 +181,8 @@ public class RetryingTransactionAspect {
} else {
throw re;
}
} finally {
this.logger.debug("returned to tx: {}", AlfrescoTransactionSupport.getTransactionId());
}
}

View File

@ -33,6 +33,7 @@ import javax.transaction.TransactionManager;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.search.transaction.SimpleTransactionManager;
import org.alfresco.repo.version.common.VersionImpl;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
@ -126,9 +127,6 @@ public class MqAsyncService extends AbstractLifecycleBean implements AsyncServic
@Autowired
protected TransactionService txService;
@Autowired
protected TransactionManager txManager;
private XaPooledConnectionFactory factory;
private SimpleCache<Pair<Class<?>, String>, Method> methodCache;
@ -150,7 +148,7 @@ public class MqAsyncService extends AbstractLifecycleBean implements AsyncServic
XaPooledConnectionFactory pool = new XaPooledConnectionFactory();
pool.setConnectionFactory(factory);
pool.setMaxConnections(this.maxConnections);
pool.setTransactionManager(this.txManager);
pool.setTransactionManager(SimpleTransactionManager.getInstance());
pool.start();
this.factory = pool;
@ -174,7 +172,8 @@ public class MqAsyncService extends AbstractLifecycleBean implements AsyncServic
@Override
protected void onShutdown(ApplicationEvent event) {
this.factory.stop();
if (this.factory != null)
this.factory.stop();
}
@Override

View File

@ -0,0 +1,14 @@
<aspectj>
<aspects>
<aspect name="com.inteligr8.alfresco.annotations.aspect.NotNullAspect" />
<aspect name="com.inteligr8.alfresco.annotations.aspect.AsyncAspect" />
<aspect name="com.inteligr8.alfresco.annotations.aspect.AuthorizedAspect" />
<aspect name="com.inteligr8.alfresco.annotations.aspect.RetryingTransactionAspect" />
<aspect name="com.inteligr8.alfresco.annotations.aspect.OperableNodeAspect" />
<aspect name="com.inteligr8.alfresco.annotations.aspect.NodeTypeAspect" />
<aspect name="com.inteligr8.alfresco.annotations.aspect.NodeAspectAspect" />
<aspect name="com.inteligr8.alfresco.annotations.aspect.ChildIsPrimaryAspect" />
</aspects>
</aspectj>

View File

@ -1,4 +1,6 @@
inteligr8.annotations.aspectj.scanPackages=com.inteligr8.alfresco.annotations
inteligr8.async.mq.enabled=false
inteligr8.async.mq.url=${messaging.broker.url}
inteligr8.async.mq.username=${messaging.broker.username}
@ -7,4 +9,5 @@ inteligr8.async.mq.queuePrefix=inteligr8.acs.
inteligr8.async.mq.clientId=acs
inteligr8.async.mq.pool.max=5
inteligr8.cache.nodeTypeConstrainable.maxBeans=32
inteligr8.cache.nodeTypeConstrainable.maxBeans=16
inteligr8.cache.nodeAspectConstrainable.maxBeans=16

View File

@ -4,7 +4,9 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Enable Spring annotation scanning for classes in package -->

View File

@ -0,0 +1,52 @@
package com.inteligr8.alfresco.annotations;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class AuthorizableTest extends AbstractLifecycleBean implements Authorizable {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
Assert.isNull(AuthenticationUtil.getRunAsUser(), "An unexpected authorization: " + AuthenticationUtil.getRunAsUser());
this.tryAuthorized();
this.tryAuthorizedAsSystem();
this.tryDoubleAuthorized();
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@Override
public String authorizeAsUser() {
return "admin";
}
@Authorized
private void tryAuthorized() {
Assert.hasText(AuthenticationUtil.getRunAsUser(), "An expected authorization");
Assert.isTrue("admin".equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: admin != " + AuthenticationUtil.getRunAsUser());
}
@AuthorizedAsSystem
private void tryAuthorizedAsSystem() {
Assert.hasText(AuthenticationUtil.getRunAsUser(), "An expected authorization");
Assert.isTrue(AuthenticationUtil.getSystemUserName().equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: " + AuthenticationUtil.getSystemUserName() + " != " + AuthenticationUtil.getRunAsUser());
}
@Authorized
private void tryDoubleAuthorized() {
this.tryAuthorizedAsSystem();
Assert.isTrue("admin".equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: admin != " + AuthenticationUtil.getRunAsUser());
}
}

View File

@ -0,0 +1,54 @@
package com.inteligr8.alfresco.annotations;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class AuthorizedTest extends AbstractLifecycleBean {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
Assert.isNull(AuthenticationUtil.getRunAsUser(), "An unexpected authorization: " + AuthenticationUtil.getRunAsUser());
this.tryAuthorized();
this.tryAdminAuthorized();
this.tryAuthorizedAsSystem();
this.tryDoubleAuthorized();
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@Authorized
private void tryAuthorized() {
Assert.hasText(AuthenticationUtil.getRunAsUser(), "An expected authorization");
Assert.isTrue(AuthenticationUtil.getSystemUserName().equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: " + AuthenticationUtil.getSystemUserName() + " != " + AuthenticationUtil.getRunAsUser());
}
@Authorized("admin")
private void tryAdminAuthorized() {
Assert.hasText(AuthenticationUtil.getRunAsUser(), "An expected authorization");
Assert.isTrue("admin".equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: admin != " + AuthenticationUtil.getRunAsUser());
}
@AuthorizedAsSystem
private void tryAuthorizedAsSystem() {
Assert.hasText(AuthenticationUtil.getRunAsUser(), "An expected authorization");
Assert.isTrue(AuthenticationUtil.getSystemUserName().equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: " + AuthenticationUtil.getSystemUserName() + " != " + AuthenticationUtil.getRunAsUser());
}
@Authorized("admin")
private void tryDoubleAuthorized() {
this.tryAuthorizedAsSystem();
Assert.isTrue("admin".equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: admin != " + AuthenticationUtil.getRunAsUser());
}
}

View File

@ -0,0 +1,114 @@
package com.inteligr8.alfresco.annotations;
import java.util.UUID;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class IfChildAssocIsPrimaryTest extends AbstractLifecycleBean {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final MutableBoolean executed = new MutableBoolean();
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
NodeRef mockNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, UUID.randomUUID().toString());
QName mockName = QName.createQNameWithValidLocalName(NamespaceService.ALFRESCO_URI, "test");
ChildAssociationRef mockPrimaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, mockNodeRef, mockName, mockNodeRef, true, 0);
ChildAssociationRef mockSecondaryAssoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, mockNodeRef, mockName, mockNodeRef, false, 0);
this.executed.setFalse();
this.tryMethodNoParam();
if (this.executed.isFalse())
throw new IllegalArgumentException();
this.executed.setFalse();
this.tryMethodNoMatchingParam("test");
if (this.executed.isFalse())
throw new IllegalArgumentException();
this.tryMethodWithOnePrimaryParam(mockPrimaryAssoc);
this.tryMethodWithOneNullParam(null);
this.tryMethodWithOneNonPrimaryParam(mockSecondaryAssoc);
this.tryMethodWithTwoPrimaryParams(mockPrimaryAssoc, "test", mockPrimaryAssoc);
this.tryMethodWithTwoNullPrimaryParams(null, "test", mockPrimaryAssoc);
this.tryMethodWithTwoNullPrimaryParams(mockPrimaryAssoc, "test", null);
this.tryMethodWithTwoMixedParams(mockPrimaryAssoc, "test", mockSecondaryAssoc);
this.tryMethodWithTwoMixedParams(mockSecondaryAssoc, "test", mockSecondaryAssoc);
this.tryParamWithPrimaryParam(mockPrimaryAssoc, mockPrimaryAssoc);
this.tryParamWithPrimaryParam(mockPrimaryAssoc, mockSecondaryAssoc);
this.tryParamWithPrimaryParam(mockSecondaryAssoc, mockPrimaryAssoc);
this.tryParamWithNullParam(null, mockPrimaryAssoc);
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@IfChildAssociationIsPrimary
private void tryMethodNoParam() {
this.executed.setTrue();
}
@IfChildAssociationIsPrimary
private void tryMethodNoMatchingParam(String test) {
this.executed.setTrue();
}
@IfChildAssociationIsPrimary
private void tryMethodWithOnePrimaryParam(ChildAssociationRef childAssocRef) {
Assert.isTrue(childAssocRef.isPrimary(), "Unexpected non-primary child association");
}
@IfChildAssociationIsPrimary
private void tryMethodWithOneNullParam(ChildAssociationRef childAssocRef) {
Assert.isTrue(childAssocRef == null, "Unexpected child association");
}
@IfChildAssociationIsPrimary
private void tryMethodWithOneNonPrimaryParam(ChildAssociationRef childAssocRef) {
throw new UnsupportedOperationException();
}
@IfChildAssociationIsPrimary
private void tryMethodWithTwoPrimaryParams(ChildAssociationRef childAssocRef1, String test, ChildAssociationRef childAssocRef2) {
Assert.isTrue(childAssocRef1.isPrimary() && childAssocRef2.isPrimary(), "Unexpected non-primary child association");
}
@IfChildAssociationIsPrimary
private void tryMethodWithTwoNullPrimaryParams(ChildAssociationRef childAssocRef1, String test, ChildAssociationRef childAssocRef2) {
Assert.isTrue(childAssocRef1 == null || childAssocRef1.isPrimary(), "Unexpected non-primary child association");
Assert.isTrue(childAssocRef2 == null || childAssocRef2.isPrimary(), "Unexpected non-primary child association");
}
@IfChildAssociationIsPrimary
private void tryMethodWithTwoMixedParams(ChildAssociationRef childAssocRef1, String test, ChildAssociationRef childAssocRef2) {
throw new UnsupportedOperationException();
}
private void tryParamWithPrimaryParam(@IfChildAssociationIsPrimary ChildAssociationRef childAssocRef1, ChildAssociationRef childAssocRef2) {
Assert.isTrue(childAssocRef1.isPrimary(), "Unexpected non-primary child association");
}
private void tryParamWithNullParam(@IfChildAssociationIsPrimary ChildAssociationRef childAssocRef1, ChildAssociationRef childAssocRef2) {
Assert.isTrue(childAssocRef1 == null, "Unexpected child association");
}
}

View File

@ -0,0 +1,111 @@
package com.inteligr8.alfresco.annotations;
import java.util.Arrays;
import java.util.Collection;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.nodelocator.CompanyHomeNodeLocator;
import org.alfresco.repo.nodelocator.NodeLocatorService;
import org.alfresco.repo.nodelocator.SharedHomeNodeLocator;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QNamePattern;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class IfNodeAspectConstrainableTest extends AbstractLifecycleBean implements NodeAspectConstrainable {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private NamespaceService namespaceService;
@Autowired
private NodeService nodeService;
@Autowired
private NodeLocatorService nodeLocatorService;
private final MutableBoolean executed = new MutableBoolean();
private String beanName;
@AuthorizedAsSystem
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
NodeRef rootNodeRef = this.nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
NodeRef chNodeRef = this.nodeLocatorService.getNode(CompanyHomeNodeLocator.NAME, null, null);
NodeRef sharedNodeRef = this.nodeLocatorService.getNode(SharedHomeNodeLocator.NAME, null, null);
this.tryNodes(chNodeRef, sharedNodeRef);
this.tryNode(sharedNodeRef);
this.executed.setFalse();
this.tryNull(null);
if (this.executed.isFalse())
throw new IllegalStateException();
this.tryNotNode(rootNodeRef);
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@Override
public String getBeanName() {
return this.beanName;
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
@Override
public NamespaceService getNamespaceService() {
return this.namespaceService;
}
@Override
public Collection<? extends QNamePattern> constrainedAspects() {
return Arrays.asList(ContentModel.ASPECT_AUDITABLE);
}
@IfNodeHasAspect
private void tryNodes(NodeRef... nodeRefs) {
for (NodeRef nodeRef : nodeRefs) {
Assert.isTrue(this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_AUDITABLE), "Missing 'cm:auditable' aspect: " + nodeRef);
}
}
private void tryNode(@IfNodeHasAspect NodeRef nodeRef) {
Assert.isTrue(this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_AUDITABLE), "Missing 'cm:auditable' aspect: " + nodeRef);
}
@IfNodeHasAspect
private void tryNotNodes(NodeRef... nodeRefs) {
throw new UnsupportedOperationException();
}
@IfNodeHasAspect
private void tryNull(NodeRef nodeRef) {
this.executed.setTrue();
}
private void tryNotNode(@IfNodeHasAspect NodeRef nodeRef) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,87 @@
package com.inteligr8.alfresco.annotations;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.nodelocator.NodeLocatorService;
import org.alfresco.repo.nodelocator.SharedHomeNodeLocator;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class IfNodeAspectTest extends AbstractLifecycleBean {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private NodeService nodeService;
@Autowired
private NodeLocatorService nodeLocatorService;
private final MutableBoolean executed = new MutableBoolean();
@AuthorizedAsSystem
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
NodeRef rootNodeRef = this.nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
NodeRef sharedNodeRef = this.nodeLocatorService.getNode(SharedHomeNodeLocator.NAME, null, null);
ChildAssociationRef sharedParentRef = this.nodeService.getPrimaryParent(sharedNodeRef);
this.tryAuditables(sharedNodeRef);
this.tryAuditable(sharedNodeRef);
this.tryAuditable(sharedParentRef);
this.executed.setFalse();
this.tryNull(null);
if (this.executed.isFalse())
throw new IllegalStateException();
this.tryNotAuditable(rootNodeRef);
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@IfNodeHasAspect(aspect = "cm:auditable")
private void tryAuditables(NodeRef... nodeRefs) {
for (NodeRef nodeRef : nodeRefs) {
Assert.isTrue(this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_AUDITABLE), "Missing 'cm:auditable' aspect: " + nodeRef);
}
}
private void tryAuditable(@IfNodeHasAspect(aspect = "cm:auditable") NodeRef nodeRef) {
Assert.isTrue(this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_AUDITABLE), "Missing 'cm:auditable' aspect: " + nodeRef);
}
private void tryAuditable(@IfNodeHasAspect(aspect = "cm:auditable") ChildAssociationRef childAssocRef) {
NodeRef nodeRef = childAssocRef.getChildRef();
Assert.isTrue(this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_AUDITABLE), "Missing 'cm:auditable' aspect: " + nodeRef);
}
@IfNodeHasAspect(aspect = "cm:auditable")
private void tryNotAuditables(NodeRef... nodeRefs) {
throw new UnsupportedOperationException();
}
@IfNodeHasAspect(aspect = "cm:auditable")
private void tryNull(NodeRef nodeRef) {
this.executed.setTrue();
}
private void tryNotAuditable(@IfNodeOfType(type = "cm:auditable") NodeRef nodeRef) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,82 @@
package com.inteligr8.alfresco.annotations;
import java.util.UUID;
import org.alfresco.repo.nodelocator.CompanyHomeNodeLocator;
import org.alfresco.repo.nodelocator.NodeLocatorService;
import org.alfresco.repo.nodelocator.SharedHomeNodeLocator;
import org.alfresco.repo.nodelocator.SitesHomeNodeLocator;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class IfNodeExistsTest extends AbstractLifecycleBean {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private NodeService nodeService;
@Autowired
private NodeLocatorService nodeLocatorService;
private final MutableBoolean executed = new MutableBoolean();
@AuthorizedAsSystem
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
NodeRef mockNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, UUID.randomUUID().toString());
NodeRef rootNodeRef = this.nodeLocatorService.getNode(CompanyHomeNodeLocator.NAME, null, null);
NodeRef sharedNodeRef = this.nodeLocatorService.getNode(SharedHomeNodeLocator.NAME, null, null);
NodeRef sitesNodeRef = this.nodeLocatorService.getNode(SitesHomeNodeLocator.NAME, null, null);
this.tryNodesExist(rootNodeRef, sharedNodeRef, sitesNodeRef);
this.tryNodeExists(sharedNodeRef);
this.executed.setFalse();
this.tryNull(null);
if (this.executed.isFalse())
throw new IllegalStateException();
this.tryNodesNotExist(mockNodeRef);
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@IfNodeExists
private void tryNodesExist(NodeRef... nodeRefs) {
for (NodeRef nodeRef : nodeRefs) {
Assert.isTrue(nodeRef != null, "Expected node reference: " + nodeRef);
Assert.isTrue(this.nodeService.exists(nodeRef) && !this.nodeService.getNodeStatus(nodeRef).isDeleted(), "Expected node: " + nodeRef);
}
}
private void tryNodeExists(@IfNodeExists NodeRef nodeRef) {
Assert.isTrue(nodeRef != null, "Expected node reference: " + nodeRef);
Assert.isTrue(this.nodeService.exists(nodeRef) && !this.nodeService.getNodeStatus(nodeRef).isDeleted(), "Expected node: " + nodeRef);
}
@IfNodeExists
private void tryNull(NodeRef nodeRef) {
this.executed.setTrue();
}
@IfNodeExists
private void tryNodesNotExist(NodeRef... nodeRefs) {
throw new IllegalStateException();
}
}

View File

@ -0,0 +1,118 @@
package com.inteligr8.alfresco.annotations;
import java.util.Arrays;
import java.util.Collection;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.nodelocator.CompanyHomeNodeLocator;
import org.alfresco.repo.nodelocator.NodeLocatorService;
import org.alfresco.repo.nodelocator.SharedHomeNodeLocator;
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.cmr.repository.StoreRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNamePattern;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class IfNodeTypeConstrainableTest extends AbstractLifecycleBean implements NodeTypeConstrainable {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private DictionaryService dictionaryService;
@Autowired
private NamespaceService namespaceService;
@Autowired
private NodeService nodeService;
@Autowired
private NodeLocatorService nodeLocatorService;
private final MutableBoolean executed = new MutableBoolean();
private String beanName;
@AuthorizedAsSystem
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
NodeRef rootNodeRef = this.nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
NodeRef chNodeRef = this.nodeLocatorService.getNode(CompanyHomeNodeLocator.NAME, null, null);
NodeRef sharedNodeRef = this.nodeLocatorService.getNode(SharedHomeNodeLocator.NAME, null, null);
this.tryNodes(chNodeRef, sharedNodeRef);
this.tryNode(sharedNodeRef);
this.executed.setFalse();
this.tryNull(null);
if (this.executed.isFalse())
throw new IllegalStateException();
this.tryNotNode(rootNodeRef);
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@Override
public String getBeanName() {
return this.beanName;
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
@Override
public NamespaceService getNamespaceService() {
return this.namespaceService;
}
@Override
public Collection<? extends QNamePattern> constrainedNodeTypes() {
return Arrays.asList(ContentModel.TYPE_FOLDER);
}
@IfNodeOfType
private void tryNodes(NodeRef... nodeRefs) {
for (NodeRef nodeRef : nodeRefs) {
QName nodeType = this.nodeService.getType(nodeRef);
Assert.isTrue(this.dictionaryService.isSubClass(nodeType, ContentModel.TYPE_FOLDER), "Unexpected node type: " + nodeType);
}
}
private void tryNode(@IfNodeOfType NodeRef nodeRef) {
QName nodeType = this.nodeService.getType(nodeRef);
Assert.isTrue(this.dictionaryService.isSubClass(nodeType, ContentModel.TYPE_FOLDER), "Unexpected node type: " + nodeType);
}
@IfNodeOfType
private void tryNotNodes(NodeRef... nodeRefs) {
throw new UnsupportedOperationException();
}
@IfNodeOfType
private void tryNull(NodeRef nodeRef) {
this.executed.setTrue();
}
private void tryNotNode(@IfNodeOfType NodeRef nodeRef) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,96 @@
package com.inteligr8.alfresco.annotations;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.nodelocator.CompanyHomeNodeLocator;
import org.alfresco.repo.nodelocator.NodeLocatorService;
import org.alfresco.repo.nodelocator.SharedHomeNodeLocator;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class IfNodeTypeTest extends AbstractLifecycleBean {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private DictionaryService dictionaryService;
@Autowired
private NodeService nodeService;
@Autowired
private NodeLocatorService nodeLocatorService;
private final MutableBoolean executed = new MutableBoolean();
@AuthorizedAsSystem
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
NodeRef rootNodeRef = this.nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
NodeRef chNodeRef = this.nodeLocatorService.getNode(CompanyHomeNodeLocator.NAME, null, null);
NodeRef sharedNodeRef = this.nodeLocatorService.getNode(SharedHomeNodeLocator.NAME, null, null);
ChildAssociationRef sharedParentRef = this.nodeService.getPrimaryParent(sharedNodeRef);
this.tryFolders(chNodeRef, sharedNodeRef);
this.tryFolder(sharedNodeRef);
this.tryFolder(sharedParentRef);
this.executed.setFalse();
this.tryNull(null);
if (this.executed.isFalse())
throw new IllegalStateException();
this.tryNotFolder(rootNodeRef);
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@IfNodeOfType(type = "cm:folder")
private void tryFolders(NodeRef... nodeRefs) {
for (NodeRef nodeRef : nodeRefs) {
QName nodeType = this.nodeService.getType(nodeRef);
Assert.isTrue(this.dictionaryService.isSubClass(nodeType, ContentModel.TYPE_FOLDER), "Unexpected node type: " + nodeType);
}
}
private void tryFolder(@IfNodeOfType(type = "cm:folder") NodeRef nodeRef) {
QName nodeType = this.nodeService.getType(nodeRef);
Assert.isTrue(this.dictionaryService.isSubClass(nodeType, ContentModel.TYPE_FOLDER), "Unexpected node type: " + nodeType);
}
private void tryFolder(@IfNodeOfType(type = "cm:folder") ChildAssociationRef childAssocRef) {
QName nodeType = this.nodeService.getType(childAssocRef.getChildRef());
Assert.isTrue(this.dictionaryService.isSubClass(nodeType, ContentModel.TYPE_FOLDER), "Unexpected node type: " + nodeType);
}
@IfNodeOfType(type = "cm:folder")
private void tryNotFolders(NodeRef... nodeRefs) {
throw new UnsupportedOperationException();
}
@IfNodeOfType
private void tryNull(NodeRef nodeRef) {
this.executed.setTrue();
}
private void tryNotFolder(@IfNodeOfType(type = "cm:folder") NodeRef nodeRef) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,43 @@
package com.inteligr8.alfresco.annotations;
import javax.annotation.Nonnull;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
@Component
public class IfNotNullTest extends AbstractLifecycleBean {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final MutableBoolean executed = new MutableBoolean();
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
this.executed.setFalse();
this.tryNotNull("test");
if (this.executed.isFalse())
throw new IllegalStateException();
this.tryNull(null);
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
private void tryNotNull(@Nonnull String str) {
executed.setTrue();
}
private void tryNull(@Nonnull String str) {
throw new IllegalStateException();
}
}

View File

@ -0,0 +1,46 @@
package com.inteligr8.alfresco.annotations;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class InvalidAuthorizableTest extends AbstractLifecycleBean implements Authorizable {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
Assert.isNull(AuthenticationUtil.getRunAsUser(), "An unexpected authorization: " + AuthenticationUtil.getRunAsUser());
this.tryAuthorized();
this.tryAuthorizedAsSystem();
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@Override
public String authorizeAsUser() {
return "!@#lkjw 1432";
}
@Authorized
private void tryAuthorized() {
Assert.hasText(AuthenticationUtil.getRunAsUser(), "An expected authorization");
Assert.isTrue(this.authorizeAsUser().equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: " + this.authorizeAsUser() + " != " + AuthenticationUtil.getRunAsUser());
}
@AuthorizedAsSystem
private void tryAuthorizedAsSystem() {
Assert.hasText(AuthenticationUtil.getRunAsUser(), "An expected authorization");
Assert.isTrue(AuthenticationUtil.getSystemUserName().equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: " + AuthenticationUtil.getSystemUserName() + " != " + AuthenticationUtil.getRunAsUser());
}
}

View File

@ -0,0 +1,46 @@
package com.inteligr8.alfresco.annotations;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class NoExistAuthorizableTest extends AbstractLifecycleBean implements Authorizable {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
Assert.isNull(AuthenticationUtil.getRunAsUser(), "An unexpected authorization: " + AuthenticationUtil.getRunAsUser());
this.tryAuthorized();
this.tryAuthorizedAsSystem();
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@Override
public String authorizeAsUser() {
return "doesnotexist";
}
@Authorized
private void tryAuthorized() {
Assert.hasText(AuthenticationUtil.getRunAsUser(), "An expected authorization");
Assert.isTrue(this.authorizeAsUser().equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: " + this.authorizeAsUser() + " != " + AuthenticationUtil.getRunAsUser());
}
@AuthorizedAsSystem
private void tryAuthorizedAsSystem() {
Assert.hasText(AuthenticationUtil.getRunAsUser(), "An expected authorization");
Assert.isTrue(AuthenticationUtil.getSystemUserName().equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: " + AuthenticationUtil.getSystemUserName() + " != " + AuthenticationUtil.getRunAsUser());
}
}

View File

@ -0,0 +1,51 @@
package com.inteligr8.alfresco.annotations;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@Component
public class NullAuthorizableTest extends AbstractLifecycleBean implements Authorizable {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
Assert.isNull(AuthenticationUtil.getRunAsUser(), "An unexpected authorization: " + AuthenticationUtil.getRunAsUser());
try {
this.tryAuthorized();
throw new IllegalStateException("An 'IllegalArgumentException' was expected");
} catch (IllegalArgumentException iae) {
// suppress
}
this.tryAuthorizedAsSystem();
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
@Override
public String authorizeAsUser() {
return null;
}
@Authorized
private void tryAuthorized() {
throw new UnsupportedOperationException();
}
@AuthorizedAsSystem
private void tryAuthorizedAsSystem() {
Assert.hasText(AuthenticationUtil.getRunAsUser(), "An expected authorization");
Assert.isTrue(AuthenticationUtil.getSystemUserName().equals(AuthenticationUtil.getRunAsUser()), "An unexpected authorization: " + AuthenticationUtil.getSystemUserName() + " != " + AuthenticationUtil.getRunAsUser());
}
}

View File

@ -0,0 +1,224 @@
package com.inteligr8.alfresco.annotations;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
@Component
public class TransactionalTest extends AbstractLifecycleBean {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void onBootstrap(ApplicationEvent event) {
this.logger.info("Running test: " + this.getClass());
Assert.isNull(AlfrescoTransactionSupport.getTransactionId(), "An unexpected transaction: " + AlfrescoTransactionSupport.getTransactionId());
this.tryOutsideTx();
this.tryWithinTx();
this.tryWithinReadonlyTx();
}
@Override
protected void onShutdown(ApplicationEvent event) {
}
private void tryOutsideTx() {
this.logger.info("Running outside TX test");
this.tryDefaultTransactional(null, false);
this.tryReadOnlyTransactional(null, false);
this.tryRetryOnlyTransactional(null);
this.trySupportsTransactional(null, false);
this.tryRequiresNewTransactional(null, false);
this.tryRequiredTransactional(null, false);
this.tryNeverTransactional(null);
try {
this.tryNoSupportsTransactional();
throw new IllegalStateException();
} catch (IllegalTransactionStateException uoe) {
// suppress
}
try {
this.tryMandatoryTransactional(null, false);
throw new IllegalStateException();
} catch (IllegalTransactionStateException itse) {
// suppress
}
}
@Transactional
private void tryWithinTx() {
this.logger.info("Running inside read/write TX test");
String txId = AlfrescoTransactionSupport.getTransactionId();
boolean readonly = false;
this.tryDefaultTransactional(txId, readonly);
this.tryReadOnlyTransactional(txId, readonly);
this.tryRetryOnlyTransactional(txId);
this.trySupportsTransactional(txId, readonly);
this.tryRequiresNewTransactional(txId, readonly);
this.tryRequiredTransactional(txId, readonly);
this.tryMandatoryTransactional(txId, readonly);
try {
this.tryNoSupportsTransactional();
throw new IllegalStateException();
} catch (IllegalTransactionStateException uoe) {
// suppress
}
try {
this.tryNeverTransactional(txId);
throw new IllegalStateException();
} catch (IllegalTransactionStateException itse) {
// suppress
}
}
@Transactional(readOnly = true)
private void tryWithinReadonlyTx() {
this.logger.info("Running inside read-only TX test");
String txId = AlfrescoTransactionSupport.getTransactionId();
boolean readonly = true;
this.tryDefaultTransactional(txId, readonly);
this.tryReadOnlyTransactional(txId, readonly);
this.tryRetryOnlyTransactional(txId);
this.trySupportsTransactional(txId, readonly);
this.tryRequiresNewTransactional(txId, readonly);
this.tryRequiredTransactional(txId, readonly);
try {
this.tryNoSupportsTransactional();
throw new IllegalStateException();
} catch (IllegalTransactionStateException uoe) {
// suppress
}
try {
this.tryMandatoryTransactional(txId, readonly);
throw new IllegalStateException();
} catch (IllegalTransactionStateException itse) {
// suppress
}
try {
this.tryNeverTransactional(txId);
throw new IllegalStateException();
} catch (IllegalTransactionStateException itse) {
// suppress
}
}
@Transactional
private void tryDefaultTransactional(String originTxId, boolean originReadonly) {
Assert.hasText(AlfrescoTransactionSupport.getTransactionId(), "Expected a transaction");
Assert.isTrue(TxnReadState.TXN_READ_WRITE.equals(AlfrescoTransactionSupport.getTransactionReadState()), "Expected a read/write transaction");
if (originTxId != null) {
if (originReadonly) {
// changed from readonly to read/write; need new TX
Assert.isTrue(!AlfrescoTransactionSupport.getTransactionId().equals(originTxId), "Expected a different transaction: " + AlfrescoTransactionSupport.getTransactionId() + " == " + originTxId);
} else {
// no changes; same TX
Assert.isTrue(AlfrescoTransactionSupport.getTransactionId().equals(originTxId), "Expected the same transaction: " + AlfrescoTransactionSupport.getTransactionId() + " != " + originTxId);
}
}
}
@Transactional(readOnly = true)
private void tryReadOnlyTransactional(String originTxId, boolean originReadonly) {
Assert.hasText(AlfrescoTransactionSupport.getTransactionId(), "Expected a transaction");
Assert.isTrue(TxnReadState.TXN_READ_ONLY.equals(AlfrescoTransactionSupport.getTransactionReadState()), "Expected a readonly transaction");
if (originTxId != null) {
if (originReadonly) {
// no changes; same TX
Assert.isTrue(AlfrescoTransactionSupport.getTransactionId().equals(originTxId), "Expected the same transaction: " + AlfrescoTransactionSupport.getTransactionId() + " != " + originTxId);
} else {
// changed from read/write to readonly; need new TX
Assert.isTrue(!AlfrescoTransactionSupport.getTransactionId().equals(originTxId), "Expected a different transaction: " + AlfrescoTransactionSupport.getTransactionId() + " == " + originTxId);
}
}
}
@Transactional(propagation = Propagation.SUPPORTS)
private void trySupportsTransactional(String originTxId, boolean originReadonly) {
if (originTxId == null) {
Assert.isNull(AlfrescoTransactionSupport.getTransactionId(), "Unexpected transaction");
} else {
Assert.hasText(AlfrescoTransactionSupport.getTransactionId(), "Expected a transaction");
Assert.isTrue(originReadonly == TxnReadState.TXN_READ_ONLY.equals(AlfrescoTransactionSupport.getTransactionReadState()), "Expected the same read-state transaction");
Assert.isTrue(AlfrescoTransactionSupport.getTransactionId().equals(originTxId), "Expected the same transaction: " + AlfrescoTransactionSupport.getTransactionId() + " != " + originTxId);
}
}
@Transactional(propagation = Propagation.REQUIRED)
private void tryRequiredTransactional(String originTxId, boolean originReadonly) {
Assert.hasText(AlfrescoTransactionSupport.getTransactionId(), "Expected a transaction");
Assert.isTrue(TxnReadState.TXN_READ_WRITE.equals(AlfrescoTransactionSupport.getTransactionReadState()), "Expected a read/write transaction");
if (originTxId != null) {
if (originReadonly) {
// changed from readonly to read/write; need new TX
Assert.isTrue(!AlfrescoTransactionSupport.getTransactionId().equals(originTxId), "Expected a different transaction: " + AlfrescoTransactionSupport.getTransactionId() + " == " + originTxId);
} else {
// no changes; same TX
Assert.isTrue(AlfrescoTransactionSupport.getTransactionId().equals(originTxId), "Expected the same transaction: " + AlfrescoTransactionSupport.getTransactionId() + " != " + originTxId);
}
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void tryRequiresNewTransactional(String originTxId, boolean originReadonly) {
Assert.hasText(AlfrescoTransactionSupport.getTransactionId(), "Expected a transaction");
Assert.isTrue(TxnReadState.TXN_READ_WRITE.equals(AlfrescoTransactionSupport.getTransactionReadState()), "Expected a read/write transaction");
if (originTxId != null)
Assert.isTrue(!AlfrescoTransactionSupport.getTransactionId().equals(originTxId), "Expected a different transaction: " + AlfrescoTransactionSupport.getTransactionId() + " == " + originTxId);
}
@Transactional(propagation = Propagation.MANDATORY)
private void tryMandatoryTransactional(String originTxId, boolean originReadonly) {
if (originTxId == null) {
throw new IllegalStateException();
} else {
Assert.hasText(AlfrescoTransactionSupport.getTransactionId(), "Expected a transaction");
Assert.isTrue(AlfrescoTransactionSupport.getTransactionId().equals(originTxId), "Expected the same transaction: " + AlfrescoTransactionSupport.getTransactionId() + " != " + originTxId);
Assert.isTrue(originReadonly == TxnReadState.TXN_READ_ONLY.equals(AlfrescoTransactionSupport.getTransactionReadState()), "Expected the same read-state transaction");
}
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
private void tryNoSupportsTransactional() {
throw new UnsupportedOperationException();
}
@Transactional(propagation = Propagation.NEVER)
private void tryNeverTransactional(String originTxId) {
if (originTxId == null) {
Assert.isNull(AlfrescoTransactionSupport.getTransactionId(), "Unexpected transaction");
} else {
throw new IllegalStateException();
}
}
@TransactionalRetryable
private void tryRetryOnlyTransactional(String originTxId) {
if (originTxId == null) {
Assert.isNull(AlfrescoTransactionSupport.getTransactionId(), "An unexpected transaction");
} else {
Assert.isTrue(AlfrescoTransactionSupport.getTransactionId().equals(originTxId), "Expected the same transaction: " + AlfrescoTransactionSupport.getTransactionId() + " != " + originTxId);
}
}
}

View File

@ -1,5 +1,5 @@
# Module debugging
log4j.logger.com.inteligr8.alfresco.foldering=trace
log4j.logger.com.inteligr8.alfresco.annotations=trace
# WebScript debugging
log4j.logger.org.springframework.extensions.webscripts.ScriptLogger=debug