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.axis2.jaxws.server.endpoint.injection.impl;
020:
021: import java.lang.annotation.Annotation;
022: import java.lang.reflect.AccessibleObject;
023: import java.lang.reflect.Field;
024: import java.lang.reflect.InvocationTargetException;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Modifier;
027: import java.security.PrivilegedAction;
028: import java.util.ArrayList;
029: import java.util.List;
030:
031: import javax.annotation.Resource;
032: import javax.xml.ws.WebServiceContext;
033: import javax.xml.ws.handler.MessageContext;
034:
035: import org.apache.axis2.java.security.AccessController;
036: import org.apache.axis2.jaxws.context.WebServiceContextImpl;
037: import org.apache.axis2.jaxws.i18n.Messages;
038: import org.apache.axis2.jaxws.injection.ResourceInjectionException;
039: import org.apache.axis2.jaxws.server.endpoint.injection.WebServiceContextInjector;
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042:
043: public class WebServiceContextInjectorImpl implements
044: WebServiceContextInjector {
045: private static final Log log = LogFactory
046: .getLog(WebServiceContextInjectorImpl.class);
047: private static String METHOD_NAME = "set";
048: private static int NUMBER_OF_PARAMETERS = 1;
049: private static String RETURN_TYPE = "void";
050:
051: public WebServiceContextInjectorImpl() {
052: super ();
053:
054: }
055:
056: /* (non-Javadoc)
057: * @see org.apache.axis2.jaxws.server.endpoint.injection.WebServiceContextInjection#addMessageContext(javax.xml.ws.WebServiceContext, javax.xml.ws.handler.MessageContext)
058: */
059: public void addMessageContext(WebServiceContext wc,
060: MessageContext mc) {
061: WebServiceContextImpl wsContext = (WebServiceContextImpl) wc;
062: wsContext.setSoapMessageContext(mc);
063:
064: }
065:
066: /* (non-Javadoc)
067: * @see org.apache.axis2.jaxws.server.endpoint.injection.ResourceInjection#inject(java.lang.Object, java.lang.Object)
068: */
069: public void inject(Object resource, Object instance)
070: throws ResourceInjectionException {
071: if (instance == null) {
072: if (log.isDebugEnabled()) {
073: log
074: .debug("Cannot inject Resource on a null Service Instance.");
075: }
076: throw new ResourceInjectionException(Messages
077: .getMessage("WebServiceContextInjectionImplErr1"));
078: }
079:
080: Class serviceClazz = instance.getClass();
081:
082: /*Look for @Resource annotation on Field. If found then look for type on the annotation. If found, then
083: * if type is java.lang.Object then make sure type on declared field in javax.xml.WebServiceContext and assign the resource value
084: * if type is javax.xml.WebServiceContext then assign the resource value
085: */
086: Field resourceField = searchFieldsForResourceAnnotation(serviceClazz);
087: if (resourceField != null) {
088: if (log.isDebugEnabled()) {
089: log.debug("Attempting to inject Resource on Field");
090: }
091: //Found field that has a @Resource for WebServiceContext
092: //Inject Resource.
093: injectOnField(resource, instance, resourceField);
094: if (log.isDebugEnabled()) {
095: log.debug("Resource Injected on Field");
096: }
097: return;
098: }
099:
100: /* If @Resource annotation not found on declared Fileds, then look for it on Methods. If found then,
101: * if @Resource type is java.lang.Object then,
102: * look for PropertyDescriptor who's write Method or setter is the Method on which you found the annotation and
103: * make sure that the declared type of that property is javax.xml.WebServiceContext and invoke the Method with Resource.
104: * if @Resource type is javax.xml.ws.WebServiceContext, Invoke the Method with Resource.
105: */
106: Method method = searchMethodsResourceAnnotation(serviceClazz);
107: if (method != null) {
108: if (log.isDebugEnabled()) {
109: log.debug("Attempting to inject resource on Method");
110: }
111: if (!isValidMethod(method)) {
112: if (log.isDebugEnabled()) {
113: log
114: .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.");
115: }
116: throw new ResourceInjectionException(
117: Messages
118: .getMessage("WebServiceContextInjectionImplErr6"));
119: }
120: injectOnMethod(resource, instance, method);
121: if (log.isDebugEnabled()) {
122: log.debug("Resource Injected");
123: }
124: return;
125: }
126:
127: //Nothing to inject
128: }
129:
130: /* (non-Javadoc)
131: * @see org.apache.axis2.jaxws.server.endpoint.injection.ResourceInjection#injectOnClass(java.lang.Object, java.lang.Object, java.lang.Class)
132: */
133: public void injectOnClass(Object resource, Object instance,
134: Class clazz) throws ResourceInjectionException {
135: throw new UnsupportedOperationException(
136: "WebServiceContext Injeciton on Class not yet supported");
137:
138: }
139:
140: /* (non-Javadoc)
141: * @see org.apache.axis2.jaxws.server.endpoint.injection.ResourceInjection#injectOnField(java.lang.Object, java.lang.Object, java.lang.reflect.Field)
142: */
143: public void injectOnField(Object resource, Object instance,
144: Field field) throws ResourceInjectionException {
145: if (instance == null) {
146: if (log.isDebugEnabled()) {
147: log
148: .debug("Cannot inject Resource on a null Service Instance.");
149: }
150: throw new ResourceInjectionException(Messages
151: .getMessage("WebServiceContextInjectionImplErr1"));
152: }
153: if (field == null) {
154: if (log.isDebugEnabled()) {
155: log
156: .debug("Cannot inject WebServiceContext on ServiceInstance Field, field cannot be NULL");
157: }
158: throw new ResourceInjectionException(Messages
159: .getMessage("WebServiceContextInjectionImplErr3"));
160: }
161: try {
162: if (!Modifier.isPublic(field.getModifiers())) {
163: setAccessible(field, true);
164: }
165: //Inject Resource.
166: field.set(instance, resource);
167: } catch (IllegalAccessException e) {
168: throw new ResourceInjectionException(e);
169: }
170:
171: }
172:
173: /* (non-Javadoc)
174: * @see org.apache.axis2.jaxws.server.endpoint.injection.ResourceInjection#injectOnMethod(java.lang.Object, java.lang.Object, java.lang.reflect.Method)
175: */
176: public void injectOnMethod(Object resource, Object instance,
177: Method method) throws ResourceInjectionException {
178: if (instance == null) {
179: if (log.isDebugEnabled()) {
180: log
181: .debug("Cannot inject Resource on a null Service Instance.");
182: }
183: throw new ResourceInjectionException(Messages
184: .getMessage("WebServiceContextInjectionImplErr1"));
185: }
186: if (method == null) {
187: if (log.isDebugEnabled()) {
188: log
189: .debug("Cannot inject WebServiceContext on ServiceInstance Method, method cannot be NULL");
190: }
191: throw new ResourceInjectionException(Messages
192: .getMessage("WebServiceContextInjectionImplErr3"));
193: }
194: try {
195: if (!Modifier.isPublic(method.getModifiers())) {
196: setAccessible(method, true);
197: }
198: method.invoke(instance, resource);
199: return;
200: } catch (IllegalAccessException e) {
201: throw new ResourceInjectionException(e);
202: } catch (InvocationTargetException e) {
203: throw new ResourceInjectionException(e);
204: }
205:
206: }
207:
208: /**
209: * Set accessible. This method must remain private
210: *
211: * @param obj AccessibleObject
212: * @param value true or false
213: */
214: private static void setAccessible(final AccessibleObject obj,
215: final boolean value) {
216: AccessController.doPrivileged(new PrivilegedAction() {
217: public Object run() {
218: obj.setAccessible(value);
219: return null;
220: }
221: });
222:
223: }
224:
225: /*
226: * Search for Field with @Resource Annotation.
227: */
228: private Field searchFieldsForResourceAnnotation(Class bean) {
229: if (bean == null) {
230: return null;
231: }
232: List<Field> fields = getFields(bean);
233: for (Field field : fields) {
234: Annotation[] annotations = field.getAnnotations();
235: for (Annotation an : annotations) {
236: if (Resource.class.isAssignableFrom(an.getClass())) {
237: //check to make sure it is a @Resource for WebServiceContext.
238: Resource atResource = (Resource) an;
239: Class type = atResource.type();
240: if (isWebServiceContextResource(atResource, field)) {
241: return field;
242: }
243: }
244: }
245: }
246: return null;
247: }
248:
249: /**
250: * Gets all of the fields in this class and the super classes
251: *
252: * @param beanClass
253: * @return
254: */
255: static private List<Field> getFields(final Class beanClass) {
256: // This class must remain private due to Java 2 Security concerns
257: List<Field> fields;
258: fields = (List<Field>) AccessController
259: .doPrivileged(new PrivilegedAction() {
260: public Object run() {
261: List<Field> fields = new ArrayList<Field>();
262: Class cls = beanClass;
263: while (cls != null) {
264: Field[] fieldArray = cls
265: .getDeclaredFields();
266: for (Field field : fieldArray) {
267: fields.add(field);
268: }
269: cls = cls.getSuperclass();
270: }
271: return fields;
272: }
273: });
274:
275: return fields;
276: }
277:
278: /**
279: * Gets all of the fields in this class and the super classes
280: *
281: * @param beanClass
282: * @return
283: */
284: static private List<Method> getMethods(final Class beanClass) {
285: // This class must remain private due to Java 2 Security concerns
286: List<Method> methods;
287: methods = (List<Method>) AccessController
288: .doPrivileged(new PrivilegedAction() {
289: public Object run() {
290: List<Method> methods = new ArrayList<Method>();
291: Class cls = beanClass;
292: while (cls != null) {
293: Method[] methodArray = cls
294: .getDeclaredMethods();
295: for (Method method : methodArray) {
296: methods.add(method);
297: }
298: cls = cls.getSuperclass();
299: }
300: return methods;
301: }
302: });
303:
304: return methods;
305: }
306:
307: /*
308: * Search for Method with @Resource Annotation
309: */
310: private Method searchMethodsResourceAnnotation(Class bean) {
311: if (bean == null) {
312: return null;
313: }
314: List<Method> methods = getMethods(bean);
315: for (Method method : methods) {
316: Annotation[] annotations = method.getAnnotations();
317: for (Annotation an : annotations) {
318: if (Resource.class.isAssignableFrom(an.getClass())) {
319: //check to make sure it is a @Resource for WebServiceContext.
320: Resource atResource = (Resource) an;
321: if (isWebServiceContextResource(atResource, method)) {
322: return method;
323: }
324: }
325: }
326: }
327: return null;
328: }
329:
330: private boolean isWebServiceContextResource(Resource atResource,
331: Field field) {
332: Class type = atResource.type();
333: if (type == java.lang.Object.class) {
334: if (field != null
335: && field.getType() == WebServiceContext.class) {
336: return true;
337: }
338: } else if (type == WebServiceContext.class) {
339: //TODO: Should I check if the field declared type is assignable from WebServiceContext. Spec is not clear about this.
340: return true;
341: }
342: if (log.isDebugEnabled()) {
343: log
344: .debug("Invalid Field type or Resource Type found, cannot inject WebServiceContext on this field");
345: }
346: return false;
347: }
348:
349: private boolean isWebServiceContextResource(Resource atResource,
350: Method method) {
351: //As per JSR-250 the method injection is nothing but setter based injection,
352: //Such a injection can happen if method name starts with "set" returns a void and
353: //only has one parameter and the type of this parameter must be compatible with
354: //resource.
355:
356: Class type = atResource.type();
357: Class[] paramTypes = method.getParameterTypes();
358: for (Class paramType : paramTypes)
359: if (type == java.lang.Object.class) {
360: if (paramType == WebServiceContext.class
361: || paramType
362: .isAssignableFrom(WebServiceContext.class)) {
363: return true;
364: }
365: } else if (type == WebServiceContext.class) {
366: //TODO: Should I check if the field declared type is assignable from WebServiceContext. Spec is not clear about this.
367: return true;
368: }
369: if (log.isDebugEnabled()) {
370: log
371: .debug("Invalid Field type or Resource Type found, cannot inject WebServiceContext on this method");
372: }
373: return false;
374: }
375:
376: private boolean isValidMethod(Method method) {
377: //As per JSR-250 the method injection is nothing but setter based injection,
378: //Such a injection can happen if method name starts with "set" returns a void and
379: //only has one parameter and the type of this parameter must be compatible with
380: //resource.
381: String name = method.getName();
382: Class returnType = method.getReturnType();
383: Class[] types = method.getParameterTypes();
384: int noOfDeclaredParameter = 0;
385: if (types != null) {
386: noOfDeclaredParameter = types.length;
387: }
388:
389: if (name.startsWith(METHOD_NAME)
390: && noOfDeclaredParameter == NUMBER_OF_PARAMETERS
391: && returnType.getName().equals(RETURN_TYPE)) {
392: return true;
393: }
394: if (log.isDebugEnabled()) {
395: log
396: .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");
397: }
398: return false;
399:
400: }
401:
402: }
|