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.Message;
029: import org.apache.axis2.jaxws.message.Protocol;
030: import org.apache.axis2.jaxws.message.factory.MessageFactory;
031: import org.apache.axis2.jaxws.registry.FactoryRegistry;
032: import org.apache.axis2.jaxws.runtime.description.marshal.MarshalServiceRuntimeDescription;
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035:
036: import javax.jws.soap.SOAPBinding.Style;
037: import javax.xml.namespace.QName;
038: import javax.xml.ws.WebServiceException;
039: import java.util.List;
040: import java.util.TreeSet;
041:
042: /**
043: * The Doc/Lit Wrapped Minimal Marshaller is used when 1) The web service is Doc/Lit Wrapped, and 2)
044: * The wrapper and fault bean objects are missing (hence the term 'Minimal')
045: */
046: public class DocLitWrappedMinimalMethodMarshaller implements
047: MethodMarshaller {
048:
049: private static Log log = LogFactory
050: .getLog(DocLitWrappedMinimalMethodMarshaller.class);
051:
052: public DocLitWrappedMinimalMethodMarshaller() {
053: super ();
054: }
055:
056: public Message marshalRequest(Object[] signatureArguments,
057: OperationDescription operationDesc)
058: throws WebServiceException {
059:
060: EndpointInterfaceDescription ed = operationDesc
061: .getEndpointInterfaceDescription();
062: EndpointDescription endpointDesc = ed.getEndpointDescription();
063: Protocol protocol = Protocol.getProtocolForBinding(endpointDesc
064: .getClientBindingID());
065:
066: // Note all exceptions are caught and rethrown with a WebServiceException
067: try {
068:
069: // Sample Document message
070: // ..
071: // <soapenv:body>
072: // <m:operation>
073: // <param>hello</param>
074: // </m:operation>
075: // </soapenv:body>
076: //
077: // Important points.
078: // 1) There is no operation element under the body.
079: // 2) The data blocks are located underneath the body.
080: // 3) The name of the data block (m:operation) is defined by the schema and match the name of the operation.
081: // This is called the wrapper element. The wrapper element has a corresponding JAXB element pojo.
082: // 4) The parameters (m:param) are child elements of the wrapper element.
083: // 5) NOTE: For doc/literal wrapped "minimal", the wrapper JAXB element pojo is missing.
084:
085: // Get the operation information
086: ParameterDescription[] pds = operationDesc
087: .getParameterDescriptions();
088: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
089: .getMarshalDesc(endpointDesc);
090: TreeSet<String> packages = marshalDesc.getPackages();
091:
092: // TODO This needs more work. We need to check inside holders of input params. We also
093: // may want to exclude header params from this check
094: //Validate input parameters for operation and make sure no input parameters are null.
095: //As per JAXWS Specification section 3.6.2.3 if a null value is passes as an argument
096: //to a method then an implementation MUST throw WebServiceException.
097: if (pds.length > 0) {
098: if (signatureArguments == null) {
099: throw ExceptionFactory
100: .makeWebServiceException(Messages
101: .getMessage(
102: "NullParamErr1",
103: "Input",
104: operationDesc
105: .getJavaMethodName(),
106: "doc/lit"));
107: }
108: if (signatureArguments != null) {
109: for (Object argument : signatureArguments) {
110: if (argument == null) {
111: throw ExceptionFactory
112: .makeWebServiceException(Messages
113: .getMessage(
114: "NullParamErr1",
115: "Input",
116: operationDesc
117: .getJavaMethodName(),
118: "doc/lit"));
119: }
120: }
121: }
122: }
123:
124: // Create the message
125: MessageFactory mf = (MessageFactory) FactoryRegistry
126: .getFactory(MessageFactory.class);
127: Message m = mf.create(protocol);
128:
129: // Indicate the style and wrapper element name. This triggers the message to
130: // put the data blocks underneath the wrapper element
131: m.setStyle(Style.DOCUMENT);
132: m.setIndirection(1);
133: m
134: .setOperationElement(getRequestWrapperQName(operationDesc));
135:
136: // The input object represent the signature arguments.
137: // Signature arguments are both holders and non-holders
138: // Convert the signature into a list of JAXB objects for marshalling
139: List<PDElement> pdeList = MethodMarshallerUtils
140: .getPDElements(marshalDesc, pds,
141: signatureArguments, true, // input
142: true, // doc/lit wrapped
143: true); // false
144:
145: // We want to use "by Java Type" marshalling for
146: // all objects
147: for (PDElement pde : pdeList) {
148: ParameterDescription pd = pde.getParam();
149: Class type = pd.getParameterActualType();
150: pde.setByJavaTypeClass(type);
151: }
152:
153: // Put values onto the message
154: MethodMarshallerUtils.toMessage(pdeList, m, packages);
155:
156: return m;
157: } catch (Exception e) {
158: throw ExceptionFactory.makeWebServiceException(e);
159: }
160: }
161:
162: public Object[] demarshalRequest(Message message,
163: OperationDescription operationDesc)
164: throws WebServiceException {
165:
166: EndpointInterfaceDescription ed = operationDesc
167: .getEndpointInterfaceDescription();
168: EndpointDescription endpointDesc = ed.getEndpointDescription();
169:
170: // Note all exceptions are caught and rethrown with a WebServiceException
171: try {
172: // Sample RPC message
173: // ..
174: // <soapenv:body>
175: // <m:op xmlns:m="urn://api">
176: // <param xsi:type="data:foo" >...</param>
177: // </m:op>
178: // </soapenv:body>
179: //
180: // Important points.
181: // 1) RPC has an operation element under the body. This is the name of the
182: // wsdl operation.
183: // 2) The data blocks are located underneath the operation element. (In doc/lit
184: // the data elements are underneath the body.
185: // 3) The name of the data blocks (param) are defined by the wsdl:part not the
186: // schema. Note that it is unqualified per WSI-BP
187: // 4) The type of the data block (data:foo) is defined by schema (thus there is
188: // JAXB type rendering.
189: // 5) We always send an xsi:type, but other vendor's may not.
190: // Get the operation information
191: ParameterDescription[] pds = operationDesc
192: .getParameterDescriptions();
193: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
194: .getMarshalDesc(endpointDesc);
195: TreeSet<String> packages = marshalDesc.getPackages();
196:
197: // Indicate that the style is Document, but the blocks are underneath
198: // the wrapper element
199: message.setStyle(Style.DOCUMENT);
200: message.setIndirection(1);
201:
202: // We want to use "by Java Type" unmarshalling for
203: // all objects
204: Class[] javaTypes = new Class[pds.length];
205: for (int i = 0; i < pds.length; i++) {
206: ParameterDescription pd = pds[i];
207: javaTypes[i] = pd.getParameterActualType();
208: }
209:
210: // Unmarshal the ParamValues from the Message
211: List<PDElement> pvList = MethodMarshallerUtils
212: .getPDElements(pds, message, packages, true, // input
213: false, javaTypes); // sigh...unmarshal by type because there is no wrapper
214:
215: // Build the signature arguments
216: Object[] sigArguments = MethodMarshallerUtils
217: .createRequestSignatureArgs(pds, pvList);
218:
219: // TODO This needs more work. We need to check inside holders of input params. We also
220: // may want to exclude header params from this check
221: //Validate input parameters for operation and make sure no input parameters are null.
222: //As per JAXWS Specification section 3.6.2.3 if a null value is passes as an argument
223: //to a method then an implementation MUST throw WebServiceException.
224: if (sigArguments != null) {
225: for (Object argument : sigArguments) {
226: if (argument == null) {
227: throw ExceptionFactory
228: .makeWebServiceException(Messages
229: .getMessage(
230: "NullParamErr1",
231: "Input",
232: operationDesc
233: .getJavaMethodName(),
234: "rpc/lit"));
235:
236: }
237: }
238: }
239: return sigArguments;
240: } catch (Exception e) {
241: throw ExceptionFactory.makeWebServiceException(e);
242: }
243: }
244:
245: public Message marshalResponse(Object returnObject,
246: Object[] signatureArgs, OperationDescription operationDesc,
247: Protocol protocol) throws WebServiceException {
248:
249: EndpointInterfaceDescription ed = operationDesc
250: .getEndpointInterfaceDescription();
251: EndpointDescription endpointDesc = ed.getEndpointDescription();
252: // We want to respond with the same protocol as the request,
253: // It the protocol is null, then use the Protocol defined by the binding
254: if (protocol == null) {
255: protocol = Protocol.getProtocolForBinding(endpointDesc
256: .getBindingType());
257: }
258:
259: // Note all exceptions are caught and rethrown with a WebServiceException
260: try {
261: // Sample RPC message
262: // ..
263: // <soapenv:body>
264: // <m:opResponse xmlns:m="urn://api">
265: // <param xsi:type="data:foo" >...</param>
266: // </m:op>
267: // </soapenv:body>
268: //
269: // Important points.
270: // 1) RPC has an operation element under the body. This is the name of the
271: // wsdl operation.
272: // 2) The data blocks are located underneath the operation element. (In doc/lit
273: // the data elements are underneath the body.
274: // 3) The name of the data blocks (param) are defined by the wsdl:part not the
275: // schema. Note that it is unqualified.
276: // 4) The type of the data block (data:foo) is defined by schema (thus there is
277: // JAXB type rendering. Since we are using JAXB to marshal the data,
278: // we always generate an xsi:type attribute. This is an implemenation detail
279: // and is not defined by any spec.
280:
281: // Get the operation information
282: ParameterDescription[] pds = operationDesc
283: .getParameterDescriptions();
284: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
285: .getMarshalDesc(endpointDesc);
286: TreeSet<String> packages = marshalDesc.getPackages();
287:
288: // Create the message
289: MessageFactory mf = (MessageFactory) FactoryRegistry
290: .getFactory(MessageFactory.class);
291: Message m = mf.create(protocol);
292:
293: // Indicate the style and wrapper element name. This triggers the message to
294: // put the data blocks underneath the operation element
295: m.setStyle(Style.DOCUMENT);
296: m.setIndirection(1);
297: QName responseOp = getResponseWrapperQName(operationDesc);
298: m.setOperationElement(responseOp);
299:
300: // Put the return object onto the message
301: Class returnType = operationDesc.getResultActualType();
302: String returnNS = null;
303: String returnLocalPart = null;
304: if (operationDesc.isResultHeader()) {
305: returnNS = operationDesc.getResultTargetNamespace();
306: returnLocalPart = operationDesc.getResultName();
307: } else {
308: returnNS = operationDesc.getResultTargetNamespace();
309: returnLocalPart = operationDesc.getResultPartName();
310: }
311:
312: if (returnType != void.class) {
313:
314: // TODO should we allow null if the return is a header?
315: //Validate input parameters for operation and make sure no input parameters are null.
316: //As per JAXWS Specification section 3.6.2.3 if a null value is passes as an argument
317: //to a method then an implementation MUST throw WebServiceException.
318: if (returnObject == null) {
319: throw ExceptionFactory
320: .makeWebServiceException(Messages
321: .getMessage(
322: "NullParamErr1",
323: "Return",
324: operationDesc
325: .getJavaMethodName(),
326: "rpc/lit"));
327:
328: }
329: Element returnElement = null;
330: QName returnQName = new QName(returnNS, returnLocalPart);
331: if (marshalDesc.getAnnotationDesc(returnType)
332: .hasXmlRootElement()) {
333: returnElement = new Element(returnObject,
334: returnQName);
335: } else {
336: returnElement = new Element(returnObject,
337: returnQName, returnType);
338: }
339: MethodMarshallerUtils.toMessage(returnElement,
340: returnType, operationDesc.isListType(),
341: marshalDesc, m, returnType, // force marshal by type
342: operationDesc.isResultHeader());
343: }
344:
345: // Convert the holder objects into a list of JAXB objects for marshalling
346: List<PDElement> pdeList = MethodMarshallerUtils
347: .getPDElements(marshalDesc, pds, signatureArgs,
348: false, // output
349: true, // doc/lit wrapped
350: false); // not rpc
351:
352: // We want to use "by Java Type" marshalling for
353: // all objects
354: for (PDElement pde : pdeList) {
355: ParameterDescription pd = pde.getParam();
356: Class type = pd.getParameterActualType();
357: pde.setByJavaTypeClass(type);
358: }
359:
360: // TODO Should we check for null output body values? Should we check for null output header values ?
361: // Put values onto the message
362: MethodMarshallerUtils.toMessage(pdeList, m, packages);
363:
364: return m;
365: } catch (Exception e) {
366: throw ExceptionFactory.makeWebServiceException(e);
367: }
368: }
369:
370: public Object demarshalResponse(Message message,
371: Object[] signatureArgs, OperationDescription operationDesc)
372: throws WebServiceException {
373:
374: EndpointInterfaceDescription ed = operationDesc
375: .getEndpointInterfaceDescription();
376: EndpointDescription endpointDesc = ed.getEndpointDescription();
377:
378: // Note all exceptions are caught and rethrown with a WebServiceException
379: try {
380: // Sample RPC message
381: // ..
382: // <soapenv:body>
383: // <m:opResponse xmlns:m="urn://api">
384: // <param xsi:type="data:foo" >...</param>
385: // </m:op>
386: // </soapenv:body>
387: //
388: // Important points.
389: // 1) RPC has an operation element under the body. This is the name of the
390: // wsdl operation.
391: // 2) The data blocks are located underneath the operation element. (In doc/lit
392: // the data elements are underneath the body.
393: // 3) The name of the data blocks (param) are defined by the wsdl:part not the
394: // schema. Note that it is unqualified per WSI-BP
395: // 4) The type of the data block (data:foo) is defined by schema (thus there is
396: // JAXB type rendering.
397: // 5) We always send an xsi:type, but other vendor's may not.
398: // Get the operation information
399: ParameterDescription[] pds = operationDesc
400: .getParameterDescriptions();
401: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
402: .getMarshalDesc(endpointDesc);
403: TreeSet<String> packages = marshalDesc.getPackages();
404:
405: // Indicate that the style is Document.
406: message.setStyle(Style.DOCUMENT);
407: message.setIndirection(1);
408:
409: // Get the return value.
410: Class returnType = operationDesc.getResultActualType();
411: Object returnValue = null;
412: boolean hasReturnInBody = false;
413: if (returnType != void.class) {
414: // If the webresult is in the header, we need the name of the header so that we can find it.
415: Element returnElement = null;
416: if (operationDesc.isResultHeader()) {
417: returnElement = MethodMarshallerUtils
418: .getReturnElement(
419: packages,
420: message,
421: returnType,
422: operationDesc.isListType(),
423: true, // is a header
424: operationDesc
425: .getResultTargetNamespace(),
426: // header ns
427: operationDesc.getResultPartName(), // header local part
428: MethodMarshallerUtils
429: .numOutputBodyParams(pds) > 0);
430:
431: } else {
432: returnElement = MethodMarshallerUtils
433: .getReturnElement(
434: packages,
435: message,
436: returnType,
437: operationDesc.isListType(),
438: false,
439: null,
440: null,
441: MethodMarshallerUtils
442: .numOutputBodyParams(pds) > 0);
443: hasReturnInBody = true;
444:
445: }
446: returnValue = returnElement.getTypeValue();
447: // TODO should we allow null if the return is a header?
448: //Validate input parameters for operation and make sure no input parameters are null.
449: //As per JAXWS Specification section 3.6.2.3 if a null value is passes as an argument
450: //to a method then an implementation MUST throw WebServiceException.
451: if (returnValue == null) {
452: throw ExceptionFactory
453: .makeWebServiceException(Messages
454: .getMessage(
455: "NullParamErr1",
456: "Return",
457: operationDesc
458: .getJavaMethodName(),
459: "rpc/lit"));
460: }
461: }
462:
463: // We want to use "by Java Type" unmarshalling for
464: // all objects
465: Class[] javaTypes = new Class[pds.length];
466: for (int i = 0; i < pds.length; i++) {
467: ParameterDescription pd = pds[i];
468: Class type = pd.getParameterActualType();
469: javaTypes[i] = type;
470: }
471:
472: // Unmarshall the ParamValues from the Message
473: List<PDElement> pvList = MethodMarshallerUtils
474: .getPDElements(pds, message, packages, false, // output
475: hasReturnInBody, javaTypes); // unmarshal by type
476:
477: // TODO Should we check for null output body values? Should we check for null output header values ?
478:
479: // Populate the response Holders
480: MethodMarshallerUtils.updateResponseSignatureArgs(pds,
481: pvList, signatureArgs);
482:
483: return returnValue;
484: } catch (Exception e) {
485: throw ExceptionFactory.makeWebServiceException(e);
486: }
487: }
488:
489: public Message marshalFaultResponse(Throwable throwable,
490: OperationDescription operationDesc, Protocol protocol)
491: throws WebServiceException {
492:
493: EndpointInterfaceDescription ed = operationDesc
494: .getEndpointInterfaceDescription();
495: EndpointDescription endpointDesc = ed.getEndpointDescription();
496: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
497: .getMarshalDesc(endpointDesc);
498: TreeSet<String> packages = marshalDesc.getPackages();
499:
500: // We want to respond with the same protocol as the request,
501: // It the protocol is null, then use the Protocol defined by the binding
502: if (protocol == null) {
503: protocol = Protocol.getProtocolForBinding(endpointDesc
504: .getBindingType());
505: }
506:
507: // Note all exceptions are caught and rethrown with a WebServiceException
508: try {
509: // Create the message
510: MessageFactory mf = (MessageFactory) FactoryRegistry
511: .getFactory(MessageFactory.class);
512: Message m = mf.create(protocol);
513:
514: // Put the fault onto the message
515: MethodMarshallerUtils.marshalFaultResponse(throwable,
516: marshalDesc, operationDesc, m);
517: return m;
518: } catch (Exception e) {
519: throw ExceptionFactory.makeWebServiceException(e);
520: }
521: }
522:
523: public Throwable demarshalFaultResponse(Message message,
524: OperationDescription operationDesc)
525: throws WebServiceException {
526:
527: EndpointInterfaceDescription ed = operationDesc
528: .getEndpointInterfaceDescription();
529: EndpointDescription endpointDesc = ed.getEndpointDescription();
530: MarshalServiceRuntimeDescription marshalDesc = MethodMarshallerUtils
531: .getMarshalDesc(endpointDesc);
532:
533: // Note all exceptions are caught and rethrown with a WebServiceException
534: try {
535: Throwable t = MethodMarshallerUtils.demarshalFaultResponse(
536: operationDesc, marshalDesc, message);
537: return t;
538: } catch (Exception e) {
539: throw ExceptionFactory.makeWebServiceException(e);
540: }
541: }
542:
543: /**
544: * @param opDesc
545: * @return request wrapper qname
546: */
547: private static QName getRequestWrapperQName(
548: OperationDescription opDesc) {
549:
550: QName qName = opDesc.getName();
551:
552: String localPart = opDesc.getRequestWrapperLocalName();
553: String uri = opDesc.getRequestWrapperTargetNamespace();
554: String prefix = "dlwmin"; // Prefer using an actual prefix
555:
556: qName = new QName(uri, localPart, prefix);
557: return qName;
558: }
559:
560: /**
561: * @param opDesc
562: * @return request wrapper qname
563: */
564: private static QName getResponseWrapperQName(
565: OperationDescription opDesc) {
566:
567: QName qName = opDesc.getName();
568:
569: String localPart = opDesc.getResponseWrapperLocalName();
570: String uri = opDesc.getResponseWrapperTargetNamespace();
571: String prefix = "dlwmin"; // Prefer using an actual prefix
572:
573: qName = new QName(uri, localPart, prefix);
574: return qName;
575: }
576:
577: }
|