001    // Copyright 2011 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    // http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry5.internal.plastic;
016    
017    import java.lang.annotation.Annotation;
018    import java.lang.reflect.Method;
019    
020    import org.apache.tapestry5.plastic.InstanceContext;
021    import org.apache.tapestry5.plastic.MethodInvocation;
022    
023    public abstract class AbstractMethodInvocation implements MethodInvocation
024    {
025        private final Object instance;
026    
027        private final InstanceContext instanceContext;
028    
029        private final MethodInvocationBundle bundle;
030    
031        private int adviceIndex;
032    
033        protected AbstractMethodInvocation(Object instance, InstanceContext instanceContext, MethodInvocationBundle bundle)
034        {
035            this.instance = instance;
036            this.instanceContext = instanceContext;
037            this.bundle = bundle;
038        }
039    
040        private Exception checkedException;
041    
042        /**
043         * Invoked from the implementation of {@link MethodInvocation#setReturnValue(Object)}.
044         */
045        protected void clearCheckedException()
046        {
047            checkedException = null;
048        }
049    
050        public void rethrow()
051        {
052            if (checkedException != null)
053                throw new RuntimeException(checkedException);
054        }
055    
056        public boolean didThrowCheckedException()
057        {
058            return checkedException != null;
059        }
060    
061        public <T extends Throwable> T getCheckedException(Class<T> exceptionType)
062        {
063            assert exceptionType != null;
064    
065            if (exceptionType.isInstance(checkedException))
066                return exceptionType.cast(checkedException);
067    
068            return null;
069        }
070    
071        public Object getInstance()
072        {
073            return instance;
074        }
075    
076        public InstanceContext getInstanceContext()
077        {
078            return instanceContext;
079        }
080    
081        public MethodInvocation proceed()
082        {
083            if (adviceIndex == bundle.advice.length)
084                proceedToAdvisedMethod();
085            else
086                bundle.advice[adviceIndex++].advise(this);
087    
088            return this;
089        }
090    
091        public MethodInvocation setCheckedException(Exception exception)
092        {
093            checkedException = exception;
094    
095            return this;
096        }
097    
098        public <T extends Annotation> boolean hasAnnotation(Class<T> annotationType)
099        {
100            return getAnnotation(annotationType) != null;
101        }
102    
103        public <T extends Annotation> T getAnnotation(Class<T> annotationType)
104        {
105            return getMethod().getAnnotation(annotationType);
106        }
107    
108        public Method getMethod()
109        {
110            return bundle.getMethod(getInstance());
111        }
112    
113        /** This is implemented in a runtime-generated subclass. */
114        protected abstract void proceedToAdvisedMethod();
115    }