blob: d7f231c9d0568c21edfa88963b4625d02b2c367c [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.description.impl;
import org.apache.axis2.jaxws.description.AttachmentDescription;
import org.apache.axis2.jaxws.description.EndpointDescriptionJava;
import org.apache.axis2.jaxws.description.OperationDescription;
import org.apache.axis2.jaxws.description.ParameterDescription;
import org.apache.axis2.jaxws.description.ParameterDescriptionJava;
import org.apache.axis2.jaxws.description.ParameterDescriptionWSDL;
import org.apache.axis2.jaxws.description.builder.ParameterDescriptionComposite;
import org.apache.axis2.jaxws.description.builder.converter.ConverterUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.jws.WebParam;
import javax.jws.soap.SOAPBinding;
import javax.xml.ws.Holder;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/** @see ../ParameterDescription */
class ParameterDescriptionImpl
implements ParameterDescription, ParameterDescriptionJava, ParameterDescriptionWSDL {
private static final Log log = LogFactory.getLog(ParameterDescriptionImpl.class);
private OperationDescription parentOperationDescription;
// The Class representing the parameter. Note that for a Generic, including the JAX-WS Holder<T> Generic,
// this represents the raw type of the Generic (e.g. List for List<T> or Holder for Holder<T>).
private Class parameterType;
// For the JAX-WS Generic Holder<T> (e.g. Holder<Foo>), this will be the actual type argument (e.g. Foo). For
// any other parameter (including other Generics), this will be null.
// Note that since JAX-WS Holder<T> only supports a single actual type T (not multiple types such as <K,V>)
private Class parameterHolderActualType;
// 0-based number of the parameter in the argument list
private int parameterNumber = -1;
// The Parameter Description Composite used to build the ParameterDescription
private ParameterDescriptionComposite paramDescComposite;
// ANNOTATION: @WebMethod
private WebParam webParamAnnotation;
private String webParamName;
private String webParamPartName;
public static final String WebParam_TargetNamespace_DEFAULT = "";
private String webParamTargetNamespace;
private WebParam.Mode webParamMode;
public static final Boolean WebParam_Header_DEFAULT = new Boolean(false);
private Boolean webParamHeader;
// Attachment Description information
private boolean _setAttachmentDesc = false;
private AttachmentDescription attachmentDesc = null;
// This boolean indicates whether or not there was an @XMLList on the parameter
private boolean isListType = false;
ParameterDescriptionImpl(int parameterNumber, Class parameterType, Type parameterGenericType,
Annotation[] parameterAnnotations, OperationDescription parent) {
this.parameterNumber = parameterNumber;
this.parentOperationDescription = parent;
this.parameterType = parameterType;
// The Type argument could be a Type (if the parameter is a Paramaterized Generic) or
// just a Class (if it is not). If it JAX-WS Holder<T> parameterized type, then get the
// actual parameter type and hang on to that, too.
if (ParameterizedType.class.isInstance(parameterGenericType)) {
this.parameterHolderActualType =
getGenericParameterActualType((ParameterizedType)parameterGenericType);
}
findWebParamAnnotation(parameterAnnotations);
this.isListType = ConverterUtils.hasXmlListAnnotation(parameterAnnotations);
}
ParameterDescriptionImpl(int parameterNumber, ParameterDescriptionComposite pdc,
OperationDescription parent) {
this.paramDescComposite = pdc;
this.parameterNumber = parameterNumber;
this.parentOperationDescription = parent;
webParamAnnotation = pdc.getWebParamAnnot();
this.isListType = pdc.isListType();
//TODO: Need to build the schema map. Need to add logic to add this parameter
// to the schema map.
}
/*
* This grabs the WebParam annotation from the list of annotations for this parameter
* This should be DEPRECATED once DBC processing is complete.
*/
private void findWebParamAnnotation(Annotation[] annotations) {
for (Annotation checkAnnotation : annotations) {
// REVIEW: This may not work with the MDQInput. From the java.lang.annotation.Annotation interface
// javadoc: "Note that an interface that manually extends this one does not define an annotation type."
if (checkAnnotation.annotationType() == WebParam.class) {
webParamAnnotation = (WebParam)checkAnnotation;
}
}
}
public OperationDescription getOperationDescription() {
return parentOperationDescription;
}
/**
* Returns the class associated with the parameter. Note that for the JAX-WS Holder<T> type,
* you can use getParameterActualType() to get the class associated with T.
*/
public Class getParameterType() {
if (parameterType == null && paramDescComposite != null) {
parameterType = paramDescComposite.getParameterTypeClass();
}
return parameterType;
}
/**
* For a non-Holder type, returns the parameter class. For a Holder<T> type, returns the class
* of T.
*
* @return
*/
public Class getParameterActualType() {
if (parameterHolderActualType == null && paramDescComposite != null &&
paramDescComposite.isHolderType()) {
parameterHolderActualType = paramDescComposite.getHolderActualTypeClass();
return parameterHolderActualType;
} else if (parameterHolderActualType != null) {
return parameterHolderActualType;
} else {
if (paramDescComposite != null && parameterType == null) {
parameterType = paramDescComposite.getParameterTypeClass();
}
return parameterType;
}
}
/**
* TEMPORARY METHOD! For a JAX-WS Holder<T> this returns the class associated with <T>. For a
* Holder<Generic<...>>, it returns the class associated with Generic. If the type is not a
* JAX-WS Holder, return a null.
* <p/>
* This method SHOULD BE REMOVED when the description layer is refactored to use only DBC and
* not Java reflection directly.
*
* @param parameterGenericType
* @return
*/
// TODO: Remove this method when code refactored to only use DBC.
private Class getGenericParameterActualType(ParameterizedType parameterGenericType) {
Class returnClass = null;
// If this is a JAX-WS Holder type, then get the actual type. Note that we can't use the
// isHolderType method yet because the class variable it is going to check (parameterHolderActualType)
// hasn't been initialized yet.
if (parameterGenericType != null &&
parameterGenericType.getRawType() == javax.xml.ws.Holder.class) {
// NOTE
// If you change this code, please remember to change
// OperationDesc.getResultActualType
Type type = parameterGenericType.getActualTypeArguments()[0];
if (type != null && ParameterizedType.class.isInstance(type)) {
// For types of Holder<Generic<K,V>>, return class associated with Generic
returnClass = (Class)((ParameterizedType)type).getRawType();
} else if (type != null && GenericArrayType.class.isInstance(type)) {
Type componentType = ((GenericArrayType)type).getGenericComponentType();
Class arrayClass = null;
if (ParameterizedType.class.isInstance(componentType)) {
// For types of Holder<Generic<K,V>[]>, return class associated with Generic[]
arrayClass = (Class)((ParameterizedType)componentType).getRawType();
} else {
// For types of Holder<Object[]>, return class associated with Object[]
arrayClass = (Class)componentType;
}
// REVIEW: This only works for a single dimension array! Note that if this method is removed
// when DBC is used, just make sure DBC supports multi-dim arrays
returnClass = Array.newInstance(arrayClass, 0).getClass();
} else {
// For types of Holder<Object>, return the class associated with Object
returnClass = (Class)type;
}
}
return returnClass;
}
/** Answer whether this ParameterDescription represents a JAX-WS Holder<T> type. */
public boolean isHolderType() {
// If this is a JAX-WS Holder<T> type, then we set the the class of the actual
// parameter <T> in the constructor. Otherwise, that is null.
// Holder types are defined by JSR-224 JAX-WS 2.0, Sec 2.3.3, pg 16
if (paramDescComposite != null) {
return paramDescComposite.isHolderType();
} else {
return Holder.class.equals(getParameterType());
}
}
// =====================================
// ANNOTATION: WebParam
// =====================================
public WebParam getAnnoWebParam() {
return webParamAnnotation;
}
public String getParameterName() {
return getAnnoWebParamName();
}
public String getAnnoWebParamName() {
if (webParamName == null) {
if (getAnnoWebParam() != null && !DescriptionUtils.isEmpty(getAnnoWebParam().name())) {
webParamName = getAnnoWebParam().name();
} else if (getOperationDescription().getSoapBindingStyle() == SOAPBinding.Style.DOCUMENT
&& getOperationDescription().getSoapBindingParameterStyle() ==
SOAPBinding.ParameterStyle.BARE) {
// Defaul per JSR-181 MR Sec 4.4.1, pg 19
// TODO: Validation: For BARE paramaterUse, only a single IN our INOUT paramater and a single output (either return or OUT or INOUT) is allowed
// Per JSR-224, Sec 3.6.2.2, pg 37
webParamName = getOperationDescription().getOperationName();
} else {
// Default per JSR-181 MR Sec 4.4.1, pg 20
// Return "argN" where N is the index of the parameter in the method signature
webParamName = "arg" + parameterNumber;
}
}
return webParamName;
}
public String getPartName() {
return getAnnoWebParamPartName();
}
public String getAnnoWebParamPartName() {
if (webParamPartName == null) {
if (getAnnoWebParam() != null &&
!DescriptionUtils.isEmpty(getAnnoWebParam().partName())) {
webParamPartName = getAnnoWebParam().partName();
} else {
// Default per JSR-181 MR Sec 4.4.1, pg 20
webParamPartName = getAnnoWebParamName();
}
}
return webParamPartName;
}
public String getTargetNamespace() {
return getAnnoWebParamTargetNamespace();
}
public String getAnnoWebParamTargetNamespace() {
if (webParamTargetNamespace == null) {
if (getAnnoWebParam() != null &&
!DescriptionUtils.isEmpty(getAnnoWebParam().targetNamespace())) {
webParamTargetNamespace = getAnnoWebParam().targetNamespace();
} else if (getOperationDescription().getSoapBindingStyle() == SOAPBinding.Style.DOCUMENT
&& getOperationDescription().getSoapBindingParameterStyle() ==
SOAPBinding.ParameterStyle.WRAPPED
&& !getAnnoWebParamHeader()) {
// Defaul per JSR-181 MR Sec 4.4.1, pg 20
webParamTargetNamespace = WebParam_TargetNamespace_DEFAULT;
} else {
// Default per JSR-181 MR Sec 4.4.1, pg 20
webParamTargetNamespace = ((EndpointDescriptionJava)getOperationDescription()
.getEndpointInterfaceDescription().getEndpointDescription())
.getAnnoWebServiceTargetNamespace();
}
}
return webParamTargetNamespace;
}
// public Mode getMode() {
public WebParam.Mode getMode() {
return getAnnoWebParamMode();
}
public WebParam.Mode getAnnoWebParamMode() {
if (webParamMode == null) {
// Interesting conundrum here:
// Because WebParam.mode has a default value, it will always return something if the
// annotation is present. That value is currently Mode.IN. However, that default is only
// correct for a non-Holder Type; the correct default for a Holder Type is Mode.INOUT. Furthermore,
// there's no way (I can tell) to differentiate if the setting for mode() was specified or defaulted,
// so there's no way to tell if the value is defaulted to IN or explicitly specified IN by the annotation.
// The conundrum is: Do we return the value from the annotation, or do we return the default value based on the
// type. For now, for a Holder type that has a value of IN, we reset the value to INOUT.
// That means even if WebParam.mode=IN was explicitly set, it will be overridden to INOUT.
// The default values are from JSR-181 MR Sec 4.4.1, pg 20
// Unlike a String value, if the annotation is present, it will return a usable default value as defined by
// the Annotation. That is currently Mode.IN
if (getAnnoWebParam() != null) {
webParamMode = getAnnoWebParam().mode();
} else {
webParamMode = WebParam.Mode.IN;
}
if (isHolderType() && webParamMode == WebParam.Mode.IN) {
// Default per JSR-181 MR Sec 4.4.1, pg 20
webParamMode = WebParam.Mode.INOUT;
}
}
return webParamMode;
}
public boolean isHeader() {
return getAnnoWebParamHeader();
}
public boolean getAnnoWebParamHeader() {
if (webParamHeader == null) {
// Unlike a String value, if the annotation is present, it will return a usable default value.
if (getAnnoWebParam() != null) {
webParamHeader = getAnnoWebParam().header();
} else {
webParamHeader = WebParam_Header_DEFAULT;
}
}
return webParamHeader.booleanValue();
}
public String toString() {
final String newline = "\n";
final String sameline = "; ";
StringBuffer string = new StringBuffer();
try {
string.append(super.toString());
string.append(newline);
string.append("Name: " + getParameterName());
//
string.append(newline);
string.append("Is header: " + (isHeader() == true));
string.append(sameline);
string.append("Is holder: " + (isHolderType() == true));
//
string.append(newline);
string.append("Mode: " + getMode());
//
string.append(newline);
string.append("Type: " + getParameterType());
string.append(sameline);
string.append("Actual type: " + getParameterActualType());
if (getAttachmentDescription() != null) {
string.append(newline);
string.append(getAttachmentDescription().toString());
}
}
catch (Throwable t) {
string.append(newline);
string.append("Complete debug information not currently available for " +
"ParameterDescription");
return string.toString();
}
return string.toString();
}
public boolean isListType() {
return isListType;
}
/**
* Helper method to get to parent impl object.
*/
private OperationDescriptionImpl getOperationDescriptionImpl() {
if(this.getOperationDescription() instanceof OperationDescriptionImpl) {
return (OperationDescriptionImpl) this.getOperationDescription();
}
return null;
}
/**
* This method will return an AttachmentDescription based on the part name of the parameter.
*/
public AttachmentDescription getAttachmentDescription() {
String partName = this.getPartName();
if(partName != null && getOperationDescriptionImpl() != null) {
if(log.isDebugEnabled()) {
log.debug("Returning parameter AttachmentDescription for partName: " +
partName);
}
return getOperationDescriptionImpl().getPartAttachmentDescription(partName);
}
if(log.isDebugEnabled()) {
log.debug("Did not find parameter AttachmentDescription for partName: " + partName);
}
return null;
}
}