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: */package org.apache.openejb.server.axis.assembler;
018:
019: import org.apache.openejb.OpenEJBException;
020: import org.apache.openejb.jee.ConstructorParameterOrder;
021: import org.apache.openejb.jee.ExceptionMapping;
022: import org.apache.openejb.jee.JavaWsdlMapping;
023: import org.apache.openejb.jee.JavaXmlTypeMapping;
024: import org.apache.openejb.jee.MethodParamPartsMapping;
025: import org.apache.openejb.jee.PackageMapping;
026: import org.apache.openejb.jee.ServiceEndpointMethodMapping;
027: import org.apache.openejb.jee.WsdlMessageMapping;
028: import org.apache.openejb.jee.WsdlReturnValueMapping;
029: import static org.apache.openejb.server.axis.assembler.JaxRpcParameterInfo.Mode;
030:
031: import javax.wsdl.BindingInput;
032: import javax.wsdl.BindingOperation;
033: import javax.wsdl.Fault;
034: import javax.wsdl.Message;
035: import javax.wsdl.Operation;
036: import javax.wsdl.Part;
037: import javax.wsdl.extensions.soap.SOAPBinding;
038: import javax.wsdl.extensions.soap.SOAPBody;
039: import javax.wsdl.extensions.soap.SOAPOperation;
040: import javax.xml.namespace.QName;
041: import javax.xml.rpc.holders.BigDecimalHolder;
042: import javax.xml.rpc.holders.BigIntegerHolder;
043: import javax.xml.rpc.holders.BooleanHolder;
044: import javax.xml.rpc.holders.BooleanWrapperHolder;
045: import javax.xml.rpc.holders.ByteArrayHolder;
046: import javax.xml.rpc.holders.ByteHolder;
047: import javax.xml.rpc.holders.ByteWrapperHolder;
048: import javax.xml.rpc.holders.CalendarHolder;
049: import javax.xml.rpc.holders.DoubleHolder;
050: import javax.xml.rpc.holders.DoubleWrapperHolder;
051: import javax.xml.rpc.holders.FloatHolder;
052: import javax.xml.rpc.holders.FloatWrapperHolder;
053: import javax.xml.rpc.holders.IntHolder;
054: import javax.xml.rpc.holders.IntegerWrapperHolder;
055: import javax.xml.rpc.holders.LongHolder;
056: import javax.xml.rpc.holders.LongWrapperHolder;
057: import javax.xml.rpc.holders.ObjectHolder;
058: import javax.xml.rpc.holders.QNameHolder;
059: import javax.xml.rpc.holders.ShortHolder;
060: import javax.xml.rpc.holders.ShortWrapperHolder;
061: import javax.xml.rpc.holders.StringHolder;
062: import java.math.BigDecimal;
063: import java.math.BigInteger;
064: import java.net.URI;
065: import java.util.ArrayList;
066: import java.util.Calendar;
067: import java.util.Collection;
068: import java.util.Collections;
069: import java.util.HashMap;
070: import java.util.HashSet;
071: import java.util.List;
072: import java.util.Map;
073: import java.util.Set;
074:
075: public class HeavyweightOperationInfoBuilder {
076: private final JavaWsdlMapping mapping;
077: private final ServiceEndpointMethodMapping methodMapping;
078:
079: private final XmlSchemaInfo schemaInfo;
080: private final BindingStyle bindingStyle;
081:
082: //
083: // Used to map exception class constructor args
084: //
085: private final Map<QName, String> publicTypes = new HashMap<QName, String>();
086: private final Map<String, String> anonymousTypes = new HashMap<String, String>();
087:
088: //
089: // Track in and out parameter names so we can verify that
090: // everything has been mapped and mapped correctly
091: //
092: private final Set<String> inParamNames = new HashSet<String>();
093: private final Set<String> outParamNames = new HashSet<String>();
094:
095: //
096: // Track the wrapper elements - used by HeavyweightTypeInfoBuilder
097: //
098: private final Set<QName> wrapperElementQNames = new HashSet<QName>();
099:
100: private final String operationName;
101: private final JaxRpcOperationInfo.OperationStyle operationStyle;
102: private final Message inputMessage;
103: private final Message outputMessage;
104: private final Collection<Fault> faults = new ArrayList<Fault>();
105:
106: private JaxRpcOperationInfo operationInfo;
107:
108: public HeavyweightOperationInfoBuilder(
109: BindingOperation bindingOperation,
110: ServiceEndpointMethodMapping methodMapping,
111: JavaWsdlMapping mapping, XmlSchemaInfo schemaInfo)
112: throws OpenEJBException {
113: Operation operation = bindingOperation.getOperation();
114: this .operationName = operation.getName();
115: this .operationStyle = JaxRpcOperationInfo.OperationStyle
116: .valueOf(operation.getStyle().toString());
117: this .outputMessage = operation.getOutput() == null ? null
118: : operation.getOutput().getMessage();
119: this .inputMessage = operation.getInput().getMessage();
120:
121: // faults
122: for (Object o : operation.getFaults().values()) {
123: faults.add((Fault) o);
124: }
125:
126: this .mapping = mapping;
127: this .methodMapping = methodMapping;
128: this .schemaInfo = schemaInfo;
129:
130: // index types - used to process build exception class constructor args
131: for (JavaXmlTypeMapping javaXmlTypeMapping : mapping
132: .getJavaXmlTypeMapping()) {
133: String javaClassName = javaXmlTypeMapping.getJavaType();
134: if (javaXmlTypeMapping.getAnonymousTypeQname() != null) {
135: String anonymousTypeQName = javaXmlTypeMapping
136: .getAnonymousTypeQname();
137: anonymousTypes.put(anonymousTypeQName, javaClassName);
138: } else if (javaXmlTypeMapping.getRootTypeQname() != null) {
139: QName qname = javaXmlTypeMapping.getRootTypeQname();
140: publicTypes.put(qname, javaClassName);
141: }
142: }
143:
144: // BindingStyle
145: if (methodMapping.getWrappedElement() != null) {
146: bindingStyle = BindingStyle.DOCUMENT_LITERAL_WRAPPED;
147: } else {
148: BindingInput bindingInput = bindingOperation
149: .getBindingInput();
150:
151: SOAPOperation soapOperation = JaxRpcServiceInfoBuilder
152: .getExtensibilityElement(SOAPOperation.class,
153: bindingOperation.getExtensibilityElements());
154: String styleString = soapOperation.getStyle();
155: if (styleString == null) {
156: SOAPBinding soapBinding = JaxRpcServiceInfoBuilder
157: .getExtensibilityElement(SOAPBinding.class,
158: bindingInput.getExtensibilityElements());
159: styleString = soapBinding.getStyle();
160: }
161:
162: SOAPBody soapBody = JaxRpcServiceInfoBuilder
163: .getExtensibilityElement(SOAPBody.class,
164: bindingInput.getExtensibilityElements());
165: String useString = soapBody.getUse();
166:
167: bindingStyle = BindingStyle.getBindingStyle(styleString,
168: useString);
169: }
170: }
171:
172: public Set<QName> getWrapperElementQNames() throws OpenEJBException {
173: buildOperationInfo();
174: return Collections.unmodifiableSet(wrapperElementQNames);
175: }
176:
177: public JaxRpcOperationInfo buildOperationInfo()
178: throws OpenEJBException {
179: if (operationInfo != null) {
180: return operationInfo;
181: }
182:
183: operationInfo = new JaxRpcOperationInfo();
184: operationInfo.name = operationName;
185:
186: // Binding style rpc/encoded, doc/lit, wrapped, etc.
187: operationInfo.bindingStyle = bindingStyle;
188:
189: // Operation style one way, request response, etc/
190: operationInfo.operationStyle = operationStyle;
191:
192: // Java method name
193: operationInfo.javaMethodName = methodMapping
194: .getJavaMethodName();
195:
196: //
197: // Map the parameters
198: //
199: mapParameters();
200:
201: //
202: // Map return
203: //
204: if (methodMapping.getWsdlReturnValueMapping() != null) {
205: mapReturnType();
206: }
207:
208: // Validate output mapping is complete
209: if (outputMessage != null && bindingStyle.isWrapped()) {
210: Part inputPart = getWrappedPart(outputMessage);
211:
212: QName wrapperName = inputPart.getElementName();
213: XmlElementInfo wraperElement = schemaInfo.elements
214: .get(wrapperName);
215: XmlTypeInfo wrapperType = schemaInfo.types
216: .get(wraperElement.xmlType);
217:
218: Set<String> expectedOutParams = new HashSet<String>();
219: for (XmlElementInfo expectedOutParam : wrapperType.elements
220: .values()) {
221: expectedOutParams.add(expectedOutParam.qname
222: .getLocalPart());
223: }
224: if (!outParamNames.equals(expectedOutParams)) {
225: throw new OpenEJBException(
226: "Not all wrapper children were mapped to parameters or a return value for operation "
227: + operationName);
228: }
229: } else if (null != outputMessage) {
230: if (!outParamNames
231: .equals(outputMessage.getParts().keySet())) {
232: throw new OpenEJBException(
233: "Not all output message parts were mapped to parameters or a return value for operation "
234: + operationName);
235: }
236: }
237:
238: //
239: // Map faults (exception)
240: //
241: for (Fault fault : faults) {
242: JaxRpcFaultInfo faultInfo = mapFaults(fault);
243: operationInfo.faults.add(faultInfo);
244: }
245:
246: return operationInfo;
247: }
248:
249: private JaxRpcParameterInfo[] mapParameters()
250: throws OpenEJBException {
251: List<MethodParamPartsMapping> paramMappings = methodMapping
252: .getMethodParamPartsMapping();
253:
254: //
255: // Map the ParameterDesc instance in an array so they can be ordered properly
256: // before they are added to the the OperationDesc.
257: //
258: JaxRpcParameterInfo[] parameterInfos = new JaxRpcParameterInfo[paramMappings
259: .size()];
260: for (MethodParamPartsMapping paramMapping : paramMappings) {
261: JaxRpcParameterInfo parameterInfo = mapParameter(paramMapping);
262: parameterInfos[paramMapping.getParamPosition().intValue()] = parameterInfo;
263: }
264:
265: //
266: // verify that all parameters were mapped and we don't have nulls in the parameter array
267: //
268: for (int i = 0; i < parameterInfos.length; i++) {
269: if (parameterInfos[i] == null) {
270: throw new OpenEJBException(
271: "There is no mapping for parameter number " + i
272: + " for operation " + operationName);
273: }
274: }
275:
276: //
277: // Verify that all parameter names were mapped
278: //
279: if (bindingStyle.isWrapped()) {
280: // verify that all child elements have a parameter mapping
281: Part inputPart = getWrappedPart(inputMessage);
282:
283: QName wrapperName = inputPart.getElementName();
284: XmlElementInfo wrapperElement = schemaInfo.elements
285: .get(wrapperName);
286: XmlTypeInfo wrapperType = schemaInfo.types
287: .get(wrapperElement.xmlType);
288:
289: Set<String> expectedInParams = new HashSet<String>();
290: for (XmlElementInfo expectedInParam : wrapperType.elements
291: .values()) {
292: expectedInParams.add(expectedInParam.qname
293: .getLocalPart());
294: }
295: if (!inParamNames.equals(expectedInParams)) {
296: throw new OpenEJBException(
297: "Not all wrapper children were mapped for operation name"
298: + operationName);
299: }
300: } else {
301: // verify all input message parts are mapped
302: if (!inParamNames.equals(inputMessage.getParts().keySet())) {
303: throw new OpenEJBException(
304: "Not all input message parts were mapped for operation name"
305: + operationName);
306: }
307: }
308:
309: return parameterInfos;
310: }
311:
312: private JaxRpcParameterInfo mapParameter(
313: MethodParamPartsMapping paramMapping)
314: throws OpenEJBException {
315: WsdlMessageMapping wsdlMessageMappingType = paramMapping
316: .getWsdlMessageMapping();
317: QName wsdlMessageQName = wsdlMessageMappingType
318: .getWsdlMessage();
319: String wsdlMessagePartName = wsdlMessageMappingType
320: .getWsdlMessagePartName();
321:
322: Mode mode = Mode.valueOf(wsdlMessageMappingType
323: .getParameterMode());
324: if ((mode == Mode.OUT || mode == Mode.INOUT)
325: && outputMessage == null) {
326: throw new OpenEJBException("Mapping for output parameter "
327: + wsdlMessagePartName
328: + " found, but no output message for operation "
329: + operationName);
330: }
331:
332: //
333: // Determine the param qname and xml schema type
334: //
335: QName paramQName;
336: QName paramXmlType;
337: if (mode == Mode.IN || mode == Mode.INOUT) {
338: //
339: // IN or INOUT Parameter
340: //
341: if (!wsdlMessageQName.equals(inputMessage.getQName())) {
342: throw new OpenEJBException("QName of input message: "
343: + inputMessage.getQName()
344: + " does not match mapping message QName: "
345: + wsdlMessageQName + " for operation "
346: + operationName);
347: }
348:
349: Part part = null;
350: XmlElementInfo inParameter = null;
351: if (bindingStyle.isWrapped()) {
352: Part inPart = getWrappedPart(inputMessage);
353:
354: // operation name == wraper element name
355: QName name = inPart.getElementName();
356: if (!name.getLocalPart().equals(operationName)) {
357: throw new OpenEJBException(
358: "message "
359: + inputMessage.getQName()
360: + " refers to a global element named "
361: + name.getLocalPart()
362: + ", which is not equal to the operation name "
363: + operationName);
364: }
365: inParameter = getWrapperChild(inPart,
366: wsdlMessagePartName);
367:
368: paramQName = new QName("", inParameter.qname
369: .getLocalPart());
370: paramXmlType = inParameter.xmlType;
371: } else if (bindingStyle.isRpc()) {
372: part = inputMessage.getPart(wsdlMessagePartName);
373: if (part == null) {
374: throw new OpenEJBException(
375: "No part for wsdlMessagePartName "
376: + wsdlMessagePartName
377: + " in input message for operation "
378: + operationName);
379: }
380:
381: paramQName = new QName("", part.getName());
382:
383: // RPC can only use type
384: paramXmlType = part.getTypeName();
385: } else {
386: part = inputMessage.getPart(wsdlMessagePartName);
387: if (part == null) {
388: throw new OpenEJBException(
389: "No part for wsdlMessagePartName "
390: + wsdlMessagePartName
391: + " in input message for operation "
392: + operationName);
393: }
394: // Document should use element, but type is allowed
395: paramQName = getPartName(part);
396: paramXmlType = paramQName;
397: }
398: inParamNames.add(wsdlMessagePartName);
399:
400: //
401: // Verify INOUT parameter output message is consistent with input message
402: //
403: if (mode == Mode.INOUT) {
404: if (bindingStyle.isWrapped()) {
405: // Verify output message supports this inout parameter
406: Part outPart = getWrappedPart(outputMessage);
407: XmlElementInfo outParameter = getWrapperChild(
408: outPart, wsdlMessagePartName);
409: if (inParameter.xmlType != outParameter.xmlType) {
410: throw new OpenEJBException(
411: "The wrapper children "
412: + wsdlMessagePartName
413: + " do not have the same type for operation "
414: + operationName);
415: }
416: } else if (bindingStyle.isRpc()) {
417: // Verify output message supports this inout parameter
418: Part outPart = outputMessage
419: .getPart(wsdlMessagePartName);
420: if (outPart == null) {
421: throw new OpenEJBException(
422: "No part for wsdlMessagePartName "
423: + wsdlMessagePartName
424: + " in output message for INOUT parameter of operation "
425: + operationName);
426: }
427: // TODO this cannot happen.
428: if (!part.getName().equals(outPart.getName())) {
429: throw new OpenEJBException(
430: "Mismatched input part name: "
431: + part.getName()
432: + " and output part name: "
433: + outPart.getName()
434: + " for INOUT parameter for wsdlMessagePartName "
435: + wsdlMessagePartName
436: + " for operation "
437: + operationName);
438: }
439: if (!(part.getElementName() == null ? outPart
440: .getElementName() == null : part
441: .getElementName().equals(
442: outPart.getElementName()))) {
443: throw new OpenEJBException(
444: "Mismatched input part element name: "
445: + part.getElementName()
446: + " and output part element name: "
447: + outPart.getElementName()
448: + " for INOUT parameter for wsdlMessagePartName "
449: + wsdlMessagePartName
450: + " for operation "
451: + operationName);
452: }
453: if (!(part.getTypeName() == null ? outPart
454: .getTypeName() == null : part.getTypeName()
455: .equals(outPart.getTypeName()))) {
456: throw new OpenEJBException(
457: "Mismatched input part type name: "
458: + part.getTypeName()
459: + " and output part type name: "
460: + outPart.getTypeName()
461: + " for INOUT parameter for wsdlMessagePartName "
462: + wsdlMessagePartName
463: + " for operation "
464: + operationName);
465: }
466: } else {
467: part = outputMessage.getPart(wsdlMessagePartName);
468: if (part == null) {
469: throw new OpenEJBException(
470: "No part for wsdlMessagePartName "
471: + wsdlMessagePartName
472: + " in output message for operation "
473: + operationName);
474: }
475: // todo this seem strange... shouldn't the name and type be the same as the in binding above
476: paramQName = getPartName(part);
477: paramXmlType = paramQName;
478: }
479: outParamNames.add(wsdlMessagePartName);
480: }
481: } else {
482: //
483: // OUT only Parameter
484: //
485: if (!wsdlMessageQName.equals(outputMessage.getQName())) {
486: throw new OpenEJBException("QName of output message: "
487: + outputMessage.getQName()
488: + " does not match mapping message QName: "
489: + wsdlMessageQName + " for operation "
490: + operationName);
491: }
492:
493: if (bindingStyle.isWrapped()) {
494: Part outPart = getWrappedPart(outputMessage);
495: XmlElementInfo outParameter = getWrapperChild(outPart,
496: wsdlMessagePartName);
497:
498: paramQName = new QName("", outParameter.qname
499: .getLocalPart());
500: paramXmlType = outParameter.xmlType;
501: } else if (bindingStyle.isRpc()) {
502: Part part = outputMessage.getPart(wsdlMessagePartName);
503: if (part == null) {
504: throw new OpenEJBException(
505: "No part for wsdlMessagePartName "
506: + wsdlMessagePartName
507: + " in output message for operation "
508: + operationName);
509: }
510:
511: paramQName = new QName("", part.getName());
512:
513: // RPC can only use type
514: paramXmlType = part.getTypeName();
515: } else {
516: Part part = outputMessage.getPart(wsdlMessagePartName);
517: if (part == null) {
518: throw new OpenEJBException(
519: "No part for wsdlMessagePartName "
520: + wsdlMessagePartName
521: + " in output message for operation "
522: + operationName);
523: }
524:
525: paramQName = getPartName(part);
526: paramXmlType = paramQName;
527: }
528: outParamNames.add(wsdlMessagePartName);
529: }
530:
531: //
532: // Determine the param java type
533: //
534: String paramJavaType;
535: if (mode == Mode.IN) {
536: // IN only prarmeters don't have holders
537: paramJavaType = paramMapping.getParamType();
538: } else if (rpcHolderClasses.containsKey(paramMapping
539: .getParamType())) {
540: // This is a standard type with a built in holder class
541: paramJavaType = rpcHolderClasses.get(paramMapping
542: .getParamType());
543: } else {
544: // holderClass == ${packageName}.holders.${typeName}Holder
545: String packageName;
546: String typeName;
547:
548: PackageMapping packageMapping = mapping
549: .getPackageMappingMap().get(
550: paramXmlType.getNamespaceURI());
551: if (packageMapping != null) {
552: packageName = packageMapping.getPackageType();
553:
554: // Type name is typeQName local part, but make sure it is capitalized correctly
555: typeName = paramXmlType.getLocalPart();
556: typeName = Character.toUpperCase(typeName.charAt(0))
557: + typeName.substring(1);
558: } else {
559: // a.b.foo.Bar >>> a.b.foo.holders.BarHolder
560: String paramJavaTypeName = paramMapping.getParamType();
561: int lastDot = paramJavaTypeName.lastIndexOf(".");
562: packageName = paramJavaTypeName.substring(0, lastDot);
563: typeName = paramJavaTypeName.substring(lastDot + 1);
564: }
565:
566: paramJavaType = packageName + ".holders." + typeName
567: + "Holder";
568: }
569:
570: //
571: // Build JaxRpcParameterInfo
572: //
573: JaxRpcParameterInfo parameterInfo = new JaxRpcParameterInfo();
574: parameterInfo.qname = paramQName;
575: parameterInfo.xmlType = paramXmlType;
576: parameterInfo.javaType = paramJavaType;
577: parameterInfo.mode = Mode.valueOf(wsdlMessageMappingType
578: .getParameterMode());
579: parameterInfo.soapHeader = wsdlMessageMappingType
580: .getSoapHeader() != null;
581:
582: return parameterInfo;
583: }
584:
585: private void mapReturnType() throws OpenEJBException {
586: if (outputMessage == null) {
587: throw new OpenEJBException(
588: "No output message, but a mapping for it for operation "
589: + operationName);
590: }
591:
592: // verify mapped return value qname matches expected output message name
593: WsdlReturnValueMapping wsdlReturnValueMapping = methodMapping
594: .getWsdlReturnValueMapping();
595: if (!wsdlReturnValueMapping.getWsdlMessage().equals(
596: outputMessage.getQName())) {
597: throw new OpenEJBException("OutputMessage has QName: "
598: + outputMessage.getQName()
599: + " but mapping specifies: "
600: + wsdlReturnValueMapping.getWsdlMessage()
601: + " for operation " + operationName);
602: }
603:
604: //
605: // Determind return type qname and xml schema type
606: //
607: QName returnQName = null;
608: QName returnXmlType = null;
609: if (wsdlReturnValueMapping.getWsdlMessagePartName() != null) {
610: String wsdlMessagePartName = wsdlReturnValueMapping
611: .getWsdlMessagePartName();
612: if (outParamNames.contains(wsdlMessagePartName)) {
613: throw new OpenEJBException(
614: "output message part "
615: + wsdlMessagePartName
616: + " has both an INOUT or OUT mapping and a return value mapping for operation "
617: + operationName);
618: }
619:
620: if (bindingStyle.isWrapped()) {
621: Part outPart = getWrappedPart(outputMessage);
622: XmlElementInfo returnParticle = getWrapperChild(
623: outPart, wsdlMessagePartName);
624:
625: returnQName = new QName("", returnParticle.qname
626: .getLocalPart());
627: returnXmlType = returnParticle.xmlType;
628: } else if (bindingStyle.isRpc()) {
629: Part part = outputMessage.getPart(wsdlMessagePartName);
630: if (part == null) {
631: throw new OpenEJBException(
632: "No part for wsdlMessagePartName "
633: + wsdlMessagePartName
634: + " in output message for operation "
635: + operationName);
636: }
637:
638: returnQName = new QName("", part.getName());
639:
640: // RPC can only use type
641: returnXmlType = part.getTypeName();
642: } else {
643: Part part = outputMessage.getPart(wsdlMessagePartName);
644: if (part == null) {
645: throw new OpenEJBException(
646: "No part for wsdlMessagePartName "
647: + wsdlMessagePartName
648: + " in output message for operation "
649: + operationName);
650: }
651:
652: returnQName = getPartName(part);
653: returnXmlType = returnQName;
654: }
655:
656: outParamNames.add(wsdlMessagePartName);
657: } else {
658: // what does this mean????
659: }
660:
661: operationInfo.returnQName = returnQName;
662: operationInfo.returnXmlType = returnXmlType;
663: operationInfo.returnJavaType = wsdlReturnValueMapping
664: .getMethodReturnValue();
665: }
666:
667: private JaxRpcFaultInfo mapFaults(Fault fault)
668: throws OpenEJBException {
669: Message message = fault.getMessage();
670: ExceptionMapping exceptionMapping = mapping
671: .getExceptionMappingMap().get(message.getQName());
672: if (exceptionMapping == null) {
673: throw new OpenEJBException(
674: "No exception mapping for fault " + fault.getName()
675: + " and fault message "
676: + message.getQName() + " for operation "
677: + operationName);
678: }
679:
680: // TODO investigate whether there are other cases in which the namespace of faultQName can be determined.
681: // this is weird, but I can't figure out what it should be.
682: // if part has an element rather than a type, it should be part.getElementName() (see below)
683: Part part;
684: if (exceptionMapping.getWsdlMessagePartName() != null) {
685: // According to schema documentation, this will only be set when several headerfaults use the same message.
686: String headerFaultMessagePartName = exceptionMapping
687: .getWsdlMessagePartName();
688: part = message.getPart(headerFaultMessagePartName);
689: } else {
690: part = (Part) message.getOrderedParts(null).iterator()
691: .next();
692: }
693:
694: // Determine the fault qname and xml schema type
695: QName faultQName;
696: XmlTypeInfo faultTypeInfo;
697: if (part.getElementName() != null) {
698: XmlElementInfo elementInfo = schemaInfo.elements.get(part
699: .getElementName());
700: if (elementInfo == null) {
701: throw new OpenEJBException("Can not find element: "
702: + part.getElementName() + ", known elements: "
703: + schemaInfo.elements.keySet());
704: }
705: faultTypeInfo = schemaInfo.types.get(elementInfo.xmlType);
706: if (faultTypeInfo == null) {
707: throw new OpenEJBException("Can not find type "
708: + elementInfo.xmlType + " for element "
709: + elementInfo.qname + ", known types: "
710: + schemaInfo.types.keySet());
711: }
712:
713: faultQName = part.getElementName();
714: } else if (part.getTypeName() != null) {
715: faultTypeInfo = schemaInfo.types.get(part.getTypeName());
716: if (faultTypeInfo == null) {
717: throw new OpenEJBException("Can not find type: "
718: + part.getTypeName() + ", known elements: "
719: + schemaInfo.types.keySet());
720: }
721:
722: faultQName = new QName("", fault.getName());
723: } else {
724: throw new OpenEJBException(
725: "Neither type nor element name supplied for part: "
726: + part);
727: }
728:
729: //
730: // Build the fault info
731: //
732: JaxRpcFaultInfo faultInfo = new JaxRpcFaultInfo();
733: faultInfo.qname = faultQName;
734: faultInfo.xmlType = faultTypeInfo.qname;
735: faultInfo.javaType = exceptionMapping.getExceptionType();
736: faultInfo.complex = faultTypeInfo.simpleBaseType == null;
737:
738: //
739: // Map exception class constructor args
740: //
741: if (exceptionMapping.getConstructorParameterOrder() != null) {
742: if (faultTypeInfo.simpleBaseType != null) {
743: throw new OpenEJBException(
744: "ConstructorParameterOrder can only be set for complex types, not "
745: + faultTypeInfo.qname);
746: }
747:
748: Map<String, XmlElementInfo> elements = new HashMap<String, XmlElementInfo>();
749: for (XmlElementInfo element : faultTypeInfo.elements
750: .values()) {
751: elements.put(element.qname.getLocalPart(), element);
752: }
753:
754: ConstructorParameterOrder constructorParameterOrder = exceptionMapping
755: .getConstructorParameterOrder();
756: for (int i = 0; i < constructorParameterOrder
757: .getElementName().size(); i++) {
758: String paramName = constructorParameterOrder
759: .getElementName().get(i);
760:
761: // get the parameter element
762: XmlElementInfo paramElementInfo = elements
763: .get(paramName);
764: if (paramElementInfo == null) {
765: throw new OpenEJBException("Can not find element "
766: + paramName + " in fault type "
767: + faultTypeInfo.qname
768: + ", known elements: " + elements.keySet());
769: }
770:
771: // Java Type
772: String paramJavaType = null;
773: XmlTypeInfo paramTypeInfo = schemaInfo.types
774: .get(paramElementInfo.xmlType);
775: if (paramTypeInfo != null) {
776: if (paramTypeInfo.anonymous) {
777: paramJavaType = anonymousTypes
778: .get(paramTypeInfo.qname.getLocalPart());
779: } else {
780: paramJavaType = publicTypes
781: .get(paramTypeInfo.qname);
782: }
783: }
784: // if we don't have a java type yet, check the simple types
785: if (paramJavaType == null) {
786: paramJavaType = qnameToJavaType
787: .get(paramElementInfo.xmlType);
788: }
789: if (paramJavaType == null) {
790: throw new OpenEJBException(
791: "No class mapped for element type: "
792: + paramElementInfo.xmlType);
793: }
794:
795: JaxRpcParameterInfo parameterInfo = new JaxRpcParameterInfo();
796: parameterInfo.qname = paramElementInfo.qname;
797: parameterInfo.mode = Mode.OUT;
798: // todo could be a soap header
799: parameterInfo.soapHeader = false;
800: parameterInfo.xmlType = paramElementInfo.xmlType;
801: parameterInfo.javaType = paramJavaType;
802:
803: faultInfo.parameters.add(parameterInfo);
804: }
805: }
806: return faultInfo;
807: }
808:
809: private QName getPartName(Part part) {
810: return part.getElementName() == null ? part.getTypeName()
811: : part.getElementName();
812: }
813:
814: private Part getWrappedPart(Message message)
815: throws OpenEJBException {
816: // a wrapped element can only have one part
817: Collection parts = message.getParts().values();
818: if (parts.size() != 1) {
819: throw new OpenEJBException(
820: "message "
821: + message.getQName()
822: + " has "
823: + parts.size()
824: + " parts and should only have one as wrapper style mapping is specified for operation "
825: + operationName);
826: }
827: return (Part) parts.iterator().next();
828: }
829:
830: private XmlElementInfo getWrapperChild(Part part,
831: String wsdlMessagePartName) throws OpenEJBException {
832: // get the part name
833: QName elementName = part.getElementName();
834: wrapperElementQNames.add(elementName);
835:
836: // get the wrapper element
837: XmlElementInfo wrapperElement = schemaInfo.elements
838: .get(elementName);
839: if (wrapperElement == null) {
840: throw new OpenEJBException("No global element named "
841: + elementName + " for operation " + operationName);
842: }
843:
844: // get the wrapper type
845: XmlTypeInfo wrapperType = schemaInfo.types
846: .get(wrapperElement.xmlType);
847: if (wrapperType == null) {
848: throw new OpenEJBException("Can not find type "
849: + wrapperElement.xmlType + " for element "
850: + wrapperElement.qname + ", known types: "
851: + schemaInfo.types.keySet());
852: }
853:
854: // get the part type
855: for (XmlElementInfo wrapperChild : wrapperType.elements
856: .values()) {
857: if (wrapperChild.qname.getLocalPart().equals(
858: wsdlMessagePartName)) {
859: return wrapperChild;
860: }
861: }
862: throw new OpenEJBException("Global element named "
863: + elementName
864: + " does not define a child element named "
865: + wsdlMessagePartName + " required by the operation "
866: + operationName);
867: }
868:
869: //see jaxrpc 1.1 4.2.1
870: private static final Map<QName, String> qnameToJavaType = new HashMap<QName, String>();
871:
872: static {
873: qnameToJavaType.put(new QName(
874: "http://www.w3.org/2001/XMLSchema", "string"),
875: String.class.getName());
876: qnameToJavaType.put(new QName(
877: "http://www.w3.org/2001/XMLSchema", "integer"),
878: BigInteger.class.getName());
879: qnameToJavaType.put(new QName(
880: "http://www.w3.org/2001/XMLSchema", "int"), int.class
881: .getName());
882: qnameToJavaType.put(new QName(
883: "http://www.w3.org/2001/XMLSchema", "long"), long.class
884: .getName());
885: qnameToJavaType.put(new QName(
886: "http://www.w3.org/2001/XMLSchema", "short"),
887: short.class.getName());
888: qnameToJavaType.put(new QName(
889: "http://www.w3.org/2001/XMLSchema", "decimal"),
890: BigDecimal.class.getName());
891: qnameToJavaType.put(new QName(
892: "http://www.w3.org/2001/XMLSchema", "float"),
893: float.class.getName());
894: qnameToJavaType.put(new QName(
895: "http://www.w3.org/2001/XMLSchema", "double"),
896: double.class.getName());
897: qnameToJavaType.put(new QName(
898: "http://www.w3.org/2001/XMLSchema", "boolean"),
899: boolean.class.getName());
900: qnameToJavaType.put(new QName(
901: "http://www.w3.org/2001/XMLSchema", "byte"), byte.class
902: .getName());
903: qnameToJavaType.put(new QName(
904: "http://www.w3.org/2001/XMLSchema", "unsignedInt"),
905: long.class.getName());
906: qnameToJavaType.put(new QName(
907: "http://www.w3.org/2001/XMLSchema", "unsignedShort"),
908: int.class.getName());
909: qnameToJavaType.put(new QName(
910: "http://www.w3.org/2001/XMLSchema", "unsignedByte"),
911: short.class.getName());
912: qnameToJavaType.put(new QName(
913: "http://www.w3.org/2001/XMLSchema", "QName"),
914: QName.class.getName());
915: qnameToJavaType.put(new QName(
916: "http://www.w3.org/2001/XMLSchema", "dateTime"),
917: Calendar.class.getName());
918: qnameToJavaType.put(new QName(
919: "http://www.w3.org/2001/XMLSchema", "date"),
920: Calendar.class.getName());
921: qnameToJavaType.put(new QName(
922: "http://www.w3.org/2001/XMLSchema", "time"),
923: Calendar.class.getName());
924: qnameToJavaType.put(new QName(
925: "http://www.w3.org/2001/XMLSchema", "anyURI"),
926: URI.class.getName());
927: qnameToJavaType.put(new QName(
928: "http://www.w3.org/2001/XMLSchema", "base64Binary"),
929: byte[].class.getName());
930: qnameToJavaType.put(new QName(
931: "http://www.w3.org/2001/XMLSchema", "hexBinary"),
932: byte[].class.getName());
933: qnameToJavaType.put(new QName(
934: "http://www.w3.org/2001/XMLSchema", "anySimpleType"),
935: String.class.getName());
936: }
937:
938: /**
939: * Supporting the Document/Literal Wrapped pattern
940: *
941: * See http://www-106.ibm.com/developerworks/webservices/library/ws-whichwsdl/ for a nice explanation and example
942: *
943: * wrapped-element tag is used
944: * WSDL message with a single part
945: * part uses the 'element' attribute to point to an elemement in the types section
946: * the element type and the element's name match the operation name
947: */
948:
949: // standard holder classes by type
950: private static final Map<String, String> rpcHolderClasses = new HashMap<String, String>();
951:
952: static {
953: rpcHolderClasses.put(BigDecimal.class.getName(),
954: BigDecimalHolder.class.getName());
955: rpcHolderClasses.put(BigInteger.class.getName(),
956: BigIntegerHolder.class.getName());
957: rpcHolderClasses.put(boolean.class.getName(),
958: BooleanHolder.class.getName());
959: rpcHolderClasses.put(Boolean.class.getName(),
960: BooleanWrapperHolder.class.getName());
961: rpcHolderClasses.put(byte[].class.getName(),
962: ByteArrayHolder.class.getName());
963: rpcHolderClasses.put(byte.class.getName(), ByteHolder.class
964: .getName());
965: rpcHolderClasses.put(Byte.class.getName(),
966: ByteWrapperHolder.class.getName());
967: rpcHolderClasses.put(Calendar.class.getName(),
968: CalendarHolder.class.getName());
969: rpcHolderClasses.put(double.class.getName(), DoubleHolder.class
970: .getName());
971: rpcHolderClasses.put(Double.class.getName(),
972: DoubleWrapperHolder.class.getName());
973: rpcHolderClasses.put(float.class.getName(), FloatHolder.class
974: .getName());
975: rpcHolderClasses.put(Float.class.getName(),
976: FloatWrapperHolder.class.getName());
977: rpcHolderClasses.put(int.class.getName(), IntHolder.class
978: .getName());
979: rpcHolderClasses.put(Integer.class.getName(),
980: IntegerWrapperHolder.class.getName());
981: rpcHolderClasses.put(long.class.getName(), LongHolder.class
982: .getName());
983: rpcHolderClasses.put(Long.class.getName(),
984: LongWrapperHolder.class.getName());
985: rpcHolderClasses.put(Object.class.getName(), ObjectHolder.class
986: .getName());
987: rpcHolderClasses.put(QName.class.getName(), QNameHolder.class
988: .getName());
989: rpcHolderClasses.put(short.class.getName(), ShortHolder.class
990: .getName());
991: rpcHolderClasses.put(Short.class.getName(),
992: ShortWrapperHolder.class.getName());
993: rpcHolderClasses.put(String.class.getName(), StringHolder.class
994: .getName());
995: }
996: }
|