blob: 1c89f50993602845dbfec5e10fe13a4f71967438 [file] [log] [blame]
/*
* 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;
}
}