| /* |
| * 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.axis2.jaxws.server.endpoint.injection.impl; |
| |
| import org.apache.axis2.java.security.AccessController; |
| import org.apache.axis2.jaxws.context.WebServiceContextImpl; |
| import org.apache.axis2.jaxws.i18n.Messages; |
| import org.apache.axis2.jaxws.injection.ResourceInjectionException; |
| import org.apache.axis2.jaxws.server.endpoint.injection.WebServiceContextInjector; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import javax.annotation.Resource; |
| import javax.xml.ws.WebServiceContext; |
| import javax.xml.ws.handler.MessageContext; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.AccessibleObject; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.security.PrivilegedAction; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public class WebServiceContextInjectorImpl implements WebServiceContextInjector { |
| private static final Log log = LogFactory.getLog(WebServiceContextInjectorImpl.class); |
| private static String METHOD_NAME = "set"; |
| private static int NUMBER_OF_PARAMETERS = 1; |
| private static String RETURN_TYPE = "void"; |
| |
| public WebServiceContextInjectorImpl() { |
| super(); |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.axis2.jaxws.server.endpoint.injection.WebServiceContextInjection#addMessageContext(javax.xml.ws.WebServiceContext, javax.xml.ws.handler.MessageContext) |
| */ |
| public void addMessageContext(WebServiceContext wc, MessageContext mc) { |
| WebServiceContextImpl wsContext = (WebServiceContextImpl)wc; |
| wsContext.setSoapMessageContext(mc); |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.axis2.jaxws.server.endpoint.injection.ResourceInjection#inject(java.lang.Object, java.lang.Object) |
| */ |
| public void inject(Object resource, Object instance) throws ResourceInjectionException { |
| if (instance == null) { |
| if (log.isDebugEnabled()) { |
| log.debug("Cannot inject Resource on a null Service Instance."); |
| } |
| throw new ResourceInjectionException( |
| Messages.getMessage("WebServiceContextInjectionImplErr1")); |
| } |
| |
| Class serviceClazz = instance.getClass(); |
| |
| /*Look for @Resource annotation on Field. If found then look for type on the annotation. If found, then |
| * if type is java.lang.Object then make sure type on declared field in javax.xml.WebServiceContext and assign the resource value |
| * if type is javax.xml.WebServiceContext then assign the resource value |
| */ |
| Field resourceField = searchFieldsForResourceAnnotation(serviceClazz); |
| if (resourceField != null) { |
| if (log.isDebugEnabled()) { |
| log.debug("Attempting to inject Resource on Field"); |
| } |
| //Found field that has a @Resource for WebServiceContext |
| //Inject Resource. |
| injectOnField(resource, instance, resourceField); |
| if (log.isDebugEnabled()) { |
| log.debug("Resource Injected on Field"); |
| } |
| return; |
| } |
| |
| /* If @Resource annotation not found on declared Fileds, then look for it on Methods. If found then, |
| * if @Resource type is java.lang.Object then, |
| * look for PropertyDescriptor who's write Method or setter is the Method on which you found the annotation and |
| * make sure that the declared type of that property is javax.xml.WebServiceContext and invoke the Method with Resource. |
| * if @Resource type is javax.xml.ws.WebServiceContext, Invoke the Method with Resource. |
| */ |
| Method method = searchMethodsResourceAnnotation(serviceClazz); |
| if (method != null) { |
| if (log.isDebugEnabled()) { |
| log.debug("Attempting to inject resource on Method"); |
| } |
| if (!isValidMethod(method)) { |
| if (log.isDebugEnabled()) { |
| log.debug( |
| "injection can happen using method if method name starts with \"set\" returns a void and only has one parameter and the type of this parameter must be compatible with resource."); |
| } |
| throw new ResourceInjectionException( |
| Messages.getMessage("WebServiceContextInjectionImplErr6")); |
| } |
| injectOnMethod(resource, instance, method); |
| if (log.isDebugEnabled()) { |
| log.debug("Resource Injected"); |
| } |
| return; |
| } |
| |
| //Nothing to inject |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.axis2.jaxws.server.endpoint.injection.ResourceInjection#injectOnClass(java.lang.Object, java.lang.Object, java.lang.Class) |
| */ |
| public void injectOnClass(Object resource, Object instance, Class clazz) |
| throws ResourceInjectionException { |
| throw new UnsupportedOperationException(Messages.getMessage("injectOnClsErr")); |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.axis2.jaxws.server.endpoint.injection.ResourceInjection#injectOnField(java.lang.Object, java.lang.Object, java.lang.reflect.Field) |
| */ |
| public void injectOnField(Object resource, Object instance, Field field) |
| throws ResourceInjectionException { |
| if (instance == null) { |
| if (log.isDebugEnabled()) { |
| log.debug("Cannot inject Resource on a null Service Instance."); |
| } |
| throw new ResourceInjectionException( |
| Messages.getMessage("WebServiceContextInjectionImplErr1")); |
| } |
| if (field == null) { |
| if (log.isDebugEnabled()) { |
| log.debug( |
| "Cannot inject WebServiceContext on ServiceInstance Field, field cannot be NULL"); |
| } |
| throw new ResourceInjectionException( |
| Messages.getMessage("WebServiceContextInjectionImplErr3")); |
| } |
| try { |
| if (!Modifier.isPublic(field.getModifiers())) { |
| setAccessible(field, true); |
| } |
| //Inject Resource. |
| field.set(instance, resource); |
| } catch (IllegalAccessException e) { |
| throw new ResourceInjectionException(e); |
| } |
| |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.axis2.jaxws.server.endpoint.injection.ResourceInjection#injectOnMethod(java.lang.Object, java.lang.Object, java.lang.reflect.Method) |
| */ |
| public void injectOnMethod(Object resource, Object instance, Method method) |
| throws ResourceInjectionException { |
| if (instance == null) { |
| if (log.isDebugEnabled()) { |
| log.debug("Cannot inject Resource on a null Service Instance."); |
| } |
| throw new ResourceInjectionException( |
| Messages.getMessage("WebServiceContextInjectionImplErr1")); |
| } |
| if (method == null) { |
| if (log.isDebugEnabled()) { |
| log.debug( |
| "Cannot inject WebServiceContext on ServiceInstance Method, method cannot be NULL"); |
| } |
| throw new ResourceInjectionException( |
| Messages.getMessage("WebServiceContextInjectionImplErr3")); |
| } |
| try { |
| if (!Modifier.isPublic(method.getModifiers())) { |
| setAccessible(method, true); |
| } |
| method.invoke(instance, resource); |
| return; |
| } catch (IllegalAccessException e) { |
| throw new ResourceInjectionException(e); |
| } catch (InvocationTargetException e) { |
| throw new ResourceInjectionException(e); |
| } |
| |
| |
| } |
| |
| /** |
| * Set accessible. This method must remain private |
| * |
| * @param obj AccessibleObject |
| * @param value true or false |
| */ |
| private static void setAccessible(final AccessibleObject obj, final boolean value) { |
| AccessController.doPrivileged(new PrivilegedAction() { |
| public Object run() { |
| obj.setAccessible(value); |
| return null; |
| } |
| }); |
| |
| } |
| |
| /* |
| * Search for Field with @Resource Annotation. |
| */ |
| private Field searchFieldsForResourceAnnotation(Class bean) { |
| if (bean == null) { |
| return null; |
| } |
| List<Field> fields = getFields(bean); |
| for (Field field : fields) { |
| Annotation[] annotations = field.getAnnotations(); |
| for (Annotation an : annotations) { |
| if (Resource.class.isAssignableFrom(an.getClass())) { |
| //check to make sure it is a @Resource for WebServiceContext. |
| Resource atResource = (Resource)an; |
| Class type = atResource.type(); |
| if (isWebServiceContextResource(atResource, field)) { |
| return field; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Gets all of the fields in this class and the super classes |
| * |
| * @param beanClass |
| * @return |
| */ |
| static private List<Field> getFields(final Class beanClass) { |
| // This class must remain private due to Java 2 Security concerns |
| List<Field> fields; |
| fields = (List<Field>)AccessController.doPrivileged( |
| new PrivilegedAction() { |
| public Object run() { |
| List<Field> fields = new ArrayList<Field>(); |
| Class cls = beanClass; |
| while (cls != null) { |
| Field[] fieldArray = cls.getDeclaredFields(); |
| for (Field field : fieldArray) { |
| fields.add(field); |
| } |
| cls = cls.getSuperclass(); |
| } |
| return fields; |
| } |
| } |
| ); |
| |
| return fields; |
| } |
| |
| /** |
| * Gets all of the fields in this class and the super classes |
| * |
| * @param beanClass |
| * @return |
| */ |
| static private List<Method> getMethods(final Class beanClass) { |
| // This class must remain private due to Java 2 Security concerns |
| List<Method> methods; |
| methods = (List<Method>)AccessController.doPrivileged( |
| new PrivilegedAction() { |
| public Object run() { |
| List<Method> methods = new ArrayList<Method>(); |
| Class cls = beanClass; |
| while (cls != null) { |
| Method[] methodArray = cls.getDeclaredMethods(); |
| for (Method method : methodArray) { |
| methods.add(method); |
| } |
| cls = cls.getSuperclass(); |
| } |
| return methods; |
| } |
| } |
| ); |
| |
| return methods; |
| } |
| |
| /* |
| * Search for Method with @Resource Annotation |
| */ |
| private Method searchMethodsResourceAnnotation(Class bean) { |
| if (bean == null) { |
| return null; |
| } |
| List<Method> methods = getMethods(bean); |
| for (Method method : methods) { |
| Annotation[] annotations = method.getAnnotations(); |
| for (Annotation an : annotations) { |
| if (Resource.class.isAssignableFrom(an.getClass())) { |
| //check to make sure it is a @Resource for WebServiceContext. |
| Resource atResource = (Resource)an; |
| if (isWebServiceContextResource(atResource, method)) { |
| return method; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| private boolean isWebServiceContextResource(Resource atResource, Field field) { |
| Class type = atResource.type(); |
| if (type == java.lang.Object.class) { |
| if (field != null && field.getType() == WebServiceContext.class) { |
| return true; |
| } |
| } else if (type == WebServiceContext.class) { |
| //TODO: Should I check if the field declared type is assignable from WebServiceContext. Spec is not clear about this. |
| return true; |
| } |
| if (log.isDebugEnabled()) { |
| log.debug( |
| "Invalid Field type or Resource Type found, cannot inject WebServiceContext on this field"); |
| } |
| return false; |
| } |
| |
| private boolean isWebServiceContextResource(Resource atResource, Method method) { |
| //As per JSR-250 the method injection is nothing but setter based injection, |
| //Such a injection can happen if method name starts with "set" returns a void and |
| //only has one parameter and the type of this parameter must be compatible with |
| //resource. |
| |
| Class type = atResource.type(); |
| Class[] paramTypes = method.getParameterTypes(); |
| for (Class paramType : paramTypes) |
| if (type == java.lang.Object.class) { |
| if (paramType == WebServiceContext.class || |
| paramType.isAssignableFrom(WebServiceContext.class)) { |
| return true; |
| } |
| } else if (type == WebServiceContext.class) { |
| //TODO: Should I check if the field declared type is assignable from WebServiceContext. Spec is not clear about this. |
| return true; |
| } |
| if (log.isDebugEnabled()) { |
| log.debug( |
| "Invalid Field type or Resource Type found, cannot inject WebServiceContext on this method"); |
| } |
| return false; |
| } |
| |
| private boolean isValidMethod(Method method) { |
| //As per JSR-250 the method injection is nothing but setter based injection, |
| //Such a injection can happen if method name starts with "set" returns a void and |
| //only has one parameter and the type of this parameter must be compatible with |
| //resource. |
| String name = method.getName(); |
| Class returnType = method.getReturnType(); |
| Class[] types = method.getParameterTypes(); |
| int noOfDeclaredParameter = 0; |
| if (types != null) { |
| noOfDeclaredParameter = types.length; |
| } |
| |
| if (name.startsWith(METHOD_NAME) && noOfDeclaredParameter == NUMBER_OF_PARAMETERS && |
| returnType.getName().equals(RETURN_TYPE)) { |
| return true; |
| } |
| if (log.isDebugEnabled()) { |
| log.debug( |
| "Method found with @Resource annotaion and input param to set WebServiceContext Object, However method did not meet the criteria for injection as per JSR-250"); |
| } |
| return false; |
| |
| } |
| |
| |
| } |