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