001: package org.objectweb.celtix.bus.bindings.soap;
002:
003: import java.io.ByteArrayOutputStream;
004: import java.io.IOException;
005: import java.util.ArrayList;
006: import java.util.HashMap;
007: import java.util.Iterator;
008: import java.util.List;
009: import java.util.Map;
010: import java.util.Set;
011: import java.util.logging.Level;
012: import java.util.logging.Logger;
013:
014: import javax.jws.WebParam;
015: import javax.jws.soap.SOAPBinding.ParameterStyle;
016: import javax.jws.soap.SOAPBinding.Style;
017: import javax.xml.namespace.QName;
018: import javax.xml.soap.Detail;
019: import javax.xml.soap.MessageFactory;
020: import javax.xml.soap.MimeHeader;
021: import javax.xml.soap.MimeHeaders;
022: import javax.xml.soap.SOAPBody;
023: import javax.xml.soap.SOAPConstants;
024: import javax.xml.soap.SOAPElement;
025: import javax.xml.soap.SOAPEnvelope;
026: import javax.xml.soap.SOAPException;
027: import javax.xml.soap.SOAPFactory;
028: import javax.xml.soap.SOAPFault;
029: import javax.xml.soap.SOAPHeader;
030: import javax.xml.soap.SOAPMessage;
031: import javax.xml.transform.dom.DOMSource;
032: import javax.xml.transform.sax.SAXSource;
033: import javax.xml.transform.stream.StreamSource;
034: import javax.xml.ws.Holder;
035: import javax.xml.ws.ProtocolException;
036: import javax.xml.ws.WebFault;
037: import javax.xml.ws.WebServiceException;
038: import javax.xml.ws.handler.MessageContext;
039: import javax.xml.ws.handler.soap.SOAPMessageContext;
040: import javax.xml.ws.soap.SOAPBinding;
041: import javax.xml.ws.soap.SOAPFaultException;
042:
043: import org.w3c.dom.Element;
044: import org.w3c.dom.Node;
045: import org.w3c.dom.NodeList;
046:
047: import org.objectweb.celtix.bindings.AbstractBindingImpl;
048: import org.objectweb.celtix.bindings.DataBindingCallback;
049: import org.objectweb.celtix.bindings.DataReader;
050: import org.objectweb.celtix.bindings.DataWriter;
051: import org.objectweb.celtix.bus.handlers.HandlerChainInvoker;
052: import org.objectweb.celtix.common.logging.LogUtils;
053: import org.objectweb.celtix.context.InputStreamMessageContext;
054: import org.objectweb.celtix.context.ObjectMessageContext;
055: import org.objectweb.celtix.context.OutputStreamMessageContext;
056: import org.objectweb.celtix.handlers.HandlerInvoker;
057: import org.objectweb.celtix.helpers.NSStack;
058: import org.objectweb.celtix.helpers.NodeUtils;
059:
060: import static org.objectweb.celtix.bus.bindings.soap.SOAPConstants.FAULTCODE_CLIENT;
061: import static org.objectweb.celtix.bus.bindings.soap.SOAPConstants.FAULTCODE_SERVER;
062: import static org.objectweb.celtix.bus.bindings.soap.SOAPConstants.FAULTCODE_VERSIONMISMATCH;
063: import static org.objectweb.celtix.bus.bindings.soap.SOAPConstants.HEADER_MUSTUNDERSTAND;
064:
065: public class SOAPBindingImpl extends AbstractBindingImpl implements
066: SOAPBinding {
067: private static final Logger LOG = LogUtils
068: .getL7dLogger(SOAPBindingImpl.class);
069: protected final MessageFactory msgFactory;
070: protected final SOAPFactory soapFactory;
071: protected final boolean isServer;
072: private NSStack nsStack;
073: private QName faultCode;
074:
075: public SOAPBindingImpl(boolean server) {
076: try {
077: isServer = server;
078: msgFactory = MessageFactory
079: .newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
080: soapFactory = SOAPFactory
081: .newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
082: faultCode = isServer ? FAULTCODE_SERVER : FAULTCODE_CLIENT;
083: } catch (SOAPException se) {
084: LOG.log(Level.SEVERE, "SAAJ_FACTORY_CREATION_FAILURE_MSG",
085: se);
086: throw new WebServiceException(se.getMessage());
087: }
088: }
089:
090: // --- AbstractBindingImpl interface ---
091:
092: public MessageContext createBindingMessageContext(
093: MessageContext srcCtx) {
094: return new SOAPMessageContextImpl(srcCtx);
095: }
096:
097: public HandlerInvoker createHandlerInvoker() {
098: return new HandlerChainInvoker(getHandlerChain(true));
099: }
100:
101: public void marshal(ObjectMessageContext objContext,
102: MessageContext mc, DataBindingCallback callback) {
103:
104: try {
105: boolean isInputMsg = (Boolean) mc
106: .get(ObjectMessageContext.MESSAGE_INPUT);
107: SOAPMessage msg = initSOAPMessage();
108:
109: if (null != callback) {
110:
111: if (!"".equals(callback.getSOAPAction())) {
112: msg.getMimeHeaders().setHeader("SOAPAction",
113: "\"" + callback.getSOAPAction() + "\"");
114: }
115:
116: if (callback.getMode() == DataBindingCallback.Mode.PARTS) {
117: if (callback.getSOAPStyle() == Style.RPC) {
118: nsStack = new NSStack();
119: nsStack.push();
120: }
121:
122: // add in, out and inout header params
123: addHeaderParts(msg.getSOAPPart().getEnvelope(),
124: objContext, isInputMsg, callback);
125:
126: SOAPElement soapElement = addOperationNode(msg
127: .getSOAPBody(), callback, isInputMsg);
128: // add in, out and inout non-header params
129: addParts(soapElement, objContext, isInputMsg,
130: callback);
131: } else if (callback.getMode() == DataBindingCallback.Mode.MESSAGE) {
132:
133: Object src = isInputMsg ? objContext.getReturn()
134: : objContext.getMessageObjects()[0];
135: // contains the entire SOAP message
136: boolean found = false;
137: for (Class<?> cls : callback.getSupportedFormats()) {
138: if (cls == SOAPMessage.class) {
139: msg = (SOAPMessage) src;
140: found = true;
141: break;
142: } else if (cls == DOMSource.class
143: || cls == SAXSource.class
144: || cls == StreamSource.class) {
145: DataWriter<SOAPMessage> writer = callback
146: .createWriter(SOAPMessage.class);
147: writer.write(src, msg);
148: found = true;
149: break;
150: }
151: }
152: if (!found) {
153: throw new SOAPException(
154: "Could not figure out how to marshal data");
155: }
156: } else if (callback.getMode() == DataBindingCallback.Mode.PAYLOAD) {
157: // contains the contents of the SOAP:Body
158: boolean found = false;
159: Object src = isInputMsg ? objContext.getReturn()
160: : objContext.getMessageObjects()[0];
161:
162: for (Class<?> cls : callback.getSupportedFormats()) {
163: if (cls == DOMSource.class
164: || cls == SAXSource.class
165: || cls == StreamSource.class
166: || cls == Object.class) {
167: DataWriter<SOAPBody> writer = callback
168: .createWriter(SOAPBody.class);
169: writer.write(src, msg.getSOAPBody());
170: found = true;
171: break;
172: }
173: }
174: if (!found) {
175: throw new SOAPException(
176: "Could not figure out how to marshal data");
177: }
178: }
179: } else {
180: LOG
181: .fine("Leaving soap message empty - no data binding callback");
182: }
183: ((SOAPMessageContext) mc).setMessage(msg);
184:
185: } catch (SOAPException se) {
186: LOG.log(Level.SEVERE, "SOAP_MARSHALLING_FAILURE_MSG", se);
187: throw SOAPFaultExHelper.createSOAPFaultEx(soapFactory,
188: faultCode, se);
189: }
190: }
191:
192: public void marshalFault(ObjectMessageContext objContext,
193: MessageContext mc, DataBindingCallback callback) {
194:
195: SOAPMessage msg = null;
196:
197: try {
198: msg = SOAPMessageContext.class.isInstance(mc)
199: && ((SOAPMessageContext) mc).getMessage() != null ? ((SOAPMessageContext) mc)
200: .getMessage()
201: : initSOAPMessage();
202:
203: if (msg.getSOAPBody().hasChildNodes()) {
204: msg.getSOAPBody().removeContents();
205: }
206:
207: Throwable t = objContext.getException();
208: if (t instanceof SOAPFaultException) {
209: msg.getSOAPBody().addChildElement(
210: ((SOAPFaultException) t).getFault());
211: } else {
212: StringBuffer str = new StringBuffer(t.toString());
213: if (!t.getClass().isAnnotationPresent(WebFault.class)) {
214: str.append("\n");
215: for (StackTraceElement s : t.getStackTrace()) {
216: str.append(s.toString());
217: str.append("\n");
218: }
219: }
220:
221: SOAPFault fault = msg.getSOAPBody().addFault(faultCode,
222: str.toString());
223:
224: DataWriter<Detail> writer = callback
225: .createWriter(Detail.class);
226: if (writer != null) {
227: writer.write(t, fault.addDetail());
228: if (!fault.getDetail().hasChildNodes()) {
229: fault.removeChild(fault.getDetail());
230: }
231: }
232: }
233: } catch (SOAPException se) {
234: LOG.log(Level.SEVERE, "FAULT_MARSHALLING_FAILURE_MSG", se);
235: // Handle UnChecked Exception, Runtime Exception.
236: }
237: ((SOAPMessageContext) mc).setMessage(msg);
238: }
239:
240: public void unmarshal(MessageContext mc,
241: ObjectMessageContext objContext,
242: DataBindingCallback callback) {
243: if (null == callback) {
244: LOG
245: .fine("Suppress unmarshalling - no data binding callback.");
246: return;
247: }
248: try {
249: boolean isOutputMsg = (Boolean) mc
250: .get(ObjectMessageContext.MESSAGE_INPUT);
251: if (!SOAPMessageContext.class.isInstance(mc)) {
252: throw new SOAPException(
253: "SOAPMessageContext not available");
254: }
255:
256: SOAPMessageContext soapContext = SOAPMessageContext.class
257: .cast(mc);
258: SOAPMessage soapMessage = soapContext.getMessage();
259:
260: if (callback.getMode() == DataBindingCallback.Mode.PARTS) {
261: // Assuming No Headers are inserted.
262: Node soapEl = soapMessage.getSOAPBody();
263:
264: if (callback.getSOAPStyle() == Style.RPC) {
265: soapEl = NodeUtils.getChildElementNode(soapEl);
266: }
267:
268: if (soapEl.hasChildNodes()) {
269: getParts(soapEl, callback, objContext, isOutputMsg);
270: } else {
271: LOG.fine("Body of SOAP message is empty.");
272: }
273:
274: getHeaderParts(soapMessage.getSOAPHeader(), callback,
275: objContext, isOutputMsg);
276: } else if (callback.getMode() == DataBindingCallback.Mode.MESSAGE) {
277: boolean found = false;
278: Object obj = null;
279: for (Class<?> cls : callback.getSupportedFormats()) {
280: if (cls == SOAPMessage.class) {
281: obj = soapMessage;
282: found = true;
283: break;
284: } else if (cls == DOMSource.class
285: || cls == SAXSource.class
286: || cls == StreamSource.class) {
287: DataReader<SOAPMessage> reader = callback
288: .createReader(SOAPMessage.class);
289: obj = reader.read(0, soapMessage);
290: found = true;
291: break;
292: }
293: }
294: if (!found) {
295: throw new SOAPException("Cannot unmarshal data");
296: }
297:
298: if (isOutputMsg) {
299: objContext.setReturn(obj);
300: } else {
301: objContext.setMessageObjects(obj);
302: }
303:
304: } else if (callback.getMode() == DataBindingCallback.Mode.PAYLOAD) {
305: boolean found = false;
306: Object obj = null;
307: for (Class<?> cls : callback.getSupportedFormats()) {
308: if (cls == DOMSource.class
309: || cls == SAXSource.class
310: || cls == StreamSource.class
311: || cls == Object.class) {
312: DataReader<SOAPBody> reader = callback
313: .createReader(SOAPBody.class);
314: obj = reader.read(0, soapMessage.getSOAPBody());
315: found = true;
316: break;
317: }
318: }
319:
320: if (!found) {
321: throw new SOAPException("Cannot unmarshal data");
322: }
323:
324: if (isOutputMsg) {
325: objContext.setReturn(obj);
326: } else {
327: objContext.setMessageObjects(obj);
328: }
329: }
330: } catch (SOAPException se) {
331: LOG.log(Level.SEVERE, "SOAP_UNMARSHALLING_FAILURE_MSG", se);
332: throw SOAPFaultExHelper.createSOAPFaultEx(soapFactory,
333: faultCode, se);
334: }
335: }
336:
337: public void unmarshalFault(MessageContext context,
338: ObjectMessageContext objContext,
339: DataBindingCallback callback) {
340: try {
341: if (!SOAPMessageContext.class.isInstance(context)) {
342: throw new SOAPException(
343: "SOAPMessageContext not available");
344: }
345:
346: SOAPMessageContext soapContext = SOAPMessageContext.class
347: .cast(context);
348: SOAPMessage soapMessage = soapContext.getMessage();
349:
350: SOAPFault fault = soapMessage.getSOAPBody().getFault();
351: DataReader<SOAPFault> reader = callback
352: .createReader(SOAPFault.class);
353:
354: Object faultObj = null;
355: if (null != reader) {
356: LOG.log(Level.INFO, "SOAP_FAULT_NO_READER");
357: faultObj = reader.read(null, 0, fault);
358: }
359: if (null == faultObj) {
360: LOG.log(Level.INFO, "SOAP_FAULT_UNMARSHALLING_MSG",
361: fault.getElementQName().toString());
362: faultObj = new SOAPFaultException(fault);
363: }
364:
365: objContext.setException((Throwable) faultObj);
366: } catch (SOAPException se) {
367: LOG.log(Level.SEVERE, "SOAP_UNMARSHALLING_FAILURE_MSG", se);
368: throw SOAPFaultExHelper.createSOAPFaultEx(soapFactory,
369: faultCode, se);
370: }
371: }
372:
373: public void write(MessageContext msgContext,
374: OutputStreamMessageContext outContext) throws IOException {
375: SOAPMessageContext soapCtx = (SOAPMessageContext) msgContext;
376: try {
377: soapCtx.getMessage().writeTo(outContext.getOutputStream());
378: if (LOG.isLoggable(Level.FINE)) {
379: ByteArrayOutputStream baos = new ByteArrayOutputStream();
380: soapCtx.getMessage().writeTo(baos);
381: LOG.log(Level.FINE, baos.toString());
382: }
383: } catch (SOAPException se) {
384: LOG.log(Level.SEVERE, "SOAP_WRITE_FAILURE_MSG", se);
385: throw SOAPFaultExHelper.createSOAPFaultEx(soapFactory,
386: faultCode, se);
387: }
388: }
389:
390: @SuppressWarnings("unchecked")
391: public void read(InputStreamMessageContext inCtx,
392: MessageContext context) throws IOException {
393:
394: if (!SOAPMessageContext.class.isInstance(context)) {
395: throw SOAPFaultExHelper.createSOAPFaultEx(soapFactory,
396: faultCode, "SOAPMessageContext not available");
397: }
398: SOAPMessageContext soapCtx = SOAPMessageContext.class
399: .cast(context);
400: SOAPMessage soapMessage;
401: QName code = faultCode;
402: try {
403: MimeHeaders headers = new MimeHeaders();
404: Map<String, List<String>> httpHeaders;
405:
406: if (isServer) {
407: httpHeaders = (Map<String, List<String>>) soapCtx
408: .get(MessageContext.HTTP_REQUEST_HEADERS);
409: } else {
410: httpHeaders = (Map<String, List<String>>) soapCtx
411: .get(MessageContext.HTTP_RESPONSE_HEADERS);
412: }
413: if (httpHeaders != null) {
414: for (String key : httpHeaders.keySet()) {
415: if (null != key) {
416: List<String> values = httpHeaders.get(key);
417: for (String value : values) {
418: headers.addHeader(key, value);
419: }
420: }
421: }
422: }
423:
424: soapMessage = msgFactory.createMessage(headers, inCtx
425: .getInputStream());
426: //Test if it is a valid SOAP 1.1 Message
427: code = FAULTCODE_VERSIONMISMATCH;
428: soapMessage.getSOAPPart().getEnvelope();
429: } catch (SOAPException se) {
430: LOG.log(Level.SEVERE, "SOAP_PARSING_FAILURE_MSG", se);
431: throw SOAPFaultExHelper.createSOAPFaultEx(soapFactory,
432: code, se);
433: }
434:
435: soapCtx.setMessage(soapMessage);
436: }
437:
438: public boolean hasFault(MessageContext msgContext) {
439: boolean hasFault = false;
440: SOAPMessage msg = ((SOAPMessageContext) msgContext)
441: .getMessage();
442: assert msg != null;
443: try {
444: hasFault = msg.getSOAPBody().hasFault();
445: } catch (SOAPException se) {
446: LOG.log(Level.SEVERE, "SOAP_UNMARSHALLING_FAILURE_MSG", se);
447: throw new ProtocolException(se);
448: }
449: return hasFault;
450: }
451:
452: public void updateMessageContext(MessageContext msgContext) {
453: if (msgContext instanceof SOAPMessageContext) {
454: SOAPMessage msg = ((SOAPMessageContext) msgContext)
455: .getMessage();
456: try {
457: updateHeaders(msgContext, msg);
458: } catch (SOAPException se) {
459: throw SOAPFaultExHelper.createSOAPFaultEx(soapFactory,
460: faultCode, se);
461: }
462: }
463: }
464:
465: // --- Abstr actBindingImpl interface ---
466:
467: public Set<String> getRoles() {
468: return null;
469: }
470:
471: public void setRoles(Set<String> set) {
472: // TODO
473: }
474:
475: public boolean isMTOMEnabled() {
476: return false;
477: }
478:
479: public void setMTOMEnabled(boolean flag) {
480: throw new WebServiceException("MTOM is not supported");
481: }
482:
483: public MessageFactory getMessageFactory() {
484: return msgFactory;
485: }
486:
487: @SuppressWarnings("unchecked")
488: public void updateHeaders(MessageContext ctx, SOAPMessage msg)
489: throws SOAPException {
490: if (msg.saveRequired()) {
491: msg.saveChanges();
492: }
493: MimeHeaders headers = msg.getMimeHeaders();
494: Map<String, List<String>> reqHead;
495: String inOutKey = MessageContext.HTTP_REQUEST_HEADERS;
496: if (isServer) {
497: inOutKey = MessageContext.HTTP_RESPONSE_HEADERS;
498: }
499: reqHead = (Map<String, List<String>>) ctx.get(inOutKey);
500: if (reqHead == null) {
501: reqHead = new HashMap<String, List<String>>();
502: ctx.put(inOutKey, reqHead);
503: }
504: Iterator it = headers.getAllHeaders();
505: while (it.hasNext()) {
506: MimeHeader header = (MimeHeader) it.next();
507: if (!"Content-Length".equals(header.getName())) {
508: List<String> vals = reqHead.get(header.getName());
509: if (null == vals) {
510: vals = new ArrayList<String>();
511: reqHead.put(header.getName(), vals);
512: }
513: vals.add(header.getValue());
514: }
515: }
516: }
517:
518: private SOAPElement addOperationNode(SOAPElement body,
519: DataBindingCallback callback, boolean isOutBound)
520: throws SOAPException {
521:
522: String responseSuffix = isOutBound ? "Response" : "";
523:
524: if (callback.getSOAPStyle() == Style.RPC) {
525: String namespaceURI = callback.getTargetNamespace();
526: nsStack.add(namespaceURI);
527: String prefix = nsStack.getPrefix(namespaceURI);
528: QName operationName = new QName(namespaceURI, callback
529: .getOperationName()
530: + responseSuffix, prefix);
531:
532: SOAPElement el = body.addChildElement(operationName);
533: if (el.lookupPrefix(namespaceURI) == null) {
534: el.addNamespaceDeclaration(prefix, namespaceURI);
535: }
536: return el;
537: }
538: return body;
539: }
540:
541: private void getParts(Node xmlNode, DataBindingCallback callback,
542: ObjectMessageContext objCtx, boolean isOutBound)
543: throws SOAPException {
544:
545: DataReader<Node> reader = null;
546: for (Class<?> cls : callback.getSupportedFormats()) {
547: if (cls == Node.class) {
548: reader = callback.createReader(Node.class);
549: break;
550: }
551: }
552:
553: if (reader == null) {
554: throw new SOAPException(
555: "Could not figure out how to unmarshal data");
556: }
557:
558: if (callback.getSOAPStyle() == Style.DOCUMENT
559: && callback.getSOAPParameterStyle() == ParameterStyle.WRAPPED) {
560: reader.readWrapper(objCtx, isOutBound, xmlNode);
561: return;
562: }
563:
564: Node childNode = NodeUtils.getChildElementNode(xmlNode);
565: if (isOutBound && callback.getWebResult() != null
566: && !callback.getWebResult().header()) {
567:
568: Object retVal = reader.read(callback.getWebResultQName(),
569: -1, childNode);
570: objCtx.setReturn(retVal);
571: childNode = childNode.getNextSibling();
572: }
573:
574: WebParam.Mode ignoreParamMode = isOutBound ? WebParam.Mode.IN
575: : WebParam.Mode.OUT;
576: int noArgs = callback.getParamsLength();
577:
578: // Unmarshal parts of mode that should notbe ignored and are not part of
579: // the SOAP Headers
580: Object[] methodArgs = objCtx.getMessageObjects();
581:
582: for (int idx = 0; idx < noArgs; idx++) {
583: WebParam param = callback.getWebParam(idx);
584: if ((param.mode() != ignoreParamMode) && !param.header()) {
585:
586: QName elName = (callback.getSOAPStyle() == Style.DOCUMENT) ? new QName(
587: param.targetNamespace(), param.name())
588: : new QName("", param.partName());
589:
590: Object obj = reader.read(elName, idx, childNode);
591: if (param.mode() != WebParam.Mode.IN) {
592: try {
593: // TO avoid type safety warning the Holder
594: // needs tobe set as below.
595: methodArgs[idx].getClass().getField("value")
596: .set(methodArgs[idx], obj);
597: } catch (Exception ex) {
598: throw new SOAPException(
599: "Can not set the part value into the Holder field.");
600: }
601: } else {
602: methodArgs[idx] = obj;
603: }
604: childNode = childNode.getNextSibling();
605: }
606: }
607: }
608:
609: private void addParts(Node xmlNode, ObjectMessageContext objCtx,
610: boolean isOutBound, DataBindingCallback callback)
611: throws SOAPException {
612:
613: DataWriter<Node> writer = null;
614: for (Class<?> cls : callback.getSupportedFormats()) {
615: if (cls == Node.class) {
616: writer = callback.createWriter(Node.class);
617: break;
618: } else {
619: // TODO - other formats to support?
620: // StreamSource/DOMSource/STaX/etc..
621: }
622: }
623: if (writer == null) {
624: throw new SOAPException(
625: "Could not figure out how to marshal data");
626: }
627:
628: if (callback.getSOAPStyle() == Style.DOCUMENT
629: && callback.getSOAPParameterStyle() == ParameterStyle.WRAPPED) {
630: writer.writeWrapper(objCtx, isOutBound, xmlNode);
631: return;
632: }
633:
634: // Add the Return Type
635: if (isOutBound && callback.getWebResult() != null
636: && !callback.getWebResult().header()) {
637: writer.write(objCtx.getReturn(), callback
638: .getWebResultQName(), xmlNode);
639: }
640:
641: // Add the in,inout,out args depend on the inputMode
642: WebParam.Mode ignoreParamMode = isOutBound ? WebParam.Mode.IN
643: : WebParam.Mode.OUT;
644: int noArgs = callback.getParamsLength();
645:
646: // Marshal parts of mode that should notbe ignored and are not part of
647: // the SOAP Headers
648: Object[] args = objCtx.getMessageObjects();
649: for (int idx = 0; idx < noArgs; idx++) {
650: WebParam param = callback.getWebParam(idx);
651: if ((param.mode() != ignoreParamMode) && !param.header()) {
652: Object partValue = args[idx];
653: if (param.mode() != WebParam.Mode.IN) {
654: partValue = ((Holder) args[idx]).value;
655: }
656:
657: QName elName = (callback.getSOAPStyle() == Style.DOCUMENT) ? new QName(
658: param.targetNamespace(), param.name())
659: : new QName("", param.partName());
660: writer.write(partValue, elName, xmlNode);
661: }
662: }
663: }
664:
665: private void getHeaderParts(Element header,
666: DataBindingCallback callback, ObjectMessageContext objCtx,
667: boolean isOutBound) throws SOAPException {
668:
669: if (header == null || !header.hasChildNodes()) {
670: return;
671: }
672:
673: DataReader<Node> reader = null;
674: for (Class<?> cls : callback.getSupportedFormats()) {
675: if (cls == Node.class) {
676: reader = callback.createReader(Node.class);
677: break;
678: } else {
679: // TODO - other formats to support?
680: // StreamSource/DOMSource/STaX/etc..
681: }
682: }
683:
684: if (reader == null) {
685: throw new SOAPException(
686: "Could not figure out how to marshal data");
687: }
688:
689: if (isOutBound && callback.getWebResult() != null
690: && callback.getWebResult().header()) {
691:
692: QName elName = callback.getWebResultQName();
693: NodeList headerElems = header.getElementsByTagNameNS(elName
694: .getNamespaceURI(), elName.getLocalPart());
695: assert headerElems.getLength() == 1;
696: Node childNode = headerElems.item(0);
697:
698: Object retVal = reader.read(elName, -1, childNode);
699: objCtx.setReturn(retVal);
700: }
701:
702: WebParam.Mode ignoreParamMode = isOutBound ? WebParam.Mode.IN
703: : WebParam.Mode.OUT;
704: int noArgs = callback.getParamsLength();
705:
706: // Unmarshal parts of mode that should notbe ignored and are not part of
707: // the SOAP Headers
708: Object[] methodArgs = (Object[]) objCtx.getMessageObjects();
709: for (int idx = 0; idx < noArgs; idx++) {
710: WebParam param = callback.getWebParam(idx);
711: if ((param.mode() != ignoreParamMode) && param.header()) {
712: QName elName = new QName(param.targetNamespace(), param
713: .name());
714: NodeList headerElems = header
715: .getElementsByTagNameNS(elName
716: .getNamespaceURI(), elName
717: .getLocalPart());
718: assert headerElems.getLength() == 1;
719: Node childNode = headerElems.item(0);
720:
721: Object obj = reader.read(elName, idx, childNode);
722: if (param.mode() != WebParam.Mode.IN) {
723: try {
724: // TO avoid type safety warning the Holder
725: // needs tobe set as below.
726: methodArgs[idx].getClass().getField("value")
727: .set(methodArgs[idx], obj);
728: } catch (Exception ex) {
729: throw new SOAPException(
730: "Can not set the part value into the Holder field.");
731: }
732: } else {
733: methodArgs[idx] = obj;
734: }
735: }
736: }
737: }
738:
739: private void addHeaderParts(SOAPEnvelope envelope,
740: ObjectMessageContext objCtx, boolean isOutBound,
741: DataBindingCallback callback) throws SOAPException {
742:
743: boolean wroteHeader = false;
744: DataWriter<Node> writer = null;
745: for (Class<?> cls : callback.getSupportedFormats()) {
746: if (cls == Node.class) {
747: writer = callback.createWriter(Node.class);
748: break;
749: } else {
750: // TODO - other formats to support?
751: // StreamSource/DOMSource/STaX/etc..
752: }
753: }
754: if (writer == null) {
755: throw new SOAPException(
756: "Could not figure out how to marshal data");
757: }
758:
759: if (isOutBound && callback.getWebResult() != null
760: && callback.getWebResult().header()) {
761: SOAPHeader header = envelope.getHeader();
762: wroteHeader = true;
763: writer.write(objCtx.getReturn(), callback
764: .getWebResultQName(), header);
765: addSOAPHeaderAttributes(header, callback
766: .getWebResultQName(), true);
767: }
768:
769: // Add the in,inout,out args depend on the inputMode
770: WebParam.Mode ignoreParamMode = isOutBound ? WebParam.Mode.IN
771: : WebParam.Mode.OUT;
772: int noArgs = callback.getParamsLength();
773:
774: // Marshal parts of mode that should notbe ignored and are not part of
775: // the SOAP Headers
776: Object[] args = (Object[]) objCtx.getMessageObjects();
777: for (int idx = 0; idx < noArgs; idx++) {
778: WebParam param = callback.getWebParam(idx);
779: if ((param.mode() != ignoreParamMode) && param.header()) {
780: SOAPHeader header = envelope.getHeader();
781: wroteHeader = true;
782: Object partValue = args[idx];
783: if (param.mode() != WebParam.Mode.IN) {
784: partValue = ((Holder) args[idx]).value;
785: }
786:
787: QName elName = new QName(param.targetNamespace(), param
788: .name());
789: writer.write(partValue, elName, header);
790:
791: addSOAPHeaderAttributes(header, elName, true);
792: }
793: }
794: if (!wroteHeader) {
795: envelope.removeChild(envelope.getHeader());
796: }
797: }
798:
799: private void addSOAPHeaderAttributes(SOAPHeader header,
800: QName elName, boolean mustUnderstand) {
801: // Set mustUnderstand Attribute on header parts.
802: NodeList children = header.getElementsByTagNameNS(elName
803: .getNamespaceURI(), elName.getLocalPart());
804: assert children.getLength() == 1;
805: // Set the mustUnderstand attribute
806: if (children.item(0) instanceof Element) {
807: Element child = (Element) (children.item(0));
808: String n = header.lookupPrefix(HEADER_MUSTUNDERSTAND
809: .getNamespaceURI());
810: n += ":" + HEADER_MUSTUNDERSTAND.getLocalPart();
811: child.setAttributeNS(HEADER_MUSTUNDERSTAND
812: .getNamespaceURI(), HEADER_MUSTUNDERSTAND
813: .getLocalPart(), mustUnderstand ? "true" : "false");
814: }
815:
816: // TODO Actor/Role Attribute.
817: }
818:
819: public SOAPFactory getSOAPFactory() {
820: return soapFactory;
821: }
822:
823: private SOAPMessage initSOAPMessage() throws SOAPException {
824:
825: SOAPMessage msg = msgFactory.createMessage();
826: msg.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
827: msg.getSOAPPart().getEnvelope().addNamespaceDeclaration(
828: W3CConstants.NP_SCHEMA_XSD, W3CConstants.NU_SCHEMA_XSD);
829: msg.getSOAPPart().getEnvelope().addNamespaceDeclaration(
830: W3CConstants.NP_SCHEMA_XSI, W3CConstants.NU_SCHEMA_XSI);
831:
832: return msg;
833: }
834: }
|