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 }