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:
020: package org.apache.axis2.jaxws.description.impl;
021:
022: import org.apache.axis2.jaxws.description.AttachmentDescription;
023: import org.apache.axis2.jaxws.description.AttachmentType;
024: import org.apache.axis2.jaxws.description.EndpointDescriptionJava;
025: import org.apache.axis2.jaxws.description.OperationDescription;
026: import org.apache.axis2.jaxws.description.ParameterDescription;
027: import org.apache.axis2.jaxws.description.ParameterDescriptionJava;
028: import org.apache.axis2.jaxws.description.ParameterDescriptionWSDL;
029: import org.apache.axis2.jaxws.description.builder.ParameterDescriptionComposite;
030: import org.apache.axis2.jaxws.description.builder.converter.ConverterUtils;
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033:
034: import javax.jws.WebParam;
035: import javax.jws.soap.SOAPBinding;
036: import javax.xml.bind.annotation.XmlList;
037: import javax.xml.ws.Holder;
038: import java.lang.annotation.Annotation;
039: import java.lang.reflect.Array;
040: import java.lang.reflect.GenericArrayType;
041: import java.lang.reflect.ParameterizedType;
042: import java.lang.reflect.Type;
043:
044: /** @see ../ParameterDescription */
045: class ParameterDescriptionImpl implements ParameterDescription,
046: ParameterDescriptionJava, ParameterDescriptionWSDL {
047: private static final Log log = LogFactory
048: .getLog(ParameterDescriptionImpl.class);
049: private OperationDescription parentOperationDescription;
050: // The Class representing the parameter. Note that for a Generic, including the JAX-WS Holder<T> Generic,
051: // this represents the raw type of the Generic (e.g. List for List<T> or Holder for Holder<T>).
052: private Class parameterType;
053: // For the JAX-WS Generic Holder<T> (e.g. Holder<Foo>), this will be the actual type argument (e.g. Foo). For
054: // any other parameter (including other Generics), this will be null.
055: // Note that since JAX-WS Holder<T> only supports a single actual type T (not multiple types such as <K,V>)
056: private Class parameterHolderActualType;
057:
058: // 0-based number of the parameter in the argument list
059: private int parameterNumber = -1;
060: // The Parameter Description Composite used to build the ParameterDescription
061: private ParameterDescriptionComposite paramDescComposite;
062:
063: // ANNOTATION: @WebMethod
064: private WebParam webParamAnnotation;
065: private String webParamName;
066: private String webParamPartName;
067: public static final String WebParam_TargetNamespace_DEFAULT = "";
068: private String webParamTargetNamespace;
069: private WebParam.Mode webParamMode;
070: public static final Boolean WebParam_Header_DEFAULT = new Boolean(
071: false);
072: private Boolean webParamHeader;
073:
074: // Attachment Description information
075: private boolean _setAttachmentDesc = false;
076: private AttachmentDescription attachmentDesc = null;
077:
078: // This boolean indicates whether or not there was an @XMLList on the parameter
079: private boolean isListType = false;
080:
081: ParameterDescriptionImpl(int parameterNumber, Class parameterType,
082: Type parameterGenericType,
083: Annotation[] parameterAnnotations,
084: OperationDescription parent) {
085: this .parameterNumber = parameterNumber;
086: this .parentOperationDescription = parent;
087: this .parameterType = parameterType;
088:
089: // The Type argument could be a Type (if the parameter is a Paramaterized Generic) or
090: // just a Class (if it is not). If it JAX-WS Holder<T> parameterized type, then get the
091: // actual parameter type and hang on to that, too.
092: if (ParameterizedType.class.isInstance(parameterGenericType)) {
093: this .parameterHolderActualType = getGenericParameterActualType((ParameterizedType) parameterGenericType);
094: }
095: findWebParamAnnotation(parameterAnnotations);
096: this .isListType = ConverterUtils
097: .hasXmlListAnnotation(parameterAnnotations);
098: }
099:
100: ParameterDescriptionImpl(int parameterNumber,
101: ParameterDescriptionComposite pdc,
102: OperationDescription parent) {
103: this .paramDescComposite = pdc;
104: this .parameterNumber = parameterNumber;
105: this .parentOperationDescription = parent;
106: webParamAnnotation = pdc.getWebParamAnnot();
107: this .isListType = pdc.isListType();
108:
109: //TODO: Need to build the schema map. Need to add logic to add this parameter
110: // to the schema map.
111:
112: //TODO: Need to consider processing the following JAXWS annotations on this DBC
113: // webServiceRef is probably only client, so shouldn't be here
114: //webServiceContextAnnotation = pdc.getWebServiceContextAnnot();
115: //webServiceRefAnnotation = pdc.getWebServiceRefAnnot();
116: }
117:
118: /*
119: * This grabs the WebParam annotation from the list of annotations for this parameter
120: * This should be DEPRECATED once DBC processing is complete.
121: */
122: private void findWebParamAnnotation(Annotation[] annotations) {
123: for (Annotation checkAnnotation : annotations) {
124: // REVIEW: This may not work with the MDQInput. From the java.lang.annotation.Annotation interface
125: // javadoc: "Note that an interface that manually extends this one does not define an annotation type."
126: if (checkAnnotation.annotationType() == WebParam.class) {
127: webParamAnnotation = (WebParam) checkAnnotation;
128: }
129: }
130: }
131:
132: public OperationDescription getOperationDescription() {
133: return parentOperationDescription;
134: }
135:
136: /**
137: * Returns the class associated with the parameter. Note that for the JAX-WS Holder<T> type,
138: * you can use getParameterActualType() to get the class associated with T.
139: */
140: public Class getParameterType() {
141: if (parameterType == null && paramDescComposite != null) {
142: parameterType = paramDescComposite.getParameterTypeClass();
143: }
144: return parameterType;
145: }
146:
147: /**
148: * For a non-Holder type, returns the parameter class. For a Holder<T> type, returns the class
149: * of T.
150: *
151: * @return
152: */
153: public Class getParameterActualType() {
154: if (parameterHolderActualType == null
155: && paramDescComposite != null
156: && paramDescComposite.isHolderType()) {
157: parameterHolderActualType = paramDescComposite
158: .getHolderActualTypeClass();
159: return parameterHolderActualType;
160: } else if (parameterHolderActualType != null) {
161: return parameterHolderActualType;
162: } else {
163: if (paramDescComposite != null && parameterType == null) {
164: parameterType = paramDescComposite
165: .getParameterTypeClass();
166: }
167: return parameterType;
168: }
169: }
170:
171: /**
172: * TEMPORARY METHOD! For a JAX-WS Holder<T> this returns the class associated with <T>. For a
173: * Holder<Generic<...>>, it returns the class associated with Generic. If the type is not a
174: * JAX-WS Holder, return a null.
175: * <p/>
176: * This method SHOULD BE REMOVED when the description layer is refactored to use only DBC and
177: * not Java reflection directly.
178: *
179: * @param parameterGenericType
180: * @return
181: */
182: // TODO: Remove this method when code refactored to only use DBC.
183: private Class getGenericParameterActualType(
184: ParameterizedType parameterGenericType) {
185: Class returnClass = null;
186: // If this is a JAX-WS Holder type, then get the actual type. Note that we can't use the
187: // isHolderType method yet because the class variable it is going to check (parameterHolderActualType)
188: // hasn't been initialized yet.
189: if (parameterGenericType != null
190: && parameterGenericType.getRawType() == javax.xml.ws.Holder.class) {
191: // NOTE
192: // If you change this code, please remember to change
193: // OperationDesc.getResultActualType
194:
195: Type type = parameterGenericType.getActualTypeArguments()[0];
196: if (type != null
197: && ParameterizedType.class.isInstance(type)) {
198: // For types of Holder<Generic<K,V>>, return class associated with Generic
199: returnClass = (Class) ((ParameterizedType) type)
200: .getRawType();
201: } else if (type != null
202: && GenericArrayType.class.isInstance(type)) {
203: Type componentType = ((GenericArrayType) type)
204: .getGenericComponentType();
205: Class arrayClass = null;
206: if (ParameterizedType.class.isInstance(componentType)) {
207: // For types of Holder<Generic<K,V>[]>, return class associated with Generic[]
208: arrayClass = (Class) ((ParameterizedType) componentType)
209: .getRawType();
210: } else {
211: // For types of Holder<Object[]>, return class associated with Object[]
212: arrayClass = (Class) componentType;
213: }
214: // REVIEW: This only works for a single dimension array! Note that if this method is removed
215: // when DBC is used, just make sure DBC supports multi-dim arrays
216: returnClass = Array.newInstance(arrayClass, 0)
217: .getClass();
218: } else {
219: // For types of Holder<Object>, return the class associated with Object
220: returnClass = (Class) type;
221: }
222: }
223:
224: return returnClass;
225: }
226:
227: /** Answer whether this ParameterDescription represents a JAX-WS Holder<T> type. */
228: public boolean isHolderType() {
229: // If this is a JAX-WS Holder<T> type, then we set the the class of the actual
230: // parameter <T> in the constructor. Otherwise, that is null.
231: // Holder types are defined by JSR-224 JAX-WS 2.0, Sec 2.3.3, pg 16
232: if (paramDescComposite != null) {
233: return paramDescComposite.isHolderType();
234: } else {
235: return Holder.class.equals(getParameterType());
236: }
237: }
238:
239: // =====================================
240: // ANNOTATION: WebParam
241: // =====================================
242: public WebParam getAnnoWebParam() {
243: return webParamAnnotation;
244: }
245:
246: public String getParameterName() {
247: // REVIEW: WSDL/Anno merge
248: return getAnnoWebParamName();
249: }
250:
251: public String getAnnoWebParamName() {
252: if (webParamName == null) {
253: if (getAnnoWebParam() != null
254: && !DescriptionUtils.isEmpty(getAnnoWebParam()
255: .name())) {
256: webParamName = getAnnoWebParam().name();
257: } else if (getOperationDescription().getSoapBindingStyle() == SOAPBinding.Style.DOCUMENT
258: && getOperationDescription()
259: .getSoapBindingParameterStyle() == SOAPBinding.ParameterStyle.BARE) {
260: // Defaul per JSR-181 MR Sec 4.4.1, pg 19
261: // TODO: Validation: For BARE paramaterUse, only a single IN our INOUT paramater and a single output (either return or OUT or INOUT) is allowed
262: // Per JSR-224, Sec 3.6.2.2, pg 37
263: webParamName = getOperationDescription()
264: .getOperationName();
265: } else {
266: // Default per JSR-181 MR Sec 4.4.1, pg 20
267: // Return "argN" where N is the index of the parameter in the method signature
268: webParamName = "arg" + parameterNumber;
269: }
270: }
271: return webParamName;
272: }
273:
274: public String getPartName() {
275: // REVIEW: WSDL/Anno merge
276: return getAnnoWebParamPartName();
277: }
278:
279: public String getAnnoWebParamPartName() {
280: if (webParamPartName == null) {
281: if (getAnnoWebParam() != null
282: && !DescriptionUtils.isEmpty(getAnnoWebParam()
283: .partName())) {
284: webParamPartName = getAnnoWebParam().partName();
285: } else {
286: // Default per JSR-181 MR Sec 4.4.1, pg 20
287: webParamPartName = getAnnoWebParamName();
288: }
289: }
290: return webParamPartName;
291: }
292:
293: public String getTargetNamespace() {
294: // REVIEW: WSDL/Anno merge
295: return getAnnoWebParamTargetNamespace();
296: }
297:
298: public String getAnnoWebParamTargetNamespace() {
299: if (webParamTargetNamespace == null) {
300: if (getAnnoWebParam() != null
301: && !DescriptionUtils.isEmpty(getAnnoWebParam()
302: .targetNamespace())) {
303: webParamTargetNamespace = getAnnoWebParam()
304: .targetNamespace();
305: } else if (getOperationDescription().getSoapBindingStyle() == SOAPBinding.Style.DOCUMENT
306: && getOperationDescription()
307: .getSoapBindingParameterStyle() == SOAPBinding.ParameterStyle.WRAPPED
308: && !getAnnoWebParamHeader()) {
309: // Defaul per JSR-181 MR Sec 4.4.1, pg 20
310: webParamTargetNamespace = WebParam_TargetNamespace_DEFAULT;
311: } else {
312: // Default per JSR-181 MR Sec 4.4.1, pg 20
313: webParamTargetNamespace = ((EndpointDescriptionJava) getOperationDescription()
314: .getEndpointInterfaceDescription()
315: .getEndpointDescription())
316: .getAnnoWebServiceTargetNamespace();
317: }
318: }
319: return webParamTargetNamespace;
320: }
321:
322: // public Mode getMode() {
323:
324: public WebParam.Mode getMode() {
325: // REVIEW: WSDL/Anno merge. Problem is that OpDesc is expecting WebParam.Mode
326: return getAnnoWebParamMode();
327: }
328:
329: public WebParam.Mode getAnnoWebParamMode() {
330: if (webParamMode == null) {
331: // REVIEW: Is the following correct?
332: // Interesting conundrum here:
333: // Because WebParam.mode has a default value, it will always return something if the
334: // annotation is present. That value is currently Mode.IN. However, that default is only
335: // correct for a non-Holder Type; the correct default for a Holder Type is Mode.INOUT. Furthermore,
336: // there's no way (I can tell) to differentiate if the setting for mode() was specified or defaulted,
337: // so there's no way to tell if the value is defaulted to IN or explicitly specified IN by the annotation.
338: // The conundrum is: Do we return the value from the annotation, or do we return the default value based on the
339: // type. For now, for a Holder type that has a value of IN, we reset the value to INOUT.
340: // That means even if WebParam.mode=IN was explicitly set, it will be overridden to INOUT.
341: // The default values are from JSR-181 MR Sec 4.4.1, pg 20
342:
343: // Unlike a String value, if the annotation is present, it will return a usable default value as defined by
344: // the Annotation. That is currently Mode.IN
345: if (getAnnoWebParam() != null) {
346: webParamMode = getAnnoWebParam().mode();
347: } else {
348: webParamMode = WebParam.Mode.IN;
349: }
350:
351: if (isHolderType() && webParamMode == WebParam.Mode.IN) {
352: // Default per JSR-181 MR Sec 4.4.1, pg 20
353: webParamMode = WebParam.Mode.INOUT;
354: }
355: }
356: return webParamMode;
357: }
358:
359: public boolean isHeader() {
360: // REVIEW: WSDL/Anno merge
361: return getAnnoWebParamHeader();
362: }
363:
364: public boolean getAnnoWebParamHeader() {
365: if (webParamHeader == null) {
366: // Unlike a String value, if the annotation is present, it will return a usable default value.
367: if (getAnnoWebParam() != null) {
368: webParamHeader = getAnnoWebParam().header();
369: } else {
370: webParamHeader = WebParam_Header_DEFAULT;
371: }
372: }
373: return webParamHeader.booleanValue();
374: }
375:
376: public String toString() {
377: final String newline = "\n";
378: final String sameline = "; ";
379: StringBuffer string = new StringBuffer();
380: try {
381: string.append(super .toString());
382: string.append(newline);
383: string.append("Name: " + getParameterName());
384: //
385: string.append(newline);
386: string.append("Is header: " + (isHeader() == true));
387: string.append(sameline);
388: string.append("Is holder: " + (isHolderType() == true));
389: //
390: string.append(newline);
391: string.append("Mode: " + getMode());
392: //
393: string.append(newline);
394: string.append("Type: " + getParameterType());
395: string.append(sameline);
396: string.append("Actual type: " + getParameterActualType());
397: if (getAttachmentDescription() != null) {
398: string.append(newline);
399: string.append(getAttachmentDescription().toString());
400: }
401: } catch (Throwable t) {
402: string.append(newline);
403: string
404: .append("Complete debug information not currently available for "
405: + "ParameterDescription");
406: return string.toString();
407: }
408: return string.toString();
409: }
410:
411: public boolean isListType() {
412: return isListType;
413: }
414:
415: /**
416: * Helper method to get to parent impl object.
417: */
418: private OperationDescriptionImpl getOperationDescriptionImpl() {
419: if (this .getOperationDescription() instanceof OperationDescriptionImpl) {
420: return (OperationDescriptionImpl) this
421: .getOperationDescription();
422: }
423: return null;
424: }
425:
426: /**
427: * This method will return an AttachmentDescription based on the part name of the parameter.
428: */
429: public AttachmentDescription getAttachmentDescription() {
430: String partName = this .getPartName();
431: if (partName != null && getOperationDescriptionImpl() != null) {
432: if (log.isDebugEnabled()) {
433: log
434: .debug("Returning parameter AttachmentDescription for partName: "
435: + partName);
436: }
437: return getOperationDescriptionImpl()
438: .getPartAttachmentDescription(partName);
439:
440: }
441: if (log.isDebugEnabled()) {
442: log
443: .debug("Did not find parameter AttachmentDescription for partName: "
444: + partName);
445: }
446: return null;
447: }
448: }
|