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