001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * 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, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.geronimo.axis.builder; 019 020 import java.lang.reflect.Method; 021 import java.math.BigDecimal; 022 import java.math.BigInteger; 023 import java.net.URI; 024 import java.util.ArrayList; 025 import java.util.Calendar; 026 import java.util.Collection; 027 import java.util.Collections; 028 import java.util.HashMap; 029 import java.util.HashSet; 030 import java.util.Iterator; 031 import java.util.Map; 032 import java.util.Set; 033 034 import javax.wsdl.BindingInput; 035 import javax.wsdl.BindingOperation; 036 import javax.wsdl.Fault; 037 import javax.wsdl.Message; 038 import javax.wsdl.Part; 039 import javax.wsdl.OperationType; 040 import javax.wsdl.extensions.soap.SOAPBody; 041 import javax.xml.namespace.QName; 042 043 import org.apache.axis.constants.Style; 044 import org.apache.axis.constants.Use; 045 import org.apache.axis.description.FaultDesc; 046 import org.apache.axis.description.OperationDesc; 047 import org.apache.axis.description.ParameterDesc; 048 import org.apache.axis.soap.SOAPConstants; 049 import org.apache.axis.encoding.XMLType; 050 import org.apache.geronimo.axis.client.OperationInfo; 051 import org.apache.geronimo.common.DeploymentException; 052 import org.apache.geronimo.kernel.ClassLoading; 053 import org.apache.geronimo.xbeans.j2ee.ConstructorParameterOrderType; 054 import org.apache.geronimo.xbeans.j2ee.ExceptionMappingType; 055 import org.apache.geronimo.xbeans.j2ee.JavaWsdlMappingType; 056 import org.apache.geronimo.xbeans.j2ee.MethodParamPartsMappingType; 057 import org.apache.geronimo.xbeans.j2ee.ServiceEndpointMethodMappingType; 058 import org.apache.geronimo.xbeans.j2ee.WsdlMessageMappingType; 059 import org.apache.geronimo.xbeans.j2ee.WsdlReturnValueMappingType; 060 import org.apache.xmlbeans.SchemaParticle; 061 import org.apache.xmlbeans.SchemaProperty; 062 import org.apache.xmlbeans.SchemaType; 063 import org.objectweb.asm.Type; 064 import org.apache.geronimo.xbeans.j2ee.JavaXmlTypeMappingType; 065 import org.apache.geronimo.webservices.builder.SchemaInfoBuilder; 066 import org.apache.geronimo.webservices.builder.WSDescriptorParser; 067 068 /** 069 * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $ 070 */ 071 public class HeavyweightOperationDescBuilder extends OperationDescBuilder { 072 073 private final JavaWsdlMappingType mapping; 074 private final ServiceEndpointMethodMappingType methodMapping; 075 private final SOAPBody soapBody; 076 077 078 private final Map exceptionMap; 079 private final SchemaInfoBuilder schemaInfoBuilder; 080 private final ClassLoader classLoader; 081 private final boolean rpcStyle; 082 private final boolean documentStyle; 083 private final boolean wrappedStyle; 084 private final boolean isEncoded; 085 private final Map publicTypes = new HashMap(); 086 private final Map anonymousTypes = new HashMap(); 087 088 /* Keep track of in and out parameter names so we can verify that 089 * everything has been mapped and mapped correctly 090 */ 091 private final Set inParamNames = new HashSet(); 092 private final Set outParamNames = new HashSet(); 093 private final Class serviceEndpointInterface; 094 095 /** 096 * Track the wrapper elements 097 */ 098 private final Set wrapperElementQNames = new HashSet(); 099 100 public HeavyweightOperationDescBuilder(BindingOperation bindingOperation, JavaWsdlMappingType mapping, ServiceEndpointMethodMappingType methodMapping, Style defaultStyle, Map exceptionMap, SchemaInfoBuilder schemaInfoBuilder, JavaXmlTypeMappingType[] javaXmlTypeMappingTypes, ClassLoader classLoader, Class serviceEndpointInterface) throws DeploymentException { 101 super(bindingOperation); 102 this.mapping = mapping; 103 this.methodMapping = methodMapping; 104 this.exceptionMap = exceptionMap; 105 this.schemaInfoBuilder = schemaInfoBuilder; 106 for (int i = 0; i < javaXmlTypeMappingTypes.length; i++) { 107 JavaXmlTypeMappingType javaXmlTypeMappingType = javaXmlTypeMappingTypes[i]; 108 String javaClassName = javaXmlTypeMappingType.getJavaType().getStringValue().trim(); 109 if (javaXmlTypeMappingType.isSetAnonymousTypeQname()) { 110 String anonymousTypeQName = javaXmlTypeMappingType.getAnonymousTypeQname().getStringValue().trim(); 111 anonymousTypes.put(anonymousTypeQName, javaClassName); 112 } else if (javaXmlTypeMappingType.isSetRootTypeQname()) { 113 QName qname = javaXmlTypeMappingType.getRootTypeQname().getQNameValue(); 114 publicTypes.put(qname, javaClassName); 115 } 116 } 117 this.classLoader = classLoader; 118 this.serviceEndpointInterface = serviceEndpointInterface; 119 BindingInput bindingInput = bindingOperation.getBindingInput(); 120 this.soapBody = (SOAPBody) SchemaInfoBuilder.getExtensibilityElement(SOAPBody.class, bindingInput.getExtensibilityElements()); 121 122 wrappedStyle = methodMapping.isSetWrappedElement(); 123 if (false == wrappedStyle) { 124 Style style = Style.getStyle(soapOperation.getStyle(), defaultStyle); 125 if (style == Style.RPC) { 126 rpcStyle = true; 127 documentStyle = false; 128 } else { 129 rpcStyle = false; 130 documentStyle = true; 131 } 132 } else { 133 rpcStyle = false; 134 documentStyle = false; 135 } 136 isEncoded = Use.getUse(soapBody.getUse()) == Use.ENCODED; 137 } 138 139 public Set getWrapperElementQNames() throws DeploymentException { 140 buildOperationDesc(); 141 142 return Collections.unmodifiableSet(wrapperElementQNames); 143 } 144 145 public boolean isEncoded() { 146 return isEncoded; 147 } 148 149 public OperationInfo buildOperationInfo(SOAPConstants soapVersion) throws DeploymentException { 150 buildOperationDesc(); 151 152 String soapActionURI = soapOperation.getSoapActionURI(); 153 boolean usesSOAPAction = (soapActionURI != null); 154 QName operationQName = getOperationQName(); 155 156 String methodName = methodMapping.getJavaMethodName().getStringValue().trim(); 157 158 ArrayList parameters = operationDesc.getParameters(); 159 Type[] parameterASMTypes = new Type[parameters.size()]; 160 for (int i = 0; i < parameters.size(); i++) { 161 ParameterDesc parameterDesc = (ParameterDesc) parameters.get(i); 162 parameterASMTypes[i] = Type.getType(parameterDesc.getJavaType()); 163 } 164 165 Type returnASMType = (operationDesc.getReturnClass() != null) ? Type.getType(operationDesc.getReturnClass()) : Type.VOID_TYPE; 166 167 String methodDesc = Type.getMethodDescriptor(returnASMType, parameterASMTypes); 168 OperationInfo operationInfo = new OperationInfo(operationDesc, usesSOAPAction, soapActionURI, soapVersion, operationQName, methodName, methodDesc); 169 return operationInfo; 170 } 171 172 private QName getOperationQName() { 173 if (wrappedStyle) { 174 Map parts = operation.getInput().getMessage().getParts(); 175 if (parts != null && !parts.isEmpty()) { 176 for (Iterator iterator = parts.values().iterator(); iterator.hasNext();) { 177 Part part = (Part) iterator.next(); 178 return part.getElementName(); 179 } 180 } 181 } 182 return getOperationNameFromSOAPBody(); 183 184 } 185 186 public OperationDesc buildOperationDesc() throws DeploymentException { 187 if (built) { 188 return operationDesc; 189 } 190 built = true; 191 192 operationDesc.setName(operationName); 193 194 // Set to 'document', 'rpc' or 'wrapped' 195 if (wrappedStyle) { 196 operationDesc.setStyle(Style.WRAPPED); 197 } else if (rpcStyle) { 198 operationDesc.setStyle(Style.RPC); 199 } else { 200 operationDesc.setStyle(Style.DOCUMENT); 201 } 202 203 // Set to 'encoded' or 'literal' 204 Use use = Use.getUse(soapBody.getUse()); 205 operationDesc.setUse(use); 206 207 208 MethodParamPartsMappingType[] paramMappings = methodMapping.getMethodParamPartsMappingArray(); 209 210 /* Put the ParameterDesc instance in an array so they can be ordered properly 211 * before they are added to the the OperationDesc. 212 */ 213 ParameterDesc[] parameterDescriptions = new ParameterDesc[paramMappings.length]; 214 215 216 // MAP PARAMETERS 217 for (int i = 0; i < paramMappings.length; i++) { 218 MethodParamPartsMappingType paramMapping = paramMappings[i]; 219 int position = paramMapping.getParamPosition().getBigIntegerValue().intValue(); 220 221 ParameterDesc parameterDesc = mapParameter(paramMapping); 222 223 parameterDescriptions[position] = parameterDesc; 224 } 225 226 if (wrappedStyle) { 227 Part inputPart = getWrappedPart(input); 228 QName name = inputPart.getElementName(); 229 SchemaType operationType = (SchemaType) schemaInfoBuilder.getComplexTypesInWsdl().get(name); 230 231 Set expectedInParams = new HashSet(); 232 233 // schemaType should be complex using xsd:sequence compositor 234 SchemaParticle parametersType = operationType.getContentModel(); 235 //parametersType can be null if the element has empty content such as 236 // <element name="getMarketSummary"> 237 // <complexType> 238 // <sequence/> 239 // </complexType> 240 // </element> 241 242 if (parametersType != null) { 243 if (SchemaParticle.ELEMENT == parametersType.getParticleType()) { 244 expectedInParams.add(parametersType.getName().getLocalPart()); 245 } else if (SchemaParticle.SEQUENCE == parametersType.getParticleType()) { 246 SchemaParticle[] parameters = parametersType.getParticleChildren(); 247 for (int i = 0; i < parameters.length; i++) { 248 expectedInParams.add(parameters[i].getName().getLocalPart()); 249 } 250 } 251 } 252 if (!inParamNames.equals(expectedInParams)) { 253 throw new DeploymentException("Not all wrapper children were mapped for operation name" + operationName); 254 } 255 } else { 256 //check that all input message parts are mapped 257 if (!inParamNames.equals(input.getParts().keySet())) { 258 throw new DeploymentException("Not all input message parts were mapped for operation name" + operationName); 259 } 260 } 261 262 Class[] paramTypes = new Class[parameterDescriptions.length]; 263 for (int i = 0; i < parameterDescriptions.length; i++) { 264 ParameterDesc parameterDescription = parameterDescriptions[i]; 265 if (parameterDescription == null) { 266 throw new DeploymentException("There is no mapping for parameter number " + i + " for operation " + operationName); 267 } 268 operationDesc.addParameter(parameterDescription); 269 paramTypes[i] = parameterDescription.getJavaType(); 270 } 271 272 String methodName = methodMapping.getJavaMethodName().getStringValue().trim(); 273 Method method = null; 274 try { 275 method = serviceEndpointInterface.getMethod(methodName, paramTypes); 276 } catch (NoSuchMethodException e) { 277 String args = "("; 278 for (int i = 0; i < paramTypes.length; i++) { 279 args += paramTypes[i].getName(); 280 if (i < paramTypes.length - 1) { 281 args += ","; 282 } 283 } 284 args += ")"; 285 286 throw new DeploymentException("Mapping references non-existent method in service-endpoint: " + methodName + args); 287 } 288 289 operationDesc.setMethod(method); 290 291 // MAP RETURN TYPE 292 operationDesc.setMep(operation.getStyle()); 293 if (methodMapping.isSetWsdlReturnValueMapping()) { 294 mapReturnType(); 295 } else if (operation.getStyle() == OperationType.REQUEST_RESPONSE) { 296 //TODO WARNING THIS APPEARS TO SUBVERT THE COMMENT IN j2ee_jaxrpc_mapping_1_1.xsd IN service-endpoint-method-mappingType: 297 //The wsdl-return-value-mapping is not specified for one-way operations. 298 operationDesc.setReturnQName(null); //?? 299 operationDesc.setReturnType(XMLType.AXIS_VOID); 300 operationDesc.setReturnClass(void.class); 301 } 302 303 if (null != output && wrappedStyle) { 304 Part inputPart = getWrappedPart(output); 305 QName name = inputPart.getElementName(); 306 SchemaType operationType = (SchemaType) schemaInfoBuilder.getComplexTypesInWsdl().get(name); 307 308 Set expectedOutParams = new HashSet(); 309 310 // schemaType should be complex using xsd:sequence compositor 311 SchemaParticle parametersType = operationType.getContentModel(); 312 //again, no output can give null parametersType 313 if (parametersType != null) { 314 if (SchemaParticle.ELEMENT == parametersType.getParticleType()) { 315 expectedOutParams.add(parametersType.getName().getLocalPart()); 316 } else if (SchemaParticle.SEQUENCE == parametersType.getParticleType()) { 317 SchemaParticle[] parameters = parametersType.getParticleChildren(); 318 for (int i = 0; i < parameters.length; i++) { 319 expectedOutParams.add(parameters[i].getName().getLocalPart()); 320 } 321 } 322 } 323 if (!outParamNames.equals(expectedOutParams)) { 324 throw new DeploymentException("Not all wrapper children were mapped to parameters or a return value for operation " + operationName); 325 } 326 } else if (null != output) { 327 if (!outParamNames.equals(output.getParts().keySet())) { 328 throw new DeploymentException("Not all output message parts were mapped to parameters or a return value for operation " + operationName); 329 } 330 } 331 332 Map faultMap = operation.getFaults(); 333 for (Iterator iterator = faultMap.entrySet().iterator(); iterator.hasNext();) { 334 Map.Entry entry = (Map.Entry) iterator.next(); 335 String faultName = (String) entry.getKey(); 336 Fault fault = (Fault) entry.getValue(); 337 FaultDesc faultDesc = mapException(faultName, fault); 338 339 operationDesc.addFault(faultDesc); 340 } 341 return operationDesc; 342 } 343 344 //see jaxrpc 1.1 4.2.1 345 private static final Map qnameToClassMap = new HashMap(); 346 347 static { 348 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "string"), String.class); 349 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "integer"), BigInteger.class); 350 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "int"), int.class); 351 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "long"), long.class); 352 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "short"), short.class); 353 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "decimal"), BigDecimal.class); 354 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "float"), float.class); 355 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "double"), double.class); 356 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "boolean"), boolean.class); 357 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "byte"), byte.class); 358 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "unsignedInt"), long.class); 359 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "unsignedShort"), int.class); 360 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "unsignedByte"), short.class); 361 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "QName"), QName.class); 362 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "dateTime"), Calendar.class); 363 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "date"), Calendar.class); 364 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "time"), Calendar.class); 365 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "anyURI"), URI.class); 366 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "base64Binary"), byte[].class); 367 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "hexBinary"), byte[].class); 368 qnameToClassMap.put(new QName("http://www.w3.org/2001/XMLSchema", "anySimpleType"), String.class); 369 } 370 371 372 private FaultDesc mapException(String faultName, Fault fault) throws DeploymentException { 373 Message message = fault.getMessage(); 374 QName messageQName = message.getQName(); 375 ExceptionMappingType exceptionMapping = (ExceptionMappingType) exceptionMap.get(messageQName); 376 if (exceptionMapping == null) { 377 throw new DeploymentException("No exception mapping for fault " + faultName + " and fault message " + messageQName + " for operation " + operationName); 378 } 379 String className = exceptionMapping.getExceptionType().getStringValue().trim(); 380 //TODO investigate whether there are other cases in which the namespace of faultQName can be determined. 381 //this is weird, but I can't figure out what it should be. 382 //if part has an element rather than a type, it should be part.getElementName() (see below) 383 QName faultQName = new QName("", faultName); 384 Part part; 385 if (exceptionMapping.isSetWsdlMessagePartName()) { 386 //According to schema documentation, this will only be set when several headerfaults use the same message. 387 String headerFaultMessagePartName = exceptionMapping.getWsdlMessagePartName().getStringValue(); 388 part = message.getPart(headerFaultMessagePartName); 389 } else { 390 part = (Part) message.getOrderedParts(null).iterator().next(); 391 } 392 QName faultTypeQName;// = part.getElementName() == null ? part.getTypeName() : part.getElementName(); 393 if (part.getElementName() == null) { 394 faultTypeQName = part.getTypeName(); 395 if (faultTypeQName == null) { 396 throw new DeploymentException("Neither type nor element name supplied for part: " + part); 397 } 398 } else { 399 faultQName = part.getElementName(); 400 faultTypeQName = (QName) schemaInfoBuilder.getElementToTypeMap().get(part.getElementName()); 401 if (faultTypeQName == null) { 402 throw new DeploymentException("Can not find type for: element: " + part.getElementName() + ", known elements: " + schemaInfoBuilder.getElementToTypeMap()); 403 } 404 } 405 SchemaType complexType = (SchemaType) schemaInfoBuilder.getComplexTypesInWsdl().get(faultTypeQName); 406 boolean isComplex = complexType != null; 407 FaultDesc faultDesc = new FaultDesc(faultQName, className, faultTypeQName, isComplex); 408 409 //constructor parameters 410 if (exceptionMapping.isSetConstructorParameterOrder()) { 411 if (!isComplex) { 412 throw new DeploymentException("ConstructorParameterOrder can only be set for complex types, not " + faultTypeQName); 413 } 414 Map elementMap = new HashMap(); 415 SchemaProperty[] properties = complexType.getProperties(); 416 for (int i = 0; i < properties.length; i++) { 417 SchemaProperty property = properties[i]; 418 QName elementName = property.getName(); 419 SchemaType elementType = property.getType(); 420 elementMap.put(elementName.getLocalPart(), elementType); 421 } 422 ArrayList parameterTypes = new ArrayList(); 423 ConstructorParameterOrderType constructorParameterOrder = exceptionMapping.getConstructorParameterOrder(); 424 for (int i = 0; i < constructorParameterOrder.getElementNameArray().length; i++) { 425 String elementName = constructorParameterOrder.getElementNameArray(i).getStringValue().trim(); 426 SchemaType elementType = (SchemaType) elementMap.get(elementName); 427 Class javaElementType; 428 429 QName elementTypeQName = elementType.getName(); 430 if (elementTypeQName != null) { 431 if (schemaInfoBuilder.getComplexTypesInWsdl().containsKey(elementType)) { 432 String javaClassName = (String) publicTypes.get(elementTypeQName); 433 if (javaClassName == null) { 434 throw new DeploymentException("No class mapped for element type: " + elementType); 435 } 436 javaElementType = getJavaClass(javaClassName); 437 } else { 438 javaElementType = (Class) qnameToClassMap.get(elementTypeQName); 439 if (javaElementType == null) { 440 throw new DeploymentException("Unknown type: " + elementType + " of name: " + elementName + " and QName: " + elementTypeQName); 441 } 442 } 443 } else { 444 //anonymous type 445 //anonymous type qname is constructed using rules 1.b and 2.b 446 String anonymousQName = complexType.getName().getNamespaceURI() + ":>" + complexType.getName().getLocalPart() + ">" + elementName; 447 String javaClassName = (String) anonymousTypes.get(anonymousQName); 448 if (javaClassName == null) { 449 if (elementType.isSimpleType()) { 450 //maybe it's a restriction of a built in simple type 451 SchemaType baseType = elementType.getBaseType(); 452 QName simpleTypeQName = baseType.getName(); 453 javaElementType = (Class) qnameToClassMap.get(simpleTypeQName); 454 if (javaElementType == null) { 455 throw new DeploymentException("Unknown simple type: " + elementType + " of name: " + elementName + " and QName: " + simpleTypeQName); 456 } 457 } else { 458 throw new DeploymentException("No class mapped for anonymous type: " + anonymousQName); 459 } 460 } else { 461 javaElementType = getJavaClass(javaClassName); 462 } 463 } 464 //todo faultTypeQName is speculative 465 //todo outheader might be true! 466 ParameterDesc parameterDesc = new ParameterDesc(faultTypeQName, ParameterDesc.OUT, elementTypeQName, javaElementType, false, false); 467 parameterTypes.add(parameterDesc); 468 } 469 faultDesc.setParameters(parameterTypes); 470 } 471 return faultDesc; 472 } 473 474 private Class getJavaClass(String javaClassName) throws DeploymentException { 475 try { 476 Class javaClass = ClassLoading.loadClass(javaClassName, classLoader); 477 return javaClass; 478 } catch (ClassNotFoundException e) { 479 throw new DeploymentException("Could not load class", e); 480 } 481 } 482 483 private void mapReturnType() throws DeploymentException { 484 QName returnType = null; 485 QName returnQName = null; 486 Class returnClass = null; 487 488 if (output == null) { 489 throw new DeploymentException("No output message, but a mapping for it for operation " + operationName); 490 } 491 WsdlReturnValueMappingType wsdlReturnValueMapping = methodMapping.getWsdlReturnValueMapping(); 492 String returnClassName = wsdlReturnValueMapping.getMethodReturnValue().getStringValue().trim(); 493 try { 494 returnClass = ClassLoading.loadClass(returnClassName, classLoader); 495 } catch (ClassNotFoundException e) { 496 throw new DeploymentException("Could not load return type for operation " + operationName, e); 497 } 498 499 QName wsdlMessageQName = wsdlReturnValueMapping.getWsdlMessage().getQNameValue(); 500 501 if (!wsdlMessageQName.equals(output.getQName())) { 502 throw new DeploymentException("OutputMessage has QName: " + output.getQName() + " but mapping specifies: " + wsdlMessageQName + " for operation " + operationName); 503 } 504 505 if (wsdlReturnValueMapping.isSetWsdlMessagePartName()) { 506 String wsdlMessagePartName = wsdlReturnValueMapping.getWsdlMessagePartName().getStringValue().trim(); 507 if (outParamNames.contains(wsdlMessagePartName)) { 508 throw new DeploymentException("output message part " + wsdlMessagePartName + " has both an INOUT or OUT mapping and a return value mapping for operation " + operationName); 509 } 510 511 if (wrappedStyle) { 512 Part outPart = getWrappedPart(output); 513 SchemaParticle returnParticle = getWrapperChild(outPart, wsdlMessagePartName); 514 //TODO this makes little sense but may be correct, see comments in axis Parameter class 515 //the part name qname is really odd. 516 returnQName = new QName("", returnParticle.getName().getLocalPart()); 517 returnType = returnParticle.getType().getName(); 518 } else if (rpcStyle) { 519 Part part = output.getPart(wsdlMessagePartName); 520 if (part == null) { 521 throw new DeploymentException("No part for wsdlMessagePartName " + wsdlMessagePartName + " in output message for operation " + operationName); 522 } 523 returnQName = new QName("", part.getName()); 524 returnType = part.getTypeName(); 525 } else { 526 Part part = output.getPart(wsdlMessagePartName); 527 if (part == null) { 528 throw new DeploymentException("No part for wsdlMessagePartName " + wsdlMessagePartName + " in output message for operation " + operationName); 529 } 530 returnQName = getPartName(part); 531 returnType = returnQName; 532 } 533 534 outParamNames.add(wsdlMessagePartName); 535 } else { 536 //what does this mean???? 537 } 538 539 operationDesc.setReturnQName(returnQName); 540 operationDesc.setReturnType(returnType); 541 operationDesc.setReturnClass(returnClass); 542 } 543 544 private ParameterDesc mapParameter(MethodParamPartsMappingType paramMapping) throws DeploymentException { 545 WsdlMessageMappingType wsdlMessageMappingType = paramMapping.getWsdlMessageMapping(); 546 QName wsdlMessageQName = wsdlMessageMappingType.getWsdlMessage().getQNameValue(); 547 String wsdlMessagePartName = wsdlMessageMappingType.getWsdlMessagePartName().getStringValue().trim(); 548 549 String parameterMode = wsdlMessageMappingType.getParameterMode().getStringValue().trim(); 550 byte mode = ParameterDesc.modeFromString(parameterMode); 551 boolean isInParam = mode == ParameterDesc.IN || mode == ParameterDesc.INOUT; 552 boolean isOutParam = mode == ParameterDesc.OUT || mode == ParameterDesc.INOUT; 553 554 if (isOutParam && output == null) { 555 throw new DeploymentException("Mapping for output parameter " + wsdlMessagePartName + " found, but no output message for operation " + operationName); 556 } 557 boolean isSoapHeader = wsdlMessageMappingType.isSetSoapHeader(); 558 boolean inHeader = isSoapHeader && isInParam; 559 boolean outHeader = isSoapHeader && isOutParam; 560 561 QName paramQName; 562 QName paramTypeQName; 563 564 Part part = null; 565 SchemaParticle inParameter = null; 566 if (isInParam) { 567 if (!wsdlMessageQName.equals(input.getQName())) { 568 throw new DeploymentException("QName of input message: " + input.getQName() + 569 " does not match mapping message QName: " + wsdlMessageQName + " for operation " + operationName); 570 } 571 if (wrappedStyle) { 572 Part inPart = getWrappedPart(input); 573 // the local name of the global element refered by the part is equal to the operation name 574 QName name = inPart.getElementName(); 575 if (false == name.getLocalPart().equals(operationName)) { 576 throw new DeploymentException("message " + input.getQName() + " refers to a global element named " + 577 name.getLocalPart() + ", which is not equal to the operation name " + operationName); 578 } 579 inParameter = getWrapperChild(inPart, wsdlMessagePartName); 580 //TODO this makes little sense but may be correct, see comments in axis Parameter class 581 //the part name qname is really odd. 582 paramQName = new QName("", inParameter.getName().getLocalPart()); 583 paramTypeQName = inParameter.getType().getName(); 584 } else if (rpcStyle) { 585 part = input.getPart(wsdlMessagePartName); 586 if (part == null) { 587 throw new DeploymentException("No part for wsdlMessagePartName " + wsdlMessagePartName + " in input message for operation " + operationName); 588 } 589 //TODO this makes little sense but may be correct, see comments in axis Parameter class 590 //the part name qname is really odd. 591 paramQName = new QName("", part.getName()); 592 paramTypeQName = part.getTypeName(); 593 } else { 594 part = input.getPart(wsdlMessagePartName); 595 if (part == null) { 596 throw new DeploymentException("No part for wsdlMessagePartName " + wsdlMessagePartName + " in input message for operation " + operationName); 597 } 598 paramQName = getPartName(part); 599 paramTypeQName = paramQName; 600 } 601 inParamNames.add(wsdlMessagePartName); 602 if (isOutParam) { 603 if (wrappedStyle) { 604 Part outPart = getWrappedPart(output); 605 SchemaParticle outParameter = getWrapperChild(outPart, wsdlMessagePartName); 606 if (inParameter.getType() != outParameter.getType()) { 607 throw new DeploymentException("The wrapper children " + wsdlMessagePartName + 608 " do not have the same type for operation " + operationName); 609 } 610 } else if (rpcStyle) { 611 //inout, check that part of same name and type is in output message 612 Part outPart = output.getPart(wsdlMessagePartName); 613 if (outPart == null) { 614 throw new DeploymentException("No part for wsdlMessagePartName " + wsdlMessagePartName + " in output message for INOUT parameter of operation " + operationName); 615 } 616 // TODO this cannot happen. 617 if (!part.getName().equals(outPart.getName())) { 618 throw new DeploymentException("Mismatched input part name: " + part.getName() + " and output part name: " + outPart.getName() + " for INOUT parameter for wsdlMessagePartName " + wsdlMessagePartName + " for operation " + operationName); 619 } 620 if (!(part.getElementName() == null ? outPart.getElementName() == null : part.getElementName().equals(outPart.getElementName()))) { 621 throw new DeploymentException("Mismatched input part element name: " + part.getElementName() + " and output part element name: " + outPart.getElementName() + " for INOUT parameter for wsdlMessagePartName " + wsdlMessagePartName + " for operation " + operationName); 622 } 623 if (!(part.getTypeName() == null ? outPart.getTypeName() == null : part.getTypeName().equals(outPart.getTypeName()))) { 624 throw new DeploymentException("Mismatched input part type name: " + part.getTypeName() + " and output part type name: " + outPart.getTypeName() + " for INOUT parameter for wsdlMessagePartName " + wsdlMessagePartName + " for operation " + operationName); 625 } 626 } else { 627 part = output.getPart(wsdlMessagePartName); 628 if (part == null) { 629 throw new DeploymentException("No part for wsdlMessagePartName " + wsdlMessagePartName + " in output message for operation " + operationName); 630 } 631 paramQName = getPartName(part); 632 paramTypeQName = paramQName; 633 } 634 outParamNames.add(wsdlMessagePartName); 635 } 636 } else if (isOutParam) { 637 if (!wsdlMessageQName.equals(output.getQName())) { 638 throw new DeploymentException("QName of output message: " + output.getQName() + 639 " does not match mapping message QName: " + wsdlMessageQName + " for operation " + operationName); 640 } 641 if (wrappedStyle) { 642 Part outPart = getWrappedPart(output); 643 SchemaParticle outParameter = getWrapperChild(outPart, wsdlMessagePartName); 644 //TODO this makes little sense but may be correct, see comments in axis Parameter class 645 //the part name qname is really odd. 646 paramQName = new QName("", outParameter.getName().getLocalPart()); 647 paramTypeQName = outParameter.getType().getName(); 648 } else if (rpcStyle) { 649 part = output.getPart(wsdlMessagePartName); 650 if (part == null) { 651 throw new DeploymentException("No part for wsdlMessagePartName " + wsdlMessagePartName + " in output message for operation " + operationName); 652 } 653 //TODO this makes little sense but may be correct, see comments in axis Parameter class 654 //the part name qname is really odd. 655 paramQName = new QName("", part.getName()); 656 paramTypeQName = part.getTypeName(); 657 } else { 658 part = output.getPart(wsdlMessagePartName); 659 if (part == null) { 660 throw new DeploymentException("No part for wsdlMessagePartName " + wsdlMessagePartName + " in output message for operation " + operationName); 661 } 662 paramQName = getPartName(part); 663 paramTypeQName = paramQName; 664 } 665 outParamNames.add(wsdlMessagePartName); 666 } else { 667 throw new AssertionError("a param mapping has to be IN or OUT or INOUT"); 668 } 669 670 //use complexTypeMap 671 boolean isComplexType = schemaInfoBuilder.getComplexTypesInWsdl().containsKey(paramTypeQName); 672 String paramJavaTypeName = paramMapping.getParamType().getStringValue().trim(); 673 boolean isInOnly = mode == ParameterDesc.IN; 674 Class actualParamJavaType = WSDescriptorParser.getHolderType(paramJavaTypeName, isInOnly, paramTypeQName, isComplexType, mapping, classLoader); 675 676 ParameterDesc parameterDesc = new ParameterDesc(paramQName, mode, paramTypeQName, actualParamJavaType, inHeader, outHeader); 677 return parameterDesc; 678 } 679 680 private QName getPartName(Part part) { 681 return null == part.getElementName() ? part.getTypeName() : part.getElementName(); 682 } 683 684 private Part getWrappedPart(Message message) throws DeploymentException { 685 // in case of wrapped element, the message has only one part. 686 Collection parts = message.getParts().values(); 687 if (1 != parts.size()) { 688 throw new DeploymentException("message " + message.getQName() + " has " + parts.size() + 689 " parts and should only have one as wrapper style mapping is specified for operation " + 690 operationName); 691 } 692 return (Part) parts.iterator().next(); 693 } 694 695 private SchemaParticle getWrapperChild(Part part, String wsdlMessagePartName) throws DeploymentException { 696 QName name = part.getElementName(); 697 698 wrapperElementQNames.add(name); 699 700 SchemaType operationType = (SchemaType) schemaInfoBuilder.getComplexTypesInWsdl().get(name); 701 if (null == operationType) { 702 throw new DeploymentException("No global element named " + name + " for operation " + operationName); 703 } 704 705 // schemaType should be complex using xsd:sequence compositor 706 SchemaParticle parametersType = operationType.getContentModel(); 707 if (SchemaParticle.ELEMENT == parametersType.getParticleType()) { 708 if (parametersType.getName().getLocalPart().equals(wsdlMessagePartName)) { 709 return parametersType; 710 } 711 throw new DeploymentException("Global element named " + name + 712 " does not define a child element named " + wsdlMessagePartName + 713 " required by the operation " + operationName); 714 } else if (SchemaParticle.SEQUENCE == parametersType.getParticleType()) { 715 SchemaParticle[] parameters = parametersType.getParticleChildren(); 716 for (int i = 0; i < parameters.length; i++) { 717 SchemaParticle parameter = parameters[i]; 718 QName element = parameter.getName(); 719 if (element.getLocalPart().equals(wsdlMessagePartName)) { 720 return parameter; 721 } 722 } 723 throw new DeploymentException("Global element named " + name + 724 " does not define a child element named " + wsdlMessagePartName + 725 " required by the operation " + operationName); 726 } else { 727 throw new DeploymentException("Global element named " + name + 728 " is not a sequence for operation " + operationName); 729 } 730 } 731 732 /** 733 * Supporting the Document/Literal Wrapped pattern 734 * 735 * See http://www-106.ibm.com/developerworks/webservices/library/ws-whichwsdl/ for a nice explanation and example 736 * 737 * wrapped-element tag is used 738 * WSDL message with a single part 739 * part uses the 'element' attribute to point to an elemement in the types section 740 * the element type and the element's name match the operation name 741 */ 742 }