View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  package org.apache.geronimo.axis.builder;
19  
20  import java.lang.reflect.Method;
21  import java.math.BigDecimal;
22  import java.math.BigInteger;
23  import java.net.URI;
24  import java.util.ArrayList;
25  import java.util.Calendar;
26  import java.util.Collection;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.HashSet;
30  import java.util.Iterator;
31  import java.util.Map;
32  import java.util.Set;
33  
34  import javax.wsdl.BindingInput;
35  import javax.wsdl.BindingOperation;
36  import javax.wsdl.Fault;
37  import javax.wsdl.Message;
38  import javax.wsdl.Part;
39  import javax.wsdl.OperationType;
40  import javax.wsdl.extensions.soap.SOAPBody;
41  import javax.xml.namespace.QName;
42  
43  import org.apache.axis.constants.Style;
44  import org.apache.axis.constants.Use;
45  import org.apache.axis.description.FaultDesc;
46  import org.apache.axis.description.OperationDesc;
47  import org.apache.axis.description.ParameterDesc;
48  import org.apache.axis.soap.SOAPConstants;
49  import org.apache.axis.encoding.XMLType;
50  import org.apache.geronimo.axis.client.OperationInfo;
51  import org.apache.geronimo.common.DeploymentException;
52  import org.apache.geronimo.kernel.ClassLoading;
53  import org.apache.geronimo.xbeans.j2ee.ConstructorParameterOrderType;
54  import org.apache.geronimo.xbeans.j2ee.ExceptionMappingType;
55  import org.apache.geronimo.xbeans.j2ee.JavaWsdlMappingType;
56  import org.apache.geronimo.xbeans.j2ee.MethodParamPartsMappingType;
57  import org.apache.geronimo.xbeans.j2ee.ServiceEndpointMethodMappingType;
58  import org.apache.geronimo.xbeans.j2ee.WsdlMessageMappingType;
59  import org.apache.geronimo.xbeans.j2ee.WsdlReturnValueMappingType;
60  import org.apache.xmlbeans.SchemaParticle;
61  import org.apache.xmlbeans.SchemaProperty;
62  import org.apache.xmlbeans.SchemaType;
63  import org.objectweb.asm.Type;
64  import org.apache.geronimo.xbeans.j2ee.JavaXmlTypeMappingType;
65  import org.apache.geronimo.webservices.builder.SchemaInfoBuilder;
66  import org.apache.geronimo.webservices.builder.WSDescriptorParser;
67  
68  /**
69   * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
70   */
71  public class HeavyweightOperationDescBuilder extends OperationDescBuilder {
72  
73      private final JavaWsdlMappingType mapping;
74      private final ServiceEndpointMethodMappingType methodMapping;
75      private final SOAPBody soapBody;
76  
77  
78      private final Map exceptionMap;
79      private final SchemaInfoBuilder schemaInfoBuilder;
80      private final ClassLoader classLoader;
81      private final boolean rpcStyle;
82      private final boolean documentStyle;
83      private final boolean wrappedStyle;
84      private final boolean isEncoded;
85      private final Map publicTypes = new HashMap();
86      private final Map anonymousTypes = new HashMap();
87  
88      /* Keep track of in and out parameter names so we can verify that
89       * everything has been mapped and mapped correctly
90       */
91      private final Set inParamNames = new HashSet();
92      private final Set outParamNames = new HashSet();
93      private final Class serviceEndpointInterface;
94  
95      /**
96       * Track the wrapper elements
97       */
98      private final Set wrapperElementQNames = new HashSet();
99  
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 }