001package org.tynamo.security;
002
003import java.lang.annotation.Annotation;
004import java.util.List;
005
006import org.apache.tapestry5.model.MutableComponentModel;
007import org.apache.tapestry5.plastic.MethodAdvice;
008import org.apache.tapestry5.plastic.MethodInvocation;
009import org.apache.tapestry5.plastic.PlasticClass;
010import org.apache.tapestry5.plastic.PlasticMethod;
011import org.apache.tapestry5.services.Environment;
012import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
013import org.apache.tapestry5.services.transform.TransformationSupport;
014import org.tynamo.shiro.extension.authz.aop.AopHelper;
015import org.tynamo.shiro.extension.authz.aop.DefaultSecurityInterceptor;
016import org.tynamo.shiro.extension.authz.aop.SecurityInterceptor;
017
018
019/**
020 * Transform components based on annotation.
021 * <p/>
022 * Support annotation on method.
023 * <p/>
024 * The following rules
025 * <ul>
026 * <li>Annotations on methods are <b>not</b> inherited.</li>
027 * <li>The annotations only in target class, unlike services </li>
028 * <ul>
029 * <p/>
030 *
031 * @see org.tynamo.security.services.SecurityModule#buildSecurityFilter(org.slf4j.Logger,
032 *      org.apache.tapestry5.services.ComponentEventLinkEncoder,
033 *      org.apache.tapestry5.services.ComponentClassResolver,
034 *      org.tynamo.security.services.ClassInterceptorsCache)
035 */
036public class ShiroAnnotationWorker implements ComponentClassTransformWorker2
037{
038        private final Environment environment;
039
040        public ShiroAnnotationWorker(Environment environment)
041        {
042                this.environment = environment;
043        }
044
045        @Override
046        public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel model)
047        {
048                for (Class<? extends Annotation> annotationClass : AopHelper.getAutorizationAnnotationClasses())
049                {
050                        List<PlasticMethod> methodsToTransform = plasticClass.getMethodsWithAnnotation(annotationClass);
051
052                        for (PlasticMethod tm : methodsToTransform) processTransform(tm, tm.getAnnotation(annotationClass));
053                }
054        }
055
056        private void processTransform(PlasticMethod tm, Annotation annotation)
057        {
058                final SecurityInterceptor interceptor = new DefaultSecurityInterceptor(annotation);
059
060                MethodAdvice advice = new MethodAdvice()
061                {
062                        public void advise(MethodInvocation invocation)
063                        {
064                                environment.push(MethodInvocation.class, invocation);
065                                try
066                                {
067                                        interceptor.intercept();
068                                }
069                                finally
070                                {
071                                        environment.pop(MethodInvocation.class);
072                                }
073                                invocation.proceed();
074                        }
075                };
076
077                tm.addAdvice(advice);
078
079        }
080
081}