| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.webbeans.intercept; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.enterprise.context.spi.Context; |
| import javax.enterprise.context.spi.Contextual; |
| import javax.enterprise.context.spi.CreationalContext; |
| import javax.interceptor.InvocationContext; |
| |
| import org.apache.webbeans.component.EnterpriseBeanMarker; |
| import org.apache.webbeans.component.OwbBean; |
| import org.apache.webbeans.container.BeanManagerImpl; |
| import org.apache.webbeans.context.creational.CreationalContextImpl; |
| import org.apache.webbeans.util.ClassUtil; |
| import org.apache.webbeans.util.SecurityUtil; |
| |
| /** |
| * Implementation of the {@link InvocationContext} interface. |
| */ |
| public class InvocationContextImpl implements InvocationContext |
| { |
| /** Context data for passing between interceptors */ |
| private Map<String, Object> contextData = new HashMap<String, Object>(); |
| |
| /** Invoked method */ |
| private Method method; |
| |
| /** Method parameters */ |
| private Object[] parameters; |
| |
| /** Interceptor stack */ |
| private List<InterceptorData> interceptorDatas; |
| |
| /** Target object */ |
| private Object target; |
| |
| /** Interceptor type */ |
| private InterceptorType type; |
| |
| /** Used for numbering interceptors */ |
| private int currentMethod = 1; |
| |
| /**Bean creational context*/ |
| private CreationalContext<?> creationalContext; |
| |
| private OwbBean<?> owbBean; |
| private InvocationContext ejbInvocationContext; |
| |
| |
| /** alternate key to be used for dependent creational contexts */ |
| private Object ccKey; |
| |
| /** |
| * Initializes the context. |
| * |
| * @param target target object |
| * @param method method |
| * @param parameters method parameters |
| * @param datas interceptor stack |
| * @param type interceptor type |
| */ |
| public InvocationContextImpl(OwbBean<?> bean, Object instance, Method method, Object[] parameters, List<InterceptorData> datas, InterceptorType type) |
| { |
| this.owbBean = bean; |
| this.method = method; |
| this.parameters = parameters; |
| this.interceptorDatas = datas; |
| this.type = type; |
| |
| if(instance == null) |
| { |
| configureTarget(bean); |
| } |
| else |
| { |
| this.target = instance; |
| } |
| } |
| |
| /** |
| * Sets owner bean creational context. |
| * @param ownerCreationalContext owner creational context |
| */ |
| public void setCreationalContext(CreationalContext<?> ownerCreationalContext) |
| { |
| this.creationalContext = ownerCreationalContext; |
| } |
| |
| /** |
| * Sets EJB invocation context |
| * @param c EJB containers invocation context |
| */ |
| public void setEJBInvocationContext(InvocationContext c) |
| { |
| this.ejbInvocationContext = c; |
| } |
| |
| |
| /** |
| * Gets target instance for given bean. |
| * @param bean bean instance |
| */ |
| @SuppressWarnings("unchecked") |
| private void configureTarget(OwbBean<?> bean) |
| { |
| Context webbeansContext = BeanManagerImpl.getManager().getContext(bean.getScope()); |
| |
| this.target = webbeansContext.get((Contextual<Object>)bean, (CreationalContext<Object>)this.creationalContext); |
| |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Map<String, Object> getContextData() |
| { |
| return this.contextData; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Method getMethod() |
| { |
| return this.method; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Object[] getParameters() |
| { |
| return this.parameters; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Object getTarget() |
| { |
| return this.target; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Object proceed() throws Exception |
| { |
| try |
| { |
| if (type.equals(InterceptorType.AROUND_INVOKE)) |
| { |
| return proceedAroundInvokes(this.interceptorDatas); |
| } |
| else if (type.equals(InterceptorType.AROUND_TIMEOUT)) |
| { |
| return proceedAroundTimeouts(this.interceptorDatas); |
| } |
| return proceedCommonAnnots(this.interceptorDatas, this.type); |
| |
| } |
| catch (InvocationTargetException ite) |
| { |
| // Try to provide the original exception to the interceptor stack, |
| // not the InvocationTargetException from Method.invoke |
| Throwable t = ite.getCause(); |
| if (t instanceof Exception) |
| { |
| throw (Exception) t; |
| } |
| throw ite; |
| } |
| catch (Exception e) |
| { |
| throw e; |
| } |
| } |
| |
| /** |
| * AroundInvoke operations on stack. |
| * @param datas interceptor stack |
| * @return final result |
| * @throws Exception for exceptions |
| */ |
| private Object proceedAroundInvokes(List<InterceptorData> datas) throws Exception |
| { |
| Object result = null; |
| |
| if (currentMethod <= datas.size()) |
| { |
| InterceptorData intc = datas.get(currentMethod - 1); |
| |
| Method method = intc.getAroundInvoke(); |
| boolean accessible = method.isAccessible(); |
| |
| if (!method.isAccessible()) |
| { |
| SecurityUtil.doPrivilegedSetAccessible(method, true); |
| } |
| |
| Object t = intc.createNewInstance(this.ccKey != null ? this.ccKey : this.target, |
| (CreationalContextImpl<?>)this.creationalContext); |
| |
| if (t == null) |
| { |
| t = target; |
| } |
| |
| currentMethod++; |
| |
| result = method.invoke(t, new Object[] { this }); |
| |
| if(!accessible) |
| { |
| SecurityUtil.doPrivilegedSetAccessible(method, false); |
| } |
| |
| } |
| else |
| { |
| if(!(this.owbBean instanceof EnterpriseBeanMarker)) |
| { |
| boolean accessible = this.method.isAccessible(); |
| if(!accessible) |
| { |
| SecurityUtil.doPrivilegedSetAccessible(method, true); |
| } |
| |
| result = this.method.invoke(target, parameters); |
| |
| if(!accessible) |
| { |
| SecurityUtil.doPrivilegedSetAccessible(method, false); |
| } |
| } |
| else |
| { |
| if (this.ejbInvocationContext != null) |
| { |
| result = ejbInvocationContext.proceed(); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * AroundTimeout operations on stack. |
| * @param datas interceptor stack |
| * @return final result |
| * @throws Exception for exceptions |
| */ |
| private Object proceedAroundTimeouts(List<InterceptorData> datas) throws Exception |
| { |
| Object result = null; |
| |
| if (currentMethod <= datas.size()) |
| { |
| InterceptorData intc = datas.get(currentMethod - 1); |
| |
| Method method = intc.getAroundTimeout(); |
| boolean accessible = method.isAccessible(); |
| |
| if (!accessible) |
| { |
| SecurityUtil.doPrivilegedSetAccessible(method, true); |
| } |
| |
| Object t = intc.createNewInstance(this.ccKey != null ? this.ccKey : this.target, |
| (CreationalContextImpl<?>)this.creationalContext); |
| |
| if (t == null) |
| { |
| t = target; |
| } |
| |
| currentMethod++; |
| |
| result = method.invoke(t, new Object[] { this }); |
| |
| if(!accessible) |
| { |
| SecurityUtil.doPrivilegedSetAccessible(method, false); |
| } |
| |
| } |
| else |
| { |
| if(!(this.owbBean instanceof EnterpriseBeanMarker)) |
| { |
| boolean accessible = this.method.isAccessible(); |
| if(!accessible) |
| { |
| SecurityUtil.doPrivilegedSetAccessible(method, true); |
| } |
| |
| result = this.method.invoke(target, parameters); |
| |
| if(!accessible) |
| { |
| SecurityUtil.doPrivilegedSetAccessible(method, false); |
| } |
| } |
| else |
| { |
| if (this.ejbInvocationContext != null) |
| { |
| result = ejbInvocationContext.proceed(); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Post construct and predestroy |
| * callback operations. |
| * @param datas interceptor stack |
| * @param type interceptor type |
| * @return final result |
| * @throws Exception for any exception |
| */ |
| private Object proceedCommonAnnots(List<InterceptorData> datas, InterceptorType type) throws Exception |
| { |
| Object result = null; |
| |
| if (currentMethod <= datas.size()) |
| { |
| InterceptorData intc = datas.get(currentMethod - 1); |
| Method method = null; |
| |
| if (type.equals(InterceptorType.POST_CONSTRUCT)) |
| { |
| method = intc.getPostConstruct(); |
| } |
| else if (type.equals(InterceptorType.POST_ACTIVATE)) |
| { |
| method = intc.getPostActivate(); |
| } |
| else if (type.equals(InterceptorType.PRE_PASSIVATE)) |
| { |
| method = intc.getPrePassivate(); |
| } |
| else if (type.equals(InterceptorType.PRE_DESTROY)) |
| { |
| method = intc.getPreDestroy(); |
| } |
| |
| if (!method.isAccessible()) |
| { |
| SecurityUtil.doPrivilegedSetAccessible(method, true); |
| } |
| |
| currentMethod++; |
| |
| Object t = intc.createNewInstance(this.ccKey != null ? this.ccKey : this.target, |
| (CreationalContextImpl<?>)this.creationalContext); |
| |
| //In bean class |
| if (t == null) |
| { |
| if(!(this.owbBean instanceof EnterpriseBeanMarker)) |
| { |
| t = target; |
| result = method.invoke(t, new Object[] {}); |
| |
| //Continue to call others |
| proceedCommonAnnots(datas, type); |
| } |
| } |
| //In interceptor class |
| else |
| { |
| result = method.invoke(t, new Object[] { this }); |
| } |
| |
| } |
| else |
| { |
| /* For EJB's, we do not call the "in bean class" interceptors --the container does, and only if |
| * our last 299 interceptor called proceed (which takes us here). |
| */ |
| if ((this.owbBean instanceof EnterpriseBeanMarker) && (this.ejbInvocationContext != null)) |
| { |
| result = ejbInvocationContext.proceed(); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setParameters(Object[] params) |
| { |
| if (getMethod() != null) |
| { |
| if (params == null) |
| { |
| if (this.parameters.length >= 0) |
| { |
| throw new IllegalArgumentException("Gvien parameters is null but expected not null parameters"); |
| } |
| } |
| else |
| { |
| if (params.length != this.parameters.length) |
| { |
| throw new IllegalArgumentException("Expected " + this.parameters.length + " " + |
| "parameters, but only got " + params.length + " parameters"); |
| } |
| |
| Class<?>[] methodParameters = this.method.getParameterTypes(); |
| int i = 0; |
| for (Object obj : params) |
| { |
| Class<?> parameterType = methodParameters[i++]; |
| if (obj == null) |
| { |
| if (parameterType.isPrimitive()) |
| { |
| throw new IllegalArgumentException("Expected parameter " + i + " to be primitive type " + parameterType.getName() + |
| ", but got a parameter that is null"); |
| } |
| } |
| else |
| { |
| //Primitive check |
| if(parameterType.isPrimitive()) |
| { |
| //First change to wrapper for comparision |
| parameterType = ClassUtil.getPrimitiveWrapper(parameterType); |
| } |
| |
| //Actual check |
| if (!parameterType.isInstance(obj)) |
| { |
| throw new IllegalArgumentException("Expected parameter " + i + " to be of type " + parameterType.getName() + |
| ", but got a parameter of type " + obj.getClass().getName()); |
| } |
| } |
| } |
| |
| System.arraycopy(params, 0, this.parameters, 0, params.length); |
| |
| } |
| |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Object getTimer() |
| { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| /** |
| * Sets the alternate key (alternate owner instance) to be used within |
| * the passed CreationalContext for dependent interceptors. |
| * |
| * @param ccKey a unique key used to index dependent interceptors |
| */ |
| public void setCcKey(Object ccKey) |
| { |
| this.ccKey = ccKey; |
| } |
| } |