0001: /**
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */package org.apache.geronimo.axis.builder;
0017:
0018: import java.lang.reflect.Method;
0019: import java.math.BigDecimal;
0020: import java.math.BigInteger;
0021: import java.net.URI;
0022: import java.util.ArrayList;
0023: import java.util.Calendar;
0024: import java.util.Collection;
0025: import java.util.Collections;
0026: import java.util.HashMap;
0027: import java.util.HashSet;
0028: import java.util.Iterator;
0029: import java.util.Map;
0030: import java.util.Set;
0031:
0032: import javax.wsdl.BindingInput;
0033: import javax.wsdl.BindingOperation;
0034: import javax.wsdl.Fault;
0035: import javax.wsdl.Message;
0036: import javax.wsdl.Part;
0037: import javax.wsdl.OperationType;
0038: import javax.wsdl.extensions.soap.SOAPBody;
0039: import javax.xml.namespace.QName;
0040:
0041: import org.apache.axis.constants.Style;
0042: import org.apache.axis.constants.Use;
0043: import org.apache.axis.description.FaultDesc;
0044: import org.apache.axis.description.OperationDesc;
0045: import org.apache.axis.description.ParameterDesc;
0046: import org.apache.axis.soap.SOAPConstants;
0047: import org.apache.axis.encoding.XMLType;
0048: import org.apache.geronimo.axis.client.OperationInfo;
0049: import org.apache.geronimo.common.DeploymentException;
0050: import org.apache.geronimo.kernel.ClassLoading;
0051: import org.apache.geronimo.xbeans.j2ee.ConstructorParameterOrderType;
0052: import org.apache.geronimo.xbeans.j2ee.ExceptionMappingType;
0053: import org.apache.geronimo.xbeans.j2ee.JavaWsdlMappingType;
0054: import org.apache.geronimo.xbeans.j2ee.MethodParamPartsMappingType;
0055: import org.apache.geronimo.xbeans.j2ee.ServiceEndpointMethodMappingType;
0056: import org.apache.geronimo.xbeans.j2ee.WsdlMessageMappingType;
0057: import org.apache.geronimo.xbeans.j2ee.WsdlReturnValueMappingType;
0058: import org.apache.xmlbeans.SchemaParticle;
0059: import org.apache.xmlbeans.SchemaProperty;
0060: import org.apache.xmlbeans.SchemaType;
0061: import org.objectweb.asm.Type;
0062: import org.apache.geronimo.xbeans.j2ee.JavaXmlTypeMappingType;
0063: import org.apache.geronimo.webservices.builder.SchemaInfoBuilder;
0064: import org.apache.geronimo.webservices.builder.WSDescriptorParser;
0065:
0066: /**
0067: * @version $Rev: 476049 $ $Date: 2006-11-16 20:35:17 -0800 (Thu, 16 Nov 2006) $
0068: */
0069: public class HeavyweightOperationDescBuilder extends
0070: OperationDescBuilder {
0071:
0072: private final JavaWsdlMappingType mapping;
0073: private final ServiceEndpointMethodMappingType methodMapping;
0074: private final SOAPBody soapBody;
0075:
0076: private final Map exceptionMap;
0077: private final SchemaInfoBuilder schemaInfoBuilder;
0078: private final ClassLoader classLoader;
0079: private final boolean rpcStyle;
0080: private final boolean documentStyle;
0081: private final boolean wrappedStyle;
0082: private final boolean isEncoded;
0083: private final Map publicTypes = new HashMap();
0084: private final Map anonymousTypes = new HashMap();
0085:
0086: /* Keep track of in and out parameter names so we can verify that
0087: * everything has been mapped and mapped correctly
0088: */
0089: private final Set inParamNames = new HashSet();
0090: private final Set outParamNames = new HashSet();
0091: private final Class serviceEndpointInterface;
0092:
0093: /**
0094: * Track the wrapper elements
0095: */
0096: private final Set wrapperElementQNames = new HashSet();
0097:
0098: public HeavyweightOperationDescBuilder(
0099: BindingOperation bindingOperation,
0100: JavaWsdlMappingType mapping,
0101: ServiceEndpointMethodMappingType methodMapping,
0102: Style defaultStyle, Map exceptionMap,
0103: SchemaInfoBuilder schemaInfoBuilder,
0104: JavaXmlTypeMappingType[] javaXmlTypeMappingTypes,
0105: ClassLoader classLoader, Class serviceEndpointInterface)
0106: throws DeploymentException {
0107: super (bindingOperation);
0108: this .mapping = mapping;
0109: this .methodMapping = methodMapping;
0110: this .exceptionMap = exceptionMap;
0111: this .schemaInfoBuilder = schemaInfoBuilder;
0112: for (int i = 0; i < javaXmlTypeMappingTypes.length; i++) {
0113: JavaXmlTypeMappingType javaXmlTypeMappingType = javaXmlTypeMappingTypes[i];
0114: String javaClassName = javaXmlTypeMappingType.getJavaType()
0115: .getStringValue().trim();
0116: if (javaXmlTypeMappingType.isSetAnonymousTypeQname()) {
0117: String anonymousTypeQName = javaXmlTypeMappingType
0118: .getAnonymousTypeQname().getStringValue()
0119: .trim();
0120: anonymousTypes.put(anonymousTypeQName, javaClassName);
0121: } else if (javaXmlTypeMappingType.isSetRootTypeQname()) {
0122: QName qname = javaXmlTypeMappingType.getRootTypeQname()
0123: .getQNameValue();
0124: publicTypes.put(qname, javaClassName);
0125: }
0126: }
0127: this .classLoader = classLoader;
0128: this .serviceEndpointInterface = serviceEndpointInterface;
0129: BindingInput bindingInput = bindingOperation.getBindingInput();
0130: this .soapBody = (SOAPBody) SchemaInfoBuilder
0131: .getExtensibilityElement(SOAPBody.class, bindingInput
0132: .getExtensibilityElements());
0133:
0134: wrappedStyle = methodMapping.isSetWrappedElement();
0135: if (false == wrappedStyle) {
0136: Style style = Style.getStyle(soapOperation.getStyle(),
0137: defaultStyle);
0138: if (style == Style.RPC) {
0139: rpcStyle = true;
0140: documentStyle = false;
0141: } else {
0142: rpcStyle = false;
0143: documentStyle = true;
0144: }
0145: } else {
0146: rpcStyle = false;
0147: documentStyle = false;
0148: }
0149: isEncoded = Use.getUse(soapBody.getUse()) == Use.ENCODED;
0150: }
0151:
0152: public Set getWrapperElementQNames() throws DeploymentException {
0153: buildOperationDesc();
0154:
0155: return Collections.unmodifiableSet(wrapperElementQNames);
0156: }
0157:
0158: public boolean isEncoded() {
0159: return isEncoded;
0160: }
0161:
0162: public OperationInfo buildOperationInfo(SOAPConstants soapVersion)
0163: throws DeploymentException {
0164: buildOperationDesc();
0165:
0166: String soapActionURI = soapOperation.getSoapActionURI();
0167: boolean usesSOAPAction = (soapActionURI != null);
0168: QName operationQName = getOperationQName();
0169:
0170: String methodName = methodMapping.getJavaMethodName()
0171: .getStringValue().trim();
0172:
0173: ArrayList parameters = operationDesc.getParameters();
0174: Type[] parameterASMTypes = new Type[parameters.size()];
0175: for (int i = 0; i < parameters.size(); i++) {
0176: ParameterDesc parameterDesc = (ParameterDesc) parameters
0177: .get(i);
0178: parameterASMTypes[i] = Type.getType(parameterDesc
0179: .getJavaType());
0180: }
0181:
0182: Type returnASMType = (operationDesc.getReturnClass() != null) ? Type
0183: .getType(operationDesc.getReturnClass())
0184: : Type.VOID_TYPE;
0185:
0186: String methodDesc = Type.getMethodDescriptor(returnASMType,
0187: parameterASMTypes);
0188: OperationInfo operationInfo = new OperationInfo(operationDesc,
0189: usesSOAPAction, soapActionURI, soapVersion,
0190: operationQName, methodName, methodDesc);
0191: return operationInfo;
0192: }
0193:
0194: private QName getOperationQName() {
0195: if (wrappedStyle) {
0196: Map parts = operation.getInput().getMessage().getParts();
0197: if (parts != null && !parts.isEmpty()) {
0198: for (Iterator iterator = parts.values().iterator(); iterator
0199: .hasNext();) {
0200: Part part = (Part) iterator.next();
0201: return part.getElementName();
0202: }
0203: }
0204: }
0205: return getOperationNameFromSOAPBody();
0206:
0207: }
0208:
0209: public OperationDesc buildOperationDesc()
0210: throws DeploymentException {
0211: if (built) {
0212: return operationDesc;
0213: }
0214: built = true;
0215:
0216: operationDesc.setName(operationName);
0217:
0218: // Set to 'document', 'rpc' or 'wrapped'
0219: if (wrappedStyle) {
0220: operationDesc.setStyle(Style.WRAPPED);
0221: } else if (rpcStyle) {
0222: operationDesc.setStyle(Style.RPC);
0223: } else {
0224: operationDesc.setStyle(Style.DOCUMENT);
0225: }
0226:
0227: // Set to 'encoded' or 'literal'
0228: Use use = Use.getUse(soapBody.getUse());
0229: operationDesc.setUse(use);
0230:
0231: MethodParamPartsMappingType[] paramMappings = methodMapping
0232: .getMethodParamPartsMappingArray();
0233:
0234: /* Put the ParameterDesc instance in an array so they can be ordered properly
0235: * before they are added to the the OperationDesc.
0236: */
0237: ParameterDesc[] parameterDescriptions = new ParameterDesc[paramMappings.length];
0238:
0239: // MAP PARAMETERS
0240: for (int i = 0; i < paramMappings.length; i++) {
0241: MethodParamPartsMappingType paramMapping = paramMappings[i];
0242: int position = paramMapping.getParamPosition()
0243: .getBigIntegerValue().intValue();
0244:
0245: ParameterDesc parameterDesc = mapParameter(paramMapping);
0246:
0247: parameterDescriptions[position] = parameterDesc;
0248: }
0249:
0250: if (wrappedStyle) {
0251: Part inputPart = getWrappedPart(input);
0252: QName name = inputPart.getElementName();
0253: SchemaType operationType = (SchemaType) schemaInfoBuilder
0254: .getComplexTypesInWsdl().get(name);
0255:
0256: Set expectedInParams = new HashSet();
0257:
0258: // schemaType should be complex using xsd:sequence compositor
0259: SchemaParticle parametersType = operationType
0260: .getContentModel();
0261: //parametersType can be null if the element has empty content such as
0262: // <element name="getMarketSummary">
0263: // <complexType>
0264: // <sequence/>
0265: // </complexType>
0266: // </element>
0267:
0268: if (parametersType != null) {
0269: if (SchemaParticle.ELEMENT == parametersType
0270: .getParticleType()) {
0271: expectedInParams.add(parametersType.getName()
0272: .getLocalPart());
0273: } else if (SchemaParticle.SEQUENCE == parametersType
0274: .getParticleType()) {
0275: SchemaParticle[] parameters = parametersType
0276: .getParticleChildren();
0277: for (int i = 0; i < parameters.length; i++) {
0278: expectedInParams.add(parameters[i].getName()
0279: .getLocalPart());
0280: }
0281: }
0282: }
0283: if (!inParamNames.equals(expectedInParams)) {
0284: throw new DeploymentException(
0285: "Not all wrapper children were mapped for operation name"
0286: + operationName);
0287: }
0288: } else {
0289: //check that all input message parts are mapped
0290: if (!inParamNames.equals(input.getParts().keySet())) {
0291: throw new DeploymentException(
0292: "Not all input message parts were mapped for operation name"
0293: + operationName);
0294: }
0295: }
0296:
0297: Class[] paramTypes = new Class[parameterDescriptions.length];
0298: for (int i = 0; i < parameterDescriptions.length; i++) {
0299: ParameterDesc parameterDescription = parameterDescriptions[i];
0300: if (parameterDescription == null) {
0301: throw new DeploymentException(
0302: "There is no mapping for parameter number " + i
0303: + " for operation " + operationName);
0304: }
0305: operationDesc.addParameter(parameterDescription);
0306: paramTypes[i] = parameterDescription.getJavaType();
0307: }
0308:
0309: String methodName = methodMapping.getJavaMethodName()
0310: .getStringValue().trim();
0311: Method method = null;
0312: try {
0313: method = serviceEndpointInterface.getMethod(methodName,
0314: paramTypes);
0315: } catch (NoSuchMethodException e) {
0316: String args = "(";
0317: for (int i = 0; i < paramTypes.length; i++) {
0318: args += paramTypes[i].getName();
0319: if (i < paramTypes.length - 1) {
0320: args += ",";
0321: }
0322: }
0323: args += ")";
0324:
0325: throw new DeploymentException(
0326: "Mapping references non-existent method in service-endpoint: "
0327: + methodName + args);
0328: }
0329:
0330: operationDesc.setMethod(method);
0331:
0332: // MAP RETURN TYPE
0333: operationDesc.setMep(operation.getStyle());
0334: if (methodMapping.isSetWsdlReturnValueMapping()) {
0335: mapReturnType();
0336: } else if (operation.getStyle() == OperationType.REQUEST_RESPONSE) {
0337: //TODO WARNING THIS APPEARS TO SUBVERT THE COMMENT IN j2ee_jaxrpc_mapping_1_1.xsd IN service-endpoint-method-mappingType:
0338: //The wsdl-return-value-mapping is not specified for one-way operations.
0339: operationDesc.setReturnQName(null); //??
0340: operationDesc.setReturnType(XMLType.AXIS_VOID);
0341: operationDesc.setReturnClass(void.class);
0342: }
0343:
0344: if (null != output && wrappedStyle) {
0345: Part inputPart = getWrappedPart(output);
0346: QName name = inputPart.getElementName();
0347: SchemaType operationType = (SchemaType) schemaInfoBuilder
0348: .getComplexTypesInWsdl().get(name);
0349:
0350: Set expectedOutParams = new HashSet();
0351:
0352: // schemaType should be complex using xsd:sequence compositor
0353: SchemaParticle parametersType = operationType
0354: .getContentModel();
0355: //again, no output can give null parametersType
0356: if (parametersType != null) {
0357: if (SchemaParticle.ELEMENT == parametersType
0358: .getParticleType()) {
0359: expectedOutParams.add(parametersType.getName()
0360: .getLocalPart());
0361: } else if (SchemaParticle.SEQUENCE == parametersType
0362: .getParticleType()) {
0363: SchemaParticle[] parameters = parametersType
0364: .getParticleChildren();
0365: for (int i = 0; i < parameters.length; i++) {
0366: expectedOutParams.add(parameters[i].getName()
0367: .getLocalPart());
0368: }
0369: }
0370: }
0371: if (!outParamNames.equals(expectedOutParams)) {
0372: throw new DeploymentException(
0373: "Not all wrapper children were mapped to parameters or a return value for operation "
0374: + operationName);
0375: }
0376: } else if (null != output) {
0377: if (!outParamNames.equals(output.getParts().keySet())) {
0378: throw new DeploymentException(
0379: "Not all output message parts were mapped to parameters or a return value for operation "
0380: + operationName);
0381: }
0382: }
0383:
0384: Map faultMap = operation.getFaults();
0385: for (Iterator iterator = faultMap.entrySet().iterator(); iterator
0386: .hasNext();) {
0387: Map.Entry entry = (Map.Entry) iterator.next();
0388: String faultName = (String) entry.getKey();
0389: Fault fault = (Fault) entry.getValue();
0390: FaultDesc faultDesc = mapException(faultName, fault);
0391:
0392: operationDesc.addFault(faultDesc);
0393: }
0394: return operationDesc;
0395: }
0396:
0397: //see jaxrpc 1.1 4.2.1
0398: private static final Map qnameToClassMap = new HashMap();
0399:
0400: static {
0401: qnameToClassMap.put(new QName(
0402: "http://www.w3.org/2001/XMLSchema", "string"),
0403: String.class);
0404: qnameToClassMap.put(new QName(
0405: "http://www.w3.org/2001/XMLSchema", "integer"),
0406: BigInteger.class);
0407: qnameToClassMap.put(new QName(
0408: "http://www.w3.org/2001/XMLSchema", "int"), int.class);
0409: qnameToClassMap
0410: .put(new QName("http://www.w3.org/2001/XMLSchema",
0411: "long"), long.class);
0412: qnameToClassMap.put(new QName(
0413: "http://www.w3.org/2001/XMLSchema", "short"),
0414: short.class);
0415: qnameToClassMap.put(new QName(
0416: "http://www.w3.org/2001/XMLSchema", "decimal"),
0417: BigDecimal.class);
0418: qnameToClassMap.put(new QName(
0419: "http://www.w3.org/2001/XMLSchema", "float"),
0420: float.class);
0421: qnameToClassMap.put(new QName(
0422: "http://www.w3.org/2001/XMLSchema", "double"),
0423: double.class);
0424: qnameToClassMap.put(new QName(
0425: "http://www.w3.org/2001/XMLSchema", "boolean"),
0426: boolean.class);
0427: qnameToClassMap
0428: .put(new QName("http://www.w3.org/2001/XMLSchema",
0429: "byte"), byte.class);
0430: qnameToClassMap.put(new QName(
0431: "http://www.w3.org/2001/XMLSchema", "unsignedInt"),
0432: long.class);
0433: qnameToClassMap.put(new QName(
0434: "http://www.w3.org/2001/XMLSchema", "unsignedShort"),
0435: int.class);
0436: qnameToClassMap.put(new QName(
0437: "http://www.w3.org/2001/XMLSchema", "unsignedByte"),
0438: short.class);
0439: qnameToClassMap.put(new QName(
0440: "http://www.w3.org/2001/XMLSchema", "QName"),
0441: QName.class);
0442: qnameToClassMap.put(new QName(
0443: "http://www.w3.org/2001/XMLSchema", "dateTime"),
0444: Calendar.class);
0445: qnameToClassMap.put(new QName(
0446: "http://www.w3.org/2001/XMLSchema", "date"),
0447: Calendar.class);
0448: qnameToClassMap.put(new QName(
0449: "http://www.w3.org/2001/XMLSchema", "time"),
0450: Calendar.class);
0451: qnameToClassMap.put(new QName(
0452: "http://www.w3.org/2001/XMLSchema", "anyURI"),
0453: URI.class);
0454: qnameToClassMap.put(new QName(
0455: "http://www.w3.org/2001/XMLSchema", "base64Binary"),
0456: byte[].class);
0457: qnameToClassMap.put(new QName(
0458: "http://www.w3.org/2001/XMLSchema", "hexBinary"),
0459: byte[].class);
0460: qnameToClassMap.put(new QName(
0461: "http://www.w3.org/2001/XMLSchema", "anySimpleType"),
0462: String.class);
0463: }
0464:
0465: private FaultDesc mapException(String faultName, Fault fault)
0466: throws DeploymentException {
0467: Message message = fault.getMessage();
0468: QName messageQName = message.getQName();
0469: ExceptionMappingType exceptionMapping = (ExceptionMappingType) exceptionMap
0470: .get(messageQName);
0471: if (exceptionMapping == null) {
0472: throw new DeploymentException(
0473: "No exception mapping for fault " + faultName
0474: + " and fault message " + messageQName
0475: + " for operation " + operationName);
0476: }
0477: String className = exceptionMapping.getExceptionType()
0478: .getStringValue().trim();
0479: //TODO investigate whether there are other cases in which the namespace of faultQName can be determined.
0480: //this is weird, but I can't figure out what it should be.
0481: //if part has an element rather than a type, it should be part.getElementName() (see below)
0482: QName faultQName = new QName("", faultName);
0483: Part part;
0484: if (exceptionMapping.isSetWsdlMessagePartName()) {
0485: //According to schema documentation, this will only be set when several headerfaults use the same message.
0486: String headerFaultMessagePartName = exceptionMapping
0487: .getWsdlMessagePartName().getStringValue();
0488: part = message.getPart(headerFaultMessagePartName);
0489: } else {
0490: part = (Part) message.getOrderedParts(null).iterator()
0491: .next();
0492: }
0493: QName faultTypeQName;// = part.getElementName() == null ? part.getTypeName() : part.getElementName();
0494: if (part.getElementName() == null) {
0495: faultTypeQName = part.getTypeName();
0496: if (faultTypeQName == null) {
0497: throw new DeploymentException(
0498: "Neither type nor element name supplied for part: "
0499: + part);
0500: }
0501: } else {
0502: faultQName = part.getElementName();
0503: faultTypeQName = (QName) schemaInfoBuilder
0504: .getElementToTypeMap().get(part.getElementName());
0505: if (faultTypeQName == null) {
0506: throw new DeploymentException(
0507: "Can not find type for: element: "
0508: + part.getElementName()
0509: + ", known elements: "
0510: + schemaInfoBuilder
0511: .getElementToTypeMap());
0512: }
0513: }
0514: SchemaType complexType = (SchemaType) schemaInfoBuilder
0515: .getComplexTypesInWsdl().get(faultTypeQName);
0516: boolean isComplex = complexType != null;
0517: FaultDesc faultDesc = new FaultDesc(faultQName, className,
0518: faultTypeQName, isComplex);
0519:
0520: //constructor parameters
0521: if (exceptionMapping.isSetConstructorParameterOrder()) {
0522: if (!isComplex) {
0523: throw new DeploymentException(
0524: "ConstructorParameterOrder can only be set for complex types, not "
0525: + faultTypeQName);
0526: }
0527: Map elementMap = new HashMap();
0528: SchemaProperty[] properties = complexType.getProperties();
0529: for (int i = 0; i < properties.length; i++) {
0530: SchemaProperty property = properties[i];
0531: QName elementName = property.getName();
0532: SchemaType elementType = property.getType();
0533: elementMap.put(elementName.getLocalPart(), elementType);
0534: }
0535: ArrayList parameterTypes = new ArrayList();
0536: ConstructorParameterOrderType constructorParameterOrder = exceptionMapping
0537: .getConstructorParameterOrder();
0538: for (int i = 0; i < constructorParameterOrder
0539: .getElementNameArray().length; i++) {
0540: String elementName = constructorParameterOrder
0541: .getElementNameArray(i).getStringValue().trim();
0542: SchemaType elementType = (SchemaType) elementMap
0543: .get(elementName);
0544: Class javaElementType;
0545:
0546: QName elementTypeQName = elementType.getName();
0547: if (elementTypeQName != null) {
0548: if (schemaInfoBuilder.getComplexTypesInWsdl()
0549: .containsKey(elementType)) {
0550: String javaClassName = (String) publicTypes
0551: .get(elementTypeQName);
0552: if (javaClassName == null) {
0553: throw new DeploymentException(
0554: "No class mapped for element type: "
0555: + elementType);
0556: }
0557: javaElementType = getJavaClass(javaClassName);
0558: } else {
0559: javaElementType = (Class) qnameToClassMap
0560: .get(elementTypeQName);
0561: if (javaElementType == null) {
0562: throw new DeploymentException(
0563: "Unknown type: " + elementType
0564: + " of name: "
0565: + elementName
0566: + " and QName: "
0567: + elementTypeQName);
0568: }
0569: }
0570: } else {
0571: //anonymous type
0572: //anonymous type qname is constructed using rules 1.b and 2.b
0573: String anonymousQName = complexType.getName()
0574: .getNamespaceURI()
0575: + ":>"
0576: + complexType.getName().getLocalPart()
0577: + ">" + elementName;
0578: String javaClassName = (String) anonymousTypes
0579: .get(anonymousQName);
0580: if (javaClassName == null) {
0581: if (elementType.isSimpleType()) {
0582: //maybe it's a restriction of a built in simple type
0583: SchemaType baseType = elementType
0584: .getBaseType();
0585: QName simpleTypeQName = baseType.getName();
0586: javaElementType = (Class) qnameToClassMap
0587: .get(simpleTypeQName);
0588: if (javaElementType == null) {
0589: throw new DeploymentException(
0590: "Unknown simple type: "
0591: + elementType
0592: + " of name: "
0593: + elementName
0594: + " and QName: "
0595: + simpleTypeQName);
0596: }
0597: } else {
0598: throw new DeploymentException(
0599: "No class mapped for anonymous type: "
0600: + anonymousQName);
0601: }
0602: } else {
0603: javaElementType = getJavaClass(javaClassName);
0604: }
0605: }
0606: //todo faultTypeQName is speculative
0607: //todo outheader might be true!
0608: ParameterDesc parameterDesc = new ParameterDesc(
0609: faultTypeQName, ParameterDesc.OUT,
0610: elementTypeQName, javaElementType, false, false);
0611: parameterTypes.add(parameterDesc);
0612: }
0613: faultDesc.setParameters(parameterTypes);
0614: }
0615: return faultDesc;
0616: }
0617:
0618: private Class getJavaClass(String javaClassName)
0619: throws DeploymentException {
0620: try {
0621: Class javaClass = ClassLoading.loadClass(javaClassName,
0622: classLoader);
0623: return javaClass;
0624: } catch (ClassNotFoundException e) {
0625: throw new DeploymentException("Could not load class", e);
0626: }
0627: }
0628:
0629: private void mapReturnType() throws DeploymentException {
0630: QName returnType = null;
0631: QName returnQName = null;
0632: Class returnClass = null;
0633:
0634: if (output == null) {
0635: throw new DeploymentException(
0636: "No output message, but a mapping for it for operation "
0637: + operationName);
0638: }
0639: WsdlReturnValueMappingType wsdlReturnValueMapping = methodMapping
0640: .getWsdlReturnValueMapping();
0641: String returnClassName = wsdlReturnValueMapping
0642: .getMethodReturnValue().getStringValue().trim();
0643: try {
0644: returnClass = ClassLoading.loadClass(returnClassName,
0645: classLoader);
0646: } catch (ClassNotFoundException e) {
0647: throw new DeploymentException(
0648: "Could not load return type for operation "
0649: + operationName, e);
0650: }
0651:
0652: QName wsdlMessageQName = wsdlReturnValueMapping
0653: .getWsdlMessage().getQNameValue();
0654:
0655: if (!wsdlMessageQName.equals(output.getQName())) {
0656: throw new DeploymentException("OutputMessage has QName: "
0657: + output.getQName() + " but mapping specifies: "
0658: + wsdlMessageQName + " for operation "
0659: + operationName);
0660: }
0661:
0662: if (wsdlReturnValueMapping.isSetWsdlMessagePartName()) {
0663: String wsdlMessagePartName = wsdlReturnValueMapping
0664: .getWsdlMessagePartName().getStringValue().trim();
0665: if (outParamNames.contains(wsdlMessagePartName)) {
0666: throw new DeploymentException(
0667: "output message part "
0668: + wsdlMessagePartName
0669: + " has both an INOUT or OUT mapping and a return value mapping for operation "
0670: + operationName);
0671: }
0672:
0673: if (wrappedStyle) {
0674: Part outPart = getWrappedPart(output);
0675: SchemaParticle returnParticle = getWrapperChild(
0676: outPart, wsdlMessagePartName);
0677: //TODO this makes little sense but may be correct, see comments in axis Parameter class
0678: //the part name qname is really odd.
0679: returnQName = new QName("", returnParticle.getName()
0680: .getLocalPart());
0681: returnType = returnParticle.getType().getName();
0682: } else if (rpcStyle) {
0683: Part part = output.getPart(wsdlMessagePartName);
0684: if (part == null) {
0685: throw new DeploymentException(
0686: "No part for wsdlMessagePartName "
0687: + wsdlMessagePartName
0688: + " in output message for operation "
0689: + operationName);
0690: }
0691: returnQName = new QName("", part.getName());
0692: returnType = part.getTypeName();
0693: } else {
0694: Part part = output.getPart(wsdlMessagePartName);
0695: if (part == null) {
0696: throw new DeploymentException(
0697: "No part for wsdlMessagePartName "
0698: + wsdlMessagePartName
0699: + " in output message for operation "
0700: + operationName);
0701: }
0702: returnQName = getPartName(part);
0703: returnType = returnQName;
0704: }
0705:
0706: outParamNames.add(wsdlMessagePartName);
0707: } else {
0708: //what does this mean????
0709: }
0710:
0711: operationDesc.setReturnQName(returnQName);
0712: operationDesc.setReturnType(returnType);
0713: operationDesc.setReturnClass(returnClass);
0714: }
0715:
0716: private ParameterDesc mapParameter(
0717: MethodParamPartsMappingType paramMapping)
0718: throws DeploymentException {
0719: WsdlMessageMappingType wsdlMessageMappingType = paramMapping
0720: .getWsdlMessageMapping();
0721: QName wsdlMessageQName = wsdlMessageMappingType
0722: .getWsdlMessage().getQNameValue();
0723: String wsdlMessagePartName = wsdlMessageMappingType
0724: .getWsdlMessagePartName().getStringValue().trim();
0725:
0726: String parameterMode = wsdlMessageMappingType
0727: .getParameterMode().getStringValue().trim();
0728: byte mode = ParameterDesc.modeFromString(parameterMode);
0729: boolean isInParam = mode == ParameterDesc.IN
0730: || mode == ParameterDesc.INOUT;
0731: boolean isOutParam = mode == ParameterDesc.OUT
0732: || mode == ParameterDesc.INOUT;
0733:
0734: if (isOutParam && output == null) {
0735: throw new DeploymentException(
0736: "Mapping for output parameter "
0737: + wsdlMessagePartName
0738: + " found, but no output message for operation "
0739: + operationName);
0740: }
0741: boolean isSoapHeader = wsdlMessageMappingType.isSetSoapHeader();
0742: boolean inHeader = isSoapHeader && isInParam;
0743: boolean outHeader = isSoapHeader && isOutParam;
0744:
0745: QName paramQName;
0746: QName paramTypeQName;
0747:
0748: Part part = null;
0749: SchemaParticle inParameter = null;
0750: if (isInParam) {
0751: if (!wsdlMessageQName.equals(input.getQName())) {
0752: throw new DeploymentException(
0753: "QName of input message: "
0754: + input.getQName()
0755: + " does not match mapping message QName: "
0756: + wsdlMessageQName + " for operation "
0757: + operationName);
0758: }
0759: if (wrappedStyle) {
0760: Part inPart = getWrappedPart(input);
0761: // the local name of the global element refered by the part is equal to the operation name
0762: QName name = inPart.getElementName();
0763: if (false == name.getLocalPart().equals(operationName)) {
0764: throw new DeploymentException(
0765: "message "
0766: + input.getQName()
0767: + " refers to a global element named "
0768: + name.getLocalPart()
0769: + ", which is not equal to the operation name "
0770: + operationName);
0771: }
0772: inParameter = getWrapperChild(inPart,
0773: wsdlMessagePartName);
0774: //TODO this makes little sense but may be correct, see comments in axis Parameter class
0775: //the part name qname is really odd.
0776: paramQName = new QName("", inParameter.getName()
0777: .getLocalPart());
0778: paramTypeQName = inParameter.getType().getName();
0779: } else if (rpcStyle) {
0780: part = input.getPart(wsdlMessagePartName);
0781: if (part == null) {
0782: throw new DeploymentException(
0783: "No part for wsdlMessagePartName "
0784: + wsdlMessagePartName
0785: + " in input message for operation "
0786: + operationName);
0787: }
0788: //TODO this makes little sense but may be correct, see comments in axis Parameter class
0789: //the part name qname is really odd.
0790: paramQName = new QName("", part.getName());
0791: paramTypeQName = part.getTypeName();
0792: } else {
0793: part = input.getPart(wsdlMessagePartName);
0794: if (part == null) {
0795: throw new DeploymentException(
0796: "No part for wsdlMessagePartName "
0797: + wsdlMessagePartName
0798: + " in input message for operation "
0799: + operationName);
0800: }
0801: paramQName = getPartName(part);
0802: paramTypeQName = paramQName;
0803: }
0804: inParamNames.add(wsdlMessagePartName);
0805: if (isOutParam) {
0806: if (wrappedStyle) {
0807: Part outPart = getWrappedPart(output);
0808: SchemaParticle outParameter = getWrapperChild(
0809: outPart, wsdlMessagePartName);
0810: if (inParameter.getType() != outParameter.getType()) {
0811: throw new DeploymentException(
0812: "The wrapper children "
0813: + wsdlMessagePartName
0814: + " do not have the same type for operation "
0815: + operationName);
0816: }
0817: } else if (rpcStyle) {
0818: //inout, check that part of same name and type is in output message
0819: Part outPart = output.getPart(wsdlMessagePartName);
0820: if (outPart == null) {
0821: throw new DeploymentException(
0822: "No part for wsdlMessagePartName "
0823: + wsdlMessagePartName
0824: + " in output message for INOUT parameter of operation "
0825: + operationName);
0826: }
0827: // TODO this cannot happen.
0828: if (!part.getName().equals(outPart.getName())) {
0829: throw new DeploymentException(
0830: "Mismatched input part name: "
0831: + part.getName()
0832: + " and output part name: "
0833: + outPart.getName()
0834: + " for INOUT parameter for wsdlMessagePartName "
0835: + wsdlMessagePartName
0836: + " for operation "
0837: + operationName);
0838: }
0839: if (!(part.getElementName() == null ? outPart
0840: .getElementName() == null : part
0841: .getElementName().equals(
0842: outPart.getElementName()))) {
0843: throw new DeploymentException(
0844: "Mismatched input part element name: "
0845: + part.getElementName()
0846: + " and output part element name: "
0847: + outPart.getElementName()
0848: + " for INOUT parameter for wsdlMessagePartName "
0849: + wsdlMessagePartName
0850: + " for operation "
0851: + operationName);
0852: }
0853: if (!(part.getTypeName() == null ? outPart
0854: .getTypeName() == null : part.getTypeName()
0855: .equals(outPart.getTypeName()))) {
0856: throw new DeploymentException(
0857: "Mismatched input part type name: "
0858: + part.getTypeName()
0859: + " and output part type name: "
0860: + outPart.getTypeName()
0861: + " for INOUT parameter for wsdlMessagePartName "
0862: + wsdlMessagePartName
0863: + " for operation "
0864: + operationName);
0865: }
0866: } else {
0867: part = output.getPart(wsdlMessagePartName);
0868: if (part == null) {
0869: throw new DeploymentException(
0870: "No part for wsdlMessagePartName "
0871: + wsdlMessagePartName
0872: + " in output message for operation "
0873: + operationName);
0874: }
0875: paramQName = getPartName(part);
0876: paramTypeQName = paramQName;
0877: }
0878: outParamNames.add(wsdlMessagePartName);
0879: }
0880: } else if (isOutParam) {
0881: if (!wsdlMessageQName.equals(output.getQName())) {
0882: throw new DeploymentException(
0883: "QName of output message: "
0884: + output.getQName()
0885: + " does not match mapping message QName: "
0886: + wsdlMessageQName + " for operation "
0887: + operationName);
0888: }
0889: if (wrappedStyle) {
0890: Part outPart = getWrappedPart(output);
0891: SchemaParticle outParameter = getWrapperChild(outPart,
0892: wsdlMessagePartName);
0893: //TODO this makes little sense but may be correct, see comments in axis Parameter class
0894: //the part name qname is really odd.
0895: paramQName = new QName("", outParameter.getName()
0896: .getLocalPart());
0897: paramTypeQName = outParameter.getType().getName();
0898: } else if (rpcStyle) {
0899: part = output.getPart(wsdlMessagePartName);
0900: if (part == null) {
0901: throw new DeploymentException(
0902: "No part for wsdlMessagePartName "
0903: + wsdlMessagePartName
0904: + " in output message for operation "
0905: + operationName);
0906: }
0907: //TODO this makes little sense but may be correct, see comments in axis Parameter class
0908: //the part name qname is really odd.
0909: paramQName = new QName("", part.getName());
0910: paramTypeQName = part.getTypeName();
0911: } else {
0912: part = output.getPart(wsdlMessagePartName);
0913: if (part == null) {
0914: throw new DeploymentException(
0915: "No part for wsdlMessagePartName "
0916: + wsdlMessagePartName
0917: + " in output message for operation "
0918: + operationName);
0919: }
0920: paramQName = getPartName(part);
0921: paramTypeQName = paramQName;
0922: }
0923: outParamNames.add(wsdlMessagePartName);
0924: } else {
0925: throw new AssertionError(
0926: "a param mapping has to be IN or OUT or INOUT");
0927: }
0928:
0929: //use complexTypeMap
0930: boolean isComplexType = schemaInfoBuilder
0931: .getComplexTypesInWsdl().containsKey(paramTypeQName);
0932: String paramJavaTypeName = paramMapping.getParamType()
0933: .getStringValue().trim();
0934: boolean isInOnly = mode == ParameterDesc.IN;
0935: Class actualParamJavaType = WSDescriptorParser.getHolderType(
0936: paramJavaTypeName, isInOnly, paramTypeQName,
0937: isComplexType, mapping, classLoader);
0938:
0939: ParameterDesc parameterDesc = new ParameterDesc(paramQName,
0940: mode, paramTypeQName, actualParamJavaType, inHeader,
0941: outHeader);
0942: return parameterDesc;
0943: }
0944:
0945: private QName getPartName(Part part) {
0946: return null == part.getElementName() ? part.getTypeName()
0947: : part.getElementName();
0948: }
0949:
0950: private Part getWrappedPart(Message message)
0951: throws DeploymentException {
0952: // in case of wrapped element, the message has only one part.
0953: Collection parts = message.getParts().values();
0954: if (1 != parts.size()) {
0955: throw new DeploymentException(
0956: "message "
0957: + message.getQName()
0958: + " has "
0959: + parts.size()
0960: + " parts and should only have one as wrapper style mapping is specified for operation "
0961: + operationName);
0962: }
0963: return (Part) parts.iterator().next();
0964: }
0965:
0966: private SchemaParticle getWrapperChild(Part part,
0967: String wsdlMessagePartName) throws DeploymentException {
0968: QName name = part.getElementName();
0969:
0970: wrapperElementQNames.add(name);
0971:
0972: SchemaType operationType = (SchemaType) schemaInfoBuilder
0973: .getComplexTypesInWsdl().get(name);
0974: if (null == operationType) {
0975: throw new DeploymentException("No global element named "
0976: + name + " for operation " + operationName);
0977: }
0978:
0979: // schemaType should be complex using xsd:sequence compositor
0980: SchemaParticle parametersType = operationType.getContentModel();
0981: if (SchemaParticle.ELEMENT == parametersType.getParticleType()) {
0982: if (parametersType.getName().getLocalPart().equals(
0983: wsdlMessagePartName)) {
0984: return parametersType;
0985: }
0986: throw new DeploymentException("Global element named "
0987: + name + " does not define a child element named "
0988: + wsdlMessagePartName
0989: + " required by the operation " + operationName);
0990: } else if (SchemaParticle.SEQUENCE == parametersType
0991: .getParticleType()) {
0992: SchemaParticle[] parameters = parametersType
0993: .getParticleChildren();
0994: for (int i = 0; i < parameters.length; i++) {
0995: SchemaParticle parameter = parameters[i];
0996: QName element = parameter.getName();
0997: if (element.getLocalPart().equals(wsdlMessagePartName)) {
0998: return parameter;
0999: }
1000: }
1001: throw new DeploymentException("Global element named "
1002: + name + " does not define a child element named "
1003: + wsdlMessagePartName
1004: + " required by the operation " + operationName);
1005: } else {
1006: throw new DeploymentException("Global element named "
1007: + name + " is not a sequence for operation "
1008: + operationName);
1009: }
1010: }
1011:
1012: /**
1013: * Supporting the Document/Literal Wrapped pattern
1014: *
1015: * See http://www-106.ibm.com/developerworks/webservices/library/ws-whichwsdl/ for a nice explanation and example
1016: *
1017: * wrapped-element tag is used
1018: * WSDL message with a single part
1019: * part uses the 'element' attribute to point to an elemement in the types section
1020: * the element type and the element's name match the operation name
1021: */
1022: }
|