001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.shiro.spring.security.interceptor;
020    
021    import org.aopalliance.intercept.MethodInterceptor;
022    import org.aopalliance.intercept.MethodInvocation;
023    import org.apache.shiro.aop.AnnotationResolver;
024    import org.apache.shiro.authz.aop.*;
025    import org.apache.shiro.spring.aop.SpringAnnotationResolver;
026    
027    import java.lang.reflect.Method;
028    import java.util.ArrayList;
029    import java.util.List;
030    
031    /**
032     * Allows Shiro Annotations to work in any <a href="http://aopalliance.sourceforge.net/">AOP Alliance</a>
033     * specific implementation environment (for example, Spring).
034     *
035     * @since 0.2
036     */
037    public class AopAllianceAnnotationsAuthorizingMethodInterceptor
038            extends AnnotationsAuthorizingMethodInterceptor implements MethodInterceptor {
039    
040        public AopAllianceAnnotationsAuthorizingMethodInterceptor() {
041            List<AuthorizingAnnotationMethodInterceptor> interceptors =
042                    new ArrayList<AuthorizingAnnotationMethodInterceptor>(5);
043    
044            //use a Spring-specific Annotation resolver - Spring's AnnotationUtils is nicer than the
045            //raw JDK resolution process.
046            AnnotationResolver resolver = new SpringAnnotationResolver();
047            //we can re-use the same resolver instance - it does not retain state:
048            interceptors.add(new RoleAnnotationMethodInterceptor(resolver));
049            interceptors.add(new PermissionAnnotationMethodInterceptor(resolver));
050            interceptors.add(new AuthenticatedAnnotationMethodInterceptor(resolver));
051            interceptors.add(new UserAnnotationMethodInterceptor(resolver));
052            interceptors.add(new GuestAnnotationMethodInterceptor(resolver));
053    
054            setMethodInterceptors(interceptors);
055        }
056        /**
057         * Creates a {@link MethodInvocation MethodInvocation} that wraps an
058         * {@link org.aopalliance.intercept.MethodInvocation org.aopalliance.intercept.MethodInvocation} instance,
059         * enabling Shiro Annotations in <a href="http://aopalliance.sourceforge.net/">AOP Alliance</a> environments
060         * (Spring, etc).
061         *
062         * @param implSpecificMethodInvocation AOP Alliance {@link org.aopalliance.intercept.MethodInvocation MethodInvocation}
063         * @return a Shiro {@link MethodInvocation MethodInvocation} instance that wraps the AOP Alliance instance.
064         */
065        protected org.apache.shiro.aop.MethodInvocation createMethodInvocation(Object implSpecificMethodInvocation) {
066            final MethodInvocation mi = (MethodInvocation) implSpecificMethodInvocation;
067    
068            return new org.apache.shiro.aop.MethodInvocation() {
069                public Method getMethod() {
070                    return mi.getMethod();
071                }
072    
073                public Object[] getArguments() {
074                    return mi.getArguments();
075                }
076    
077                public String toString() {
078                    return "Method invocation [" + mi.getMethod() + "]";
079                }
080    
081                public Object proceed() throws Throwable {
082                    return mi.proceed();
083                }
084    
085                public Object getThis() {
086                    return mi.getThis();
087                }
088            };
089        }
090    
091        /**
092         * Simply casts the method argument to an
093         * {@link org.aopalliance.intercept.MethodInvocation org.aopalliance.intercept.MethodInvocation} and then
094         * calls <code>methodInvocation.{@link org.aopalliance.intercept.MethodInvocation#proceed proceed}()</code>
095         *
096         * @param aopAllianceMethodInvocation the {@link org.aopalliance.intercept.MethodInvocation org.aopalliance.intercept.MethodInvocation}
097         * @return the {@link org.aopalliance.intercept.MethodInvocation#proceed() org.aopalliance.intercept.MethodInvocation.proceed()} method call result.
098         * @throws Throwable if the underlying AOP Alliance <code>proceed()</code> call throws a <code>Throwable</code>.
099         */
100        protected Object continueInvocation(Object aopAllianceMethodInvocation) throws Throwable {
101            MethodInvocation mi = (MethodInvocation) aopAllianceMethodInvocation;
102            return mi.proceed();
103        }
104    
105        /**
106         * Creates a Shiro {@link MethodInvocation MethodInvocation} instance and then immediately calls
107         * {@link org.apache.shiro.authz.aop.AuthorizingMethodInterceptor#invoke super.invoke}.
108         *
109         * @param methodInvocation the AOP Alliance-specific <code>methodInvocation</code> instance.
110         * @return the return value from invoking the method invocation.
111         * @throws Throwable if the underlying AOP Alliance method invocation throws a <code>Throwable</code>.
112         */
113        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
114            org.apache.shiro.aop.MethodInvocation mi = createMethodInvocation(methodInvocation);
115            return super.invoke(mi);
116        }
117    }