001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with 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,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.jaxws.marshaller.impl.alt;
020:
021: import org.apache.axis2.jaxws.ExceptionFactory;
022: import org.apache.axis2.jaxws.description.EndpointDescription;
023: import org.apache.axis2.jaxws.description.EndpointInterfaceDescription;
024: import org.apache.axis2.jaxws.description.OperationDescription;
025: import org.apache.axis2.jaxws.description.ParameterDescription;
026: import org.apache.axis2.jaxws.i18n.Messages;
027: import org.apache.axis2.jaxws.marshaller.MethodMarshaller;
028: import org.apache.axis2.jaxws.message.Block;
029: import org.apache.axis2.jaxws.message.Message;
030: import org.apache.axis2.jaxws.message.Protocol;
031: import org.apache.axis2.jaxws.message.databinding.JAXBBlockContext;
032: import org.apache.axis2.jaxws.message.databinding.JAXBUtils;
033: import org.apache.axis2.jaxws.message.factory.JAXBBlockFactory;
034: import org.apache.axis2.jaxws.message.factory.MessageFactory;
035: import org.apache.axis2.jaxws.registry.FactoryRegistry;
036: import org.apache.axis2.jaxws.runtime.description.marshal.MarshalServiceRuntimeDescription;
037: import org.apache.axis2.jaxws.utility.ConvertUtils;
038: import org.apache.axis2.jaxws.wrapper.JAXBWrapperTool;
039: import org.apache.axis2.jaxws.wrapper.impl.JAXBWrapperToolImpl;
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042:
043: import javax.jws.WebParam.Mode;
044: import javax.xml.bind.JAXBElement;
045: import javax.xml.namespace.QName;
046: import javax.xml.ws.WebServiceException;
047: import java.lang.annotation.Annotation;
048: import java.util.ArrayList;
049: import java.util.HashMap;
050: import java.util.Iterator;
051: import java.util.List;
052: import java.util.Map;
053: import java.util.TreeSet;
054:
055: /**
056: * The DocLitWrapped "plus" marshaller is used when the java method is doc/lit wrapped, but it does
057: * not exactly comply with the doc/lit rules. This can result from the customer adding annotations,
058: * but it can also be the result of WSGEN generation
059: * <p/>
060: * Here is an example:
061: *
062: * @WebMethod(action = "http://addheaders.sample.test.org/echoStringWSGEN1")
063: * @RequestWrapper(localName = "echoStringWSGEN1", targetNamespace = "http://wrap.sample.test.org",
064: * className = "org.test.sample.wrap.EchoStringWSGEN1")
065: * @ResponseWrapper(localName = "echoStringWSGEN1Response", targetNamespace =
066: * "http://wrap.sample.test.org", className = "org.test.sample.wrap.EchoStringWSGEN1Response")
067: * public String echoStringWSGEN1(
068: * @WebParam(name = "headerValue", targetNamespace = "http://wrap.sample.test.org", header = true)
069: * String headerValue )
070: * <p/>
071: * In this case the method is doc/lit, but the headerValue parameter is passed in the header. The
072: * wrapper class EchoStringWSGEN1 will not have any child elements.
073: * <p/>
074: * A similar example is:
075: * @WebMethod(action = "http://addheaders.sample.test.org/echoStringWSGEN2")
076: * @RequestWrapper(localName = "echoStringWSGEN2", targetNamespace = "http://wrap.sample.test.org",
077: * className = "org.test.sample.wrap.EchoStringWSGEN2")
078: * @ResponseWrapper(localName = "echoStringWSGEN2Response", targetNamespace =
079: * "http://wrap.sample.test.org", className = "org.test.sample.wrap.EchoStringWSGEN2Response")
080: * @WebResult(name = "headerValue", targetNamespace = "http://wrap.sample.test.org", header = true)
081: * public String echoStringWSGEN2(
082: * @WebParam(name = "data", targetNamespace = "") String data )
083: * <p/>
084: * In this second case, the return is passed in a header (as defined by @WebResult)
085: * <p/>
086: * At the time of this writing, the "plus" marshaller is only used if a doc/lit wrapped method has
087: * "header" parameters. If other deviations are found, this class will be updated. The advantage
088: * of using DocLitWrapperPlus for these deviations is that it does not impact the normal
089: * DocLitWrapper marshalling (which is used for 99% of the cases). Thus these deviations will not
090: * polute or slow down the normal flow.
091: * <p/>
092: * Scheu
093: */
094: public class DocLitWrappedPlusMethodMarshaller implements
095: MethodMarshaller {
096:
097: private static Log log = LogFactory
098: .getLog(DocLitWrappedPlusMethodMarshaller.class);
099:
100: public DocLitWrappedPlusMethodMarshaller() {
101: super ();
102: }
103:
104: public Object demarshalResponse(Message message,
105: Object[] signatureArgs, OperationDescription operationDesc)
106: throws WebServiceException {
107: if (log.isDebugEnabled()) {
108: log
109: .debug("Calling DocLitWrapperPlusMethodMarshaller.demarshalResponse");
110: log
111: .debug(" The DocLitWrapped Plus marshaller is used when the web service method deviates from the normal doc/lit rules.");
112: }
113: // Note all exceptions are caught and rethrown with a WebServiceException
114:
115: EndpointInterfaceDescription ed = operationDesc
116: .getEndpointInterfaceDescription();
117: EndpointDescription endpointDesc = ed.getEndpointDescription();
118:
119: try {
120: // Sample Document message
121: // ..
122: // <soapenv:body>
123: // <m:operationResponse ... >
124: // <param>hello</param>
125: // </m:operationResponse>
126: // </soapenv:body>
127: //
128: // Important points.
129: // 1) There is no operation element in the message
130: // 2) The data blocks are located underneath the body element.
131: // 3) The name of the data block (m:operationResponse) is defined by the schema.
132: // It matches the operation name + "Response", and it has a corresponding JAXB element.
133: // This element is called the wrapper element
134: // 4) The parameters are (param) are child elements of the wrapper element.
135: ParameterDescription[] pds = operationDesc
136: .getParameterDescriptions();
137: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
138: .getMarshalDesc(endpointDesc);
139: TreeSet<String> packages = marshalDesc.getPackages();
140: String packagesKey = marshalDesc.getPackagesKey();
141:
142: // Determine if a returnValue is expected.
143: // The return value may be an child element
144: // The wrapper element
145: // or null
146: Object returnValue = null;
147: Class returnType = operationDesc.getResultActualType();
148: boolean isChildReturn = !operationDesc
149: .isJAXWSAsyncClientMethod()
150: && (operationDesc.getResultPartName() != null);
151: boolean isNoReturn = (returnType == void.class);
152:
153: // In usage=WRAPPED, there will be a single JAXB block inside the body.
154: // Get this block
155: JAXBBlockContext blockContext = new JAXBBlockContext(
156: packages, packagesKey);
157: JAXBBlockFactory factory = (JAXBBlockFactory) FactoryRegistry
158: .getFactory(JAXBBlockFactory.class);
159: Block block = message.getBodyBlock(blockContext, factory);
160: Object wrapperObject = block.getBusinessObject(true);
161:
162: // The child elements are within the object that
163: // represents the type
164: if (wrapperObject instanceof JAXBElement) {
165: wrapperObject = ((JAXBElement) wrapperObject)
166: .getValue();
167: }
168:
169: // Use the wrapper tool to get the child objects.
170: JAXBWrapperTool wrapperTool = new JAXBWrapperToolImpl();
171:
172: // Get the list of names for the output parameters
173: List<String> names = new ArrayList<String>();
174: List<ParameterDescription> pdList = new ArrayList<ParameterDescription>();
175: for (int i = 0; i < pds.length; i++) {
176: ParameterDescription pd = pds[i];
177: if (pd.getMode() == Mode.OUT
178: || pd.getMode() == Mode.INOUT) {
179: if (!pd.isHeader()) {
180: // Header names are not in the wrapped element
181: names.add(pd.getParameterName());
182: }
183: pdList.add(pd);
184: }
185: }
186:
187: if (!operationDesc.isResultHeader()) {
188: // Normal case (Body Result) The return name is in the wrapped object
189: if (isChildReturn && !isNoReturn) {
190: names.add(operationDesc.getResultPartName());
191: }
192: }
193:
194: // Get the child objects
195: Object[] objects = wrapperTool.unWrap(wrapperObject, names,
196: marshalDesc.getPropertyDescriptorMap(wrapperObject
197: .getClass()));
198:
199: // Now create a list of paramValues so that we can populate the signature
200: List<PDElement> pvList = new ArrayList<PDElement>();
201: int bodyIndex = 0;
202: for (int i = 0; i < pdList.size(); i++) {
203: ParameterDescription pd = pdList.get(i);
204: if (!pd.isHeader()) {
205: // Body elements are obtained from the unwrapped array of objects
206: Object value = objects[bodyIndex];
207: // The object in the PDElement must be an element
208: QName qName = new QName(pd.getTargetNamespace(), pd
209: .getPartName());
210: Element element = null;
211: if (!marshalDesc.getAnnotationDesc(
212: pd.getParameterActualType())
213: .hasXmlRootElement()) {
214: element = new Element(value, qName, pd
215: .getParameterActualType());
216: } else {
217: element = new Element(value, qName);
218: }
219: pvList.add(new PDElement(pd, element, null));
220: bodyIndex++;
221: } else {
222: // Header
223: // Get the Block from the header
224: String localName = pd.getParameterName();
225: JAXBBlockContext blkContext = new JAXBBlockContext(
226: packages, packagesKey);
227:
228: // Set up "by java type" unmarshalling if necessary
229: if (blkContext.getConstructionType() != JAXBUtils.CONSTRUCTION_TYPE.BY_CONTEXT_PATH) {
230: Class actualType = pd.getParameterActualType();
231: if (MethodMarshallerUtils.isNotJAXBRootElement(
232: actualType, marshalDesc)) {
233: blkContext.setProcessType(actualType);
234: blkContext.setIsxmlList(pd.isListType());
235: }
236: }
237: block = message.getHeaderBlock(pd
238: .getTargetNamespace(), localName,
239: blkContext, factory);
240: Object value = block.getBusinessObject(true);
241: Element element = new Element(value, new QName(pd
242: .getTargetNamespace(), localName));
243: pvList.add(new PDElement(pd, element, blkContext
244: .getProcessType()));
245: }
246: }
247:
248: // Populate the response Holders in the signature
249: MethodMarshallerUtils.updateResponseSignatureArgs(pds,
250: pvList, signatureArgs);
251:
252: // Now get the return value
253:
254: if (isNoReturn) {
255: returnValue = null;
256: } else if (isChildReturn) {
257: if (!operationDesc.isResultHeader()) {
258: // Normal: Get the return from the jaxb object
259: returnValue = objects[objects.length - 1];
260: } else {
261: // Header result: Get the value from the headers
262: Element returnElement = MethodMarshallerUtils
263: .getReturnElement(
264: packages,
265: message,
266: null,
267: false,
268: true,
269: operationDesc
270: .getResultTargetNamespace(),
271: operationDesc.getResultPartName(),
272: false);
273: returnValue = returnElement.getTypeValue();
274: }
275: // returnValue may be incompatible with JAX-WS signature
276: if (ConvertUtils.isConvertable(returnValue, returnType)) {
277: returnValue = ConvertUtils.convert(returnValue,
278: returnType);
279: } else {
280: String objectClass = (returnValue == null) ? "null"
281: : returnValue.getClass().getName();
282: throw ExceptionFactory
283: .makeWebServiceException(Messages
284: .getMessage("convertProblem",
285: objectClass, returnType
286: .getName()));
287: }
288: } else {
289: returnValue = wrapperObject;
290: }
291:
292: return returnValue;
293: } catch (Exception e) {
294: throw ExceptionFactory.makeWebServiceException(e);
295: }
296: }
297:
298: public Object[] demarshalRequest(Message message,
299: OperationDescription operationDesc)
300: throws WebServiceException {
301:
302: if (log.isDebugEnabled()) {
303: log
304: .debug("Calling DocLitWrapperPlusMethodMarshaller.demarshalRequest");
305: log
306: .debug(" The DocLitWrapped Plus marshaller is used when the web service method deviates from the normal doc/lit rules.");
307: }
308: EndpointInterfaceDescription ed = operationDesc
309: .getEndpointInterfaceDescription();
310: EndpointDescription endpointDesc = ed.getEndpointDescription();
311:
312: // Note all exceptions are caught and rethrown with a WebServiceException
313: try {
314: // Sample Document message
315: // ..
316: // <soapenv:body>
317: // <m:operation>
318: // <param>hello</param>
319: // </m:operation>
320: // </soapenv:body>
321: //
322: // Important points.
323: // 1) There is no operation element under the body.
324: // 2) The data blocks are located underneath the body.
325: // 3) The name of the data block (m:operation) is defined by the schema and match the name of the operation.
326: // This is called the wrapper element. The wrapper element has a corresponding JAXB element pojo.
327: // 4) The parameters (m:param) are child elements of the wrapper element.
328: ParameterDescription[] pds = operationDesc
329: .getParameterDescriptions();
330: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
331: .getMarshalDesc(endpointDesc);
332: TreeSet<String> packages = marshalDesc.getPackages();
333: String packagesKey = marshalDesc.getPackagesKey();
334:
335: // In usage=WRAPPED, there will be a single JAXB block inside the body.
336: // Get this block
337: JAXBBlockContext blockContext = new JAXBBlockContext(
338: packages, packagesKey);
339: JAXBBlockFactory factory = (JAXBBlockFactory) FactoryRegistry
340: .getFactory(JAXBBlockFactory.class);
341: Block block = message.getBodyBlock(blockContext, factory);
342: Object wrapperObject = block.getBusinessObject(true);
343:
344: // The child elements are within the object that
345: // represents the type
346: if (wrapperObject instanceof JAXBElement) {
347: wrapperObject = ((JAXBElement) wrapperObject)
348: .getValue();
349: }
350:
351: // Use the wrapper tool to get the child objects.
352: JAXBWrapperTool wrapperTool = new JAXBWrapperToolImpl();
353:
354: // Get the list of names for the input parameters
355: List<String> xmlNames = new ArrayList<String>();
356: List<ParameterDescription> pdList = new ArrayList<ParameterDescription>();
357: for (int i = 0; i < pds.length; i++) {
358: ParameterDescription pd = pds[i];
359: if (pd.getMode() == Mode.IN
360: || pd.getMode() == Mode.INOUT) {
361: if (!pd.isHeader()) {
362: // Only the body parameters will be present in the wrapper object
363: xmlNames.add(pd.getParameterName());
364: }
365: pdList.add(pd);
366: }
367:
368: }
369:
370: // Get the child objects
371: Object[] objects = wrapperTool.unWrap(wrapperObject,
372: xmlNames, marshalDesc
373: .getPropertyDescriptorMap(wrapperObject
374: .getClass()));
375:
376: // Now create a list of paramValues
377: List<PDElement> pvList = new ArrayList<PDElement>();
378: int bodyIndex = 0;
379: for (int i = 0; i < pdList.size(); i++) {
380: ParameterDescription pd = pdList.get(i);
381: if (!pd.isHeader()) {
382: // Normal case: Get the parameter value from the list of objects
383: Object value = objects[bodyIndex];
384:
385: // The object in the PDElement must be an element
386: QName qName = new QName(pd.getTargetNamespace(), pd
387: .getPartName());
388: Element element = null;
389: if (!marshalDesc.getAnnotationDesc(
390: pd.getParameterActualType())
391: .hasXmlRootElement()) {
392: element = new Element(value, qName, pd
393: .getParameterActualType());
394: } else {
395: element = new Element(value, qName);
396: }
397: pvList.add(new PDElement(pd, element, null));
398: bodyIndex++;
399: } else {
400: // Header
401: // Get the Block from the header
402: String localName = pd.getParameterName();
403: JAXBBlockContext blkContext = new JAXBBlockContext(
404: packages, marshalDesc.getPackagesKey());
405: // Set up "by java type" unmarshalling if necessary
406: if (blkContext.getConstructionType() != JAXBUtils.CONSTRUCTION_TYPE.BY_CONTEXT_PATH) {
407: Class actualType = pd.getParameterActualType();
408: if (MethodMarshallerUtils.isNotJAXBRootElement(
409: actualType, marshalDesc)) {
410: blkContext.setProcessType(actualType);
411: } else {
412: Annotation annos[] = actualType
413: .getAnnotations();
414: if (annos == null || annos.length == 0) {
415: blkContext.setProcessType(actualType);
416: blkContext
417: .setIsxmlList(pd.isListType());
418: }
419: }
420: }
421: block = message.getHeaderBlock(pd
422: .getTargetNamespace(), localName,
423: blkContext, factory);
424: Object value = block.getBusinessObject(true);
425: Element element = new Element(value, new QName(pd
426: .getTargetNamespace(), localName));
427: pvList.add(new PDElement(pd, element, blkContext
428: .getProcessType()));
429: }
430:
431: }
432:
433: // Build the signature arguments
434: Object[] sigArguments = MethodMarshallerUtils
435: .createRequestSignatureArgs(pds, pvList);
436:
437: return sigArguments;
438: } catch (Exception e) {
439: throw ExceptionFactory.makeWebServiceException(e);
440: }
441: }
442:
443: public Message marshalResponse(Object returnObject,
444: Object[] signatureArgs, OperationDescription operationDesc,
445: Protocol protocol) throws WebServiceException {
446: if (log.isDebugEnabled()) {
447: log
448: .debug("Calling DocLitWrapperPlusMethodMarshaller.marshalResponse");
449: log
450: .debug(" The DocLitWrapped Plus marshaller is used when the web service method deviates from the normal doc/lit rules.");
451: }
452: EndpointInterfaceDescription ed = operationDesc
453: .getEndpointInterfaceDescription();
454: EndpointDescription endpointDesc = ed.getEndpointDescription();
455: // We want to respond with the same protocol as the request,
456: // It the protocol is null, then use the Protocol defined by the binding
457: if (protocol == null) {
458: protocol = Protocol.getProtocolForBinding(endpointDesc
459: .getBindingType());
460: }
461:
462: // Note all exceptions are caught and rethrown with a WebServiceException
463: try {
464: // Sample Document message
465: // ..
466: // <soapenv:body>
467: // <m:operationResponse ... >
468: // <param>hello</param>
469: // </m:operationResponse>
470: // </soapenv:body>
471: //
472: // Important points.
473: // 1) There is no operation element in the message
474: // 2) The data blocks are located underneath the body element.
475: // 3) The name of the data block (m:operationResponse) is defined by the schema.
476: // It matches the operation name + "Response", and it has a corresponding JAXB element.
477: // This element is called the wrapper element
478: // 4) The parameters are (param) are child elements of the wrapper element.
479:
480: // Get the operation information
481: ParameterDescription[] pds = operationDesc
482: .getParameterDescriptions();
483: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
484: .getMarshalDesc(endpointDesc);
485: TreeSet<String> packages = marshalDesc.getPackages();
486: String packagesKey = marshalDesc.getPackagesKey();
487:
488: // Create the message
489: MessageFactory mf = (MessageFactory) FactoryRegistry
490: .getFactory(MessageFactory.class);
491: Message m = mf.create(protocol);
492:
493: // In usage=WRAPPED, there will be a single block in the body.
494: // The signatureArguments represent the child elements of that block
495: // The first step is to convert the signature arguments into a list
496: // of parameter values
497: List<PDElement> pdeList = MethodMarshallerUtils
498: .getPDElements(marshalDesc, pds, signatureArgs,
499: false, // output
500: true, false);
501:
502: // Now we want to create a single JAXB element that contains the
503: // parameter values. We will use the wrapper tool to do this.
504: // Create the inputs to the wrapper tool
505: ArrayList<String> nameList = new ArrayList<String>();
506: Map<String, Object> objectList = new HashMap<String, Object>();
507: List<PDElement> headerPDEList = new ArrayList<PDElement>();
508:
509: Iterator<PDElement> it = pdeList.iterator();
510: while (it.hasNext()) {
511: PDElement pde = it.next();
512: String name = pde.getParam().getParameterName();
513: if (!pde.getParam().isHeader()) {
514: // Normal case
515: // The object list contains type rendered objects
516: Object value = pde.getElement().getTypeValue();
517: nameList.add(name);
518: objectList.put(name, value);
519: } else {
520: // Header Case:
521: // Remove the header from the list, it will
522: // not be placed in the wrapper
523: it.remove();
524: headerPDEList.add(pde);
525: }
526: }
527:
528: Class returnType = operationDesc.getResultActualType();
529: if (!operationDesc.isResultHeader()) {
530: // Normal (Body Result): Add the return object to the nameList and objectList
531:
532: if (returnType != void.class) {
533: String name = operationDesc.getResultName();
534: nameList.add(name);
535: objectList.put(name, returnObject);
536: }
537: } else {
538: // Header Result:
539: // Put the return object onto the message
540: if (returnType != void.class) {
541: Element returnElement = null;
542: QName returnQName = new QName(operationDesc
543: .getResultTargetNamespace(), operationDesc
544: .getResultName());
545: if (marshalDesc.getAnnotationDesc(returnType)
546: .hasXmlRootElement()) {
547: returnElement = new Element(returnObject,
548: returnQName);
549: } else {
550: returnElement = new Element(returnObject,
551: returnQName, returnType);
552: }
553:
554: Class byJavaType = MethodMarshallerUtils
555: .isNotJAXBRootElement(returnType,
556: marshalDesc) ? returnType : null;
557:
558: MethodMarshallerUtils.toMessage(returnElement,
559: returnType, operationDesc.isListType(),
560: marshalDesc, m, byJavaType, true);
561: }
562: }
563:
564: // Now create the single JAXB element
565: String wrapperName = marshalDesc
566: .getResponseWrapperClassName(operationDesc);
567: Class cls = MethodMarshallerUtils.loadClass(wrapperName);
568: JAXBWrapperTool wrapperTool = new JAXBWrapperToolImpl();
569: Object object = wrapperTool.wrap(cls, nameList, objectList,
570: marshalDesc.getPropertyDescriptorMap(cls));
571:
572: QName wrapperQName = new QName(operationDesc
573: .getResponseWrapperTargetNamespace(), operationDesc
574: .getResponseWrapperLocalName());
575:
576: // Make sure object can be rendered as an element
577: if (!marshalDesc.getAnnotationDesc(cls).hasXmlRootElement()) {
578: object = new JAXBElement(wrapperQName, cls, object);
579: }
580:
581: // Put the object into the message
582: JAXBBlockFactory factory = (JAXBBlockFactory) FactoryRegistry
583: .getFactory(JAXBBlockFactory.class);
584:
585: Block block = factory.createFrom(object,
586: new JAXBBlockContext(packages, packagesKey),
587: wrapperQName); // The factory will get the qname from the value
588: m.setBodyBlock(block);
589:
590: // Now place the headers in the message
591: if (headerPDEList.size() > 0) {
592:
593: // Use "by java type" marshalling if necessary
594: for (PDElement pde : headerPDEList) {
595: Class actualType = pde.getParam()
596: .getParameterActualType();
597: if (MethodMarshallerUtils.isNotJAXBRootElement(
598: actualType, marshalDesc)) {
599: pde.setByJavaTypeClass(actualType);
600: }
601: }
602: MethodMarshallerUtils.toMessage(headerPDEList, m,
603: packages);
604: }
605: return m;
606: } catch (Exception e) {
607: throw ExceptionFactory.makeWebServiceException(e);
608: }
609: }
610:
611: public Message marshalRequest(Object[] signatureArguments,
612: OperationDescription operationDesc)
613: throws WebServiceException {
614: if (log.isDebugEnabled()) {
615: log
616: .debug("Calling DocLitWrapperPlusMethodMarshaller.marshalRequest");
617: log
618: .debug(" The DocLitWrapped Plus marshaller is used when the web service method deviates from the normal doc/lit rules.");
619: }
620: EndpointInterfaceDescription ed = operationDesc
621: .getEndpointInterfaceDescription();
622: EndpointDescription endpointDesc = ed.getEndpointDescription();
623: Protocol protocol = Protocol.getProtocolForBinding(endpointDesc
624: .getClientBindingID());
625: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
626: .getMarshalDesc(endpointDesc);
627: TreeSet<String> packages = marshalDesc.getPackages();
628: String packagesKey = marshalDesc.getPackagesKey();
629:
630: // Note all exceptions are caught and rethrown with a WebServiceException
631: try {
632: // Sample Document message
633: // ..
634: // <soapenv:body>
635: // <m:operation>
636: // <param>hello</param>
637: // </m:operation>
638: // </soapenv:body>
639: //
640: // Important points.
641: // 1) There is no operation element under the body.
642: // 2) The data blocks are located underneath the body.
643: // 3) The name of the data block (m:operation) is defined by the schema and match the name of the operation.
644: // This is called the wrapper element. The wrapper element has a corresponding JAXB element pojo.
645: // 4) The parameters (m:param) are child elements of the wrapper element.
646:
647: // Get the operation information
648: ParameterDescription[] pds = operationDesc
649: .getParameterDescriptions();
650:
651: // Create the message
652: MessageFactory mf = (MessageFactory) FactoryRegistry
653: .getFactory(MessageFactory.class);
654: Message m = mf.create(protocol);
655:
656: // In usage=WRAPPED, there will be a single block in the body.
657: // The signatureArguments represent the child elements of that block
658: // The first step is to convert the signature arguments into list
659: // of parameter values
660: List<PDElement> pdeList = MethodMarshallerUtils
661: .getPDElements(marshalDesc, pds,
662: signatureArguments, true, // input
663: true, false);
664:
665: // Now we want to create a single JAXB element that contains the
666: // ParameterValues. We will use the wrapper tool to do this.
667: // Create the inputs to the wrapper tool
668: ArrayList<String> nameList = new ArrayList<String>();
669: Map<String, Object> objectList = new HashMap<String, Object>();
670: List<PDElement> headerPDEList = new ArrayList<PDElement>();
671:
672: Iterator<PDElement> it = pdeList.iterator();
673: while (it.hasNext()) {
674: PDElement pde = it.next();
675: String name = pde.getParam().getParameterName();
676: if (!pde.getParam().isHeader()) {
677: // Normal case:
678: // The object list contains type rendered objects
679: Object value = pde.getElement().getTypeValue();
680: nameList.add(name);
681: objectList.put(name, value);
682: } else {
683: // Header Case:
684: // Remove the header from the list, it will
685: // not be placed in the wrapper
686: it.remove();
687: headerPDEList.add(pde);
688: }
689: }
690:
691: // Now create the single JAXB element
692: String wrapperName = marshalDesc
693: .getRequestWrapperClassName(operationDesc);
694: Class cls = MethodMarshallerUtils.loadClass(wrapperName);
695: JAXBWrapperTool wrapperTool = new JAXBWrapperToolImpl();
696: Object object = wrapperTool.wrap(cls, nameList, objectList,
697: marshalDesc.getPropertyDescriptorMap(cls));
698:
699: QName wrapperQName = new QName(operationDesc
700: .getRequestWrapperTargetNamespace(), operationDesc
701: .getRequestWrapperLocalName());
702:
703: // Make sure object can be rendered as an element
704: if (!marshalDesc.getAnnotationDesc(cls).hasXmlRootElement()) {
705: object = new JAXBElement(wrapperQName, cls, object);
706: }
707:
708: // Put the object into the message
709: JAXBBlockFactory factory = (JAXBBlockFactory) FactoryRegistry
710: .getFactory(JAXBBlockFactory.class);
711: Block block = factory.createFrom(object,
712: new JAXBBlockContext(packages, packagesKey),
713: wrapperQName); // The factory will get the qname from the value
714: m.setBodyBlock(block);
715:
716: // Now place the headers in the message
717: if (headerPDEList.size() > 0) {
718:
719: // Use "by java type" marshalling if necessary
720: for (PDElement pde : headerPDEList) {
721: Class actualType = pde.getParam()
722: .getParameterActualType();
723: if (MethodMarshallerUtils.isNotJAXBRootElement(
724: actualType, marshalDesc)) {
725: pde.setByJavaTypeClass(actualType);
726: }
727: }
728:
729: MethodMarshallerUtils.toMessage(headerPDEList, m,
730: packages);
731: }
732: return m;
733: } catch (Exception e) {
734: throw ExceptionFactory.makeWebServiceException(e);
735: }
736: }
737:
738: public Message marshalFaultResponse(Throwable throwable,
739: OperationDescription operationDesc, Protocol protocol)
740: throws WebServiceException {
741: if (log.isDebugEnabled()) {
742: log
743: .debug("Calling DocLitWrapperPlusMethodMarshaller.marshalFaultResponse");
744: log
745: .debug(" The DocLitWrapped Plus marshaller is used when the web service method deviates from the normal doc/lit rules.");
746: }
747: EndpointInterfaceDescription ed = operationDesc
748: .getEndpointInterfaceDescription();
749: EndpointDescription endpointDesc = ed.getEndpointDescription();
750: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
751: .getMarshalDesc(endpointDesc);
752: TreeSet<String> packages = marshalDesc.getPackages();
753:
754: // We want to respond with the same protocol as the request,
755: // It the protocol is null, then use the Protocol defined by the binding
756: if (protocol == null) {
757: protocol = Protocol.getProtocolForBinding(endpointDesc
758: .getBindingType());
759: }
760:
761: // Note all exceptions are caught and rethrown with a WebServiceException
762: try {
763: // Create the message
764: MessageFactory mf = (MessageFactory) FactoryRegistry
765: .getFactory(MessageFactory.class);
766: Message m = mf.create(protocol);
767:
768: // Put the fault onto the message
769: MethodMarshallerUtils.marshalFaultResponse(throwable,
770: marshalDesc, operationDesc, m);
771: return m;
772: } catch (Exception e) {
773: throw ExceptionFactory.makeWebServiceException(e);
774: }
775: }
776:
777: public Throwable demarshalFaultResponse(Message message,
778: OperationDescription operationDesc)
779: throws WebServiceException {
780: if (log.isDebugEnabled()) {
781: log
782: .debug("Calling DocLitWrapperPlusMethodMarshaller.demarshalFaultResponse");
783: log
784: .debug(" The DocLitWrapped Plus marshaller is used when the web service method deviates from the normal doc/lit rules.");
785: }
786: EndpointInterfaceDescription ed = operationDesc
787: .getEndpointInterfaceDescription();
788: EndpointDescription endpointDesc = ed.getEndpointDescription();
789: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
790: .getMarshalDesc(endpointDesc);
791:
792: // Note all exceptions are caught and rethrown with a WebServiceException
793: try {
794: Throwable t = MethodMarshallerUtils.demarshalFaultResponse(
795: operationDesc, marshalDesc, message);
796: return t;
797: } catch (Exception e) {
798: throw ExceptionFactory.makeWebServiceException(e);
799: }
800: }
801:
802: }
|