001: package org.objectweb.celtix.bus.bindings.xml;
002:
003: import java.io.*;
004: import java.util.*;
005: import java.util.logging.Level;
006: import java.util.logging.Logger;
007:
008: import javax.jws.WebParam;
009: import javax.jws.soap.SOAPBinding.ParameterStyle;
010: import javax.jws.soap.SOAPBinding.Style;
011: import javax.wsdl.BindingInput;
012: import javax.wsdl.BindingOperation;
013: import javax.wsdl.BindingOutput;
014: import javax.wsdl.Port;
015: import javax.wsdl.WSDLException;
016: import javax.xml.namespace.QName;
017: import javax.xml.ws.Holder;
018: import javax.xml.ws.WebFault;
019: import javax.xml.ws.WebServiceException;
020: import javax.xml.ws.handler.MessageContext;
021:
022: import org.w3c.dom.*;
023:
024: import org.objectweb.celtix.Bus;
025: import org.objectweb.celtix.bindings.AbstractBindingImpl;
026: import org.objectweb.celtix.bindings.DataBindingCallback;
027: import org.objectweb.celtix.bindings.DataReader;
028: import org.objectweb.celtix.bindings.DataWriter;
029: import org.objectweb.celtix.bindings.xmlformat.TBody;
030: import org.objectweb.celtix.bus.handlers.HandlerChainInvoker;
031: import org.objectweb.celtix.common.logging.LogUtils;
032: import org.objectweb.celtix.context.InputStreamMessageContext;
033: import org.objectweb.celtix.context.ObjectMessageContext;
034: import org.objectweb.celtix.context.OutputStreamMessageContext;
035: import org.objectweb.celtix.handlers.HandlerInvoker;
036: import org.objectweb.celtix.helpers.NodeUtils;
037: import org.objectweb.celtix.helpers.WSDLHelper;
038: import org.objectweb.celtix.helpers.XMLUtils;
039: import org.objectweb.celtix.ws.addressing.EndpointReferenceType;
040: import org.objectweb.celtix.wsdl.EndpointReferenceUtils;
041:
042: public class XMLBindingImpl extends AbstractBindingImpl {
043: private static final Logger LOG = LogUtils
044: .getL7dLogger(XMLBindingImpl.class);
045: protected final XMLMessageFactory msgFactory;
046: protected final boolean isServer;
047: private final XMLUtils xmlUtils = new XMLUtils();
048:
049: private Bus bus;
050: private EndpointReferenceType endpointRef;
051:
052: public XMLBindingImpl(boolean server) {
053: isServer = server;
054: msgFactory = XMLMessageFactory.newInstance();
055: }
056:
057: public XMLBindingImpl(Bus b, EndpointReferenceType ert,
058: boolean server) {
059: this (server);
060: this .bus = b;
061: this .endpointRef = ert;
062: }
063:
064: public Bus getBus() {
065: return this .bus;
066: }
067:
068: public EndpointReferenceType getEndpointReference() {
069: return this .endpointRef;
070: }
071:
072: // --- AbstractBindingImpl interface ---
073:
074: public MessageContext createBindingMessageContext(
075: MessageContext srcCtx) {
076: return new XMLMessageContextImpl(srcCtx);
077: }
078:
079: public HandlerInvoker createHandlerInvoker() {
080: return new HandlerChainInvoker(getHandlerChain(true));
081: }
082:
083: public XMLMessageFactory getMessageFactory() {
084: return this .msgFactory;
085: }
086:
087: private XMLMessage initXMLMessage() {
088: return msgFactory.createMessage();
089: }
090:
091: public void marshal(ObjectMessageContext objContext,
092: MessageContext mc, DataBindingCallback callback) {
093: try {
094: LOG.entering(getClass().getName(), "marshal");
095: boolean isInputMsg = (Boolean) mc
096: .get(ObjectMessageContext.MESSAGE_INPUT);
097: XMLMessage msg = initXMLMessage();
098: LOG.log(Level.INFO, "XML_MARSHALLING_START", xmlUtils
099: .toString(msg.getRoot()));
100: if (callback.getMode() == DataBindingCallback.Mode.PARTS) {
101: if (callback.getSOAPStyle() == Style.DOCUMENT
102: && callback.getSOAPParameterStyle() == ParameterStyle.BARE) {
103: if (isInputMsg) {
104: addReturnWrapperRoot(msg, callback);
105: LOG.log(Level.INFO, "XML_MARSHALLING_BARE_OUT",
106: xmlUtils.toString(msg.getRoot()));
107: } else {
108: addWrapperRoot(msg, callback);
109: LOG.log(Level.INFO, "XML_MARSHALLING_BARE_IN",
110: xmlUtils.toString(msg.getRoot()));
111:
112: }
113: }
114: addParts(msg.getRoot(), objContext, isInputMsg,
115: callback);
116: } else if (callback.getMode() == DataBindingCallback.Mode.MESSAGE) {
117: throw new XMLBindingException(
118: "Could not figure out how to marshal data");
119: } else if (callback.getMode() == DataBindingCallback.Mode.PAYLOAD) {
120: throw new XMLBindingException(
121: "Could not figure out how to marshal data");
122: }
123: LOG.log(Level.INFO, "XML_MARSHALLING_END", xmlUtils
124: .toString(msg.getRoot()));
125: ((XMLMessageContext) mc).setMessage(msg);
126: LOG.exiting(getClass().getName(), "marshal",
127: "XML binding Mashal OK");
128: } catch (Exception e) {
129: LOG.log(Level.SEVERE, "XML_MARSHALLING_FAILURE_MSG", e);
130: throw new XMLBindingException(
131: "XML binding marshal exception ", e);
132: }
133: }
134:
135: public void marshalFault(ObjectMessageContext objContext,
136: MessageContext mc, DataBindingCallback callback) {
137: XMLMessage msg = null;
138:
139: try {
140: msg = XMLMessageContext.class.isInstance(mc)
141: && ((XMLMessageContext) mc).getMessage() != null ? ((XMLMessageContext) mc)
142: .getMessage()
143: : initXMLMessage();
144: if (msg.hasChildNodes()) {
145: msg.removeContents();
146: }
147:
148: Throwable t = objContext.getException();
149:
150: XMLFault fault = msg.addFault();
151: // REVIST FaultCode to handle other codes.
152: StringBuffer str = new StringBuffer(t.toString());
153: if (!t.getClass().isAnnotationPresent(WebFault.class)) {
154: str.append("\n");
155: for (StackTraceElement s : t.getStackTrace()) {
156: str.append(s.toString());
157: str.append("\n");
158: }
159: }
160: fault.addFaultString(str.toString());
161:
162: DataWriter<XMLFault> writer = callback
163: .createWriter(XMLFault.class);
164: if (writer != null) {
165: writer.write(t, fault);
166: if (fault.getFaultDetail() != null
167: && !fault.getFaultDetail().hasChildNodes()) {
168: fault.removeChild(fault.getFaultDetail());
169: }
170: }
171: } catch (XMLBindingException se) {
172: LOG.log(Level.SEVERE, "FAULT_MARSHALLING_FAILURE_MSG", se);
173: // Handle UnChecked Exception, Runtime Exception.
174: }
175: ((XMLMessageContext) mc).setMessage(msg);
176: }
177:
178: public void unmarshal(MessageContext mc,
179: ObjectMessageContext objContext,
180: DataBindingCallback callback) {
181: try {
182: LOG.entering(getClass().getName(), "unmarshal");
183:
184: boolean isOutputMsg = (Boolean) mc
185: .get(ObjectMessageContext.MESSAGE_INPUT);
186: if (!XMLMessageContext.class.isInstance(mc)) {
187: throw new XMLBindingException(
188: "XMLMessageContext not available");
189: }
190:
191: XMLMessageContext xmlContext = XMLMessageContext.class
192: .cast(mc);
193: XMLMessage xmlMessage = xmlContext.getMessage();
194:
195: if (callback.getMode() == DataBindingCallback.Mode.PARTS) {
196: Node root = xmlMessage.getRoot();
197: LOG.log(Level.INFO, "XML_UNMARSHALLING_START", xmlUtils
198: .toString(root));
199: getParts(root, callback, objContext, isOutputMsg);
200: LOG.log(Level.INFO, "XML_UNMARSHALLING_END", xmlUtils
201: .toString(root));
202: } else if (callback.getMode() == DataBindingCallback.Mode.MESSAGE) {
203: throw new XMLBindingException(
204: "Could not figure out how to marshal data");
205: } else if (callback.getMode() == DataBindingCallback.Mode.PAYLOAD) {
206: throw new XMLBindingException(
207: "Could not figure out how to marshal data");
208: }
209: LOG.exiting(getClass().getName(), "unmarshal",
210: "XML binding Unmashal OK");
211: } catch (Exception e) {
212: LOG.log(Level.SEVERE, "XML_UNMARSHALLING_FAILURE_MSG", e);
213: throw new XMLBindingException(
214: "XML binding unmarshal exception", e);
215: }
216: }
217:
218: public void unmarshalFault(MessageContext context,
219: ObjectMessageContext objContext,
220: DataBindingCallback callback) {
221: try {
222: if (!XMLMessageContext.class.isInstance(context)) {
223: throw new XMLBindingException(
224: "XMLMessageContext not available");
225: }
226:
227: XMLMessageContext xmlContext = XMLMessageContext.class
228: .cast(context);
229: XMLMessage xmlMessage = xmlContext.getMessage();
230:
231: XMLFault fault = xmlMessage.getFault();
232: if (fault == null) {
233: fault = xmlMessage.addFault();
234: fault
235: .addFaultString("Unknow fault raised, the fault is null");
236: }
237: DataReader<XMLFault> reader = callback
238: .createReader(XMLFault.class);
239:
240: if (reader == null) {
241: throw new WebServiceException(
242: "Could not unmarshal fault");
243: }
244: Object faultObj = reader.read(null, 0, fault);
245:
246: objContext.setException((Throwable) faultObj);
247: } catch (Exception se) {
248: LOG.log(Level.SEVERE, "XML_UNMARSHALLING_FAILURE_MSG", se);
249: throw new XMLBindingException(
250: "XML binding unmarshal fault exception", se);
251: }
252: }
253:
254: public void write(MessageContext msgContext,
255: OutputStreamMessageContext outContext) throws IOException {
256: XMLMessageContext xmlContext = (XMLMessageContext) msgContext;
257: try {
258: xmlContext.getMessage().writeTo(
259: outContext.getOutputStream());
260:
261: if (LOG.isLoggable(Level.FINE)) {
262: ByteArrayOutputStream baos = new ByteArrayOutputStream();
263: xmlContext.getMessage().writeTo(baos);
264: LOG.log(Level.FINE, baos.toString());
265: }
266: } catch (Exception e) {
267: LOG.log(Level.SEVERE, "XML_WRITE_FAILURE_MSG", e);
268: throw new XMLBindingException(
269: "XML binding write exception ", e);
270: }
271: }
272:
273: public void read(InputStreamMessageContext inContext,
274: MessageContext context) throws IOException {
275: if (!XMLMessageContext.class.isInstance(context)) {
276: throw new XMLBindingException(
277: "XMLMessageContext not available");
278: }
279: try {
280: XMLMessageContext xmlContext = XMLMessageContext.class
281: .cast(context);
282: xmlContext.setMessage(msgFactory.createMessage(inContext
283: .getInputStream()));
284: } catch (Exception e) {
285: LOG.log(Level.SEVERE, "XML_READ_FAILURE_MSG", e);
286: throw new XMLBindingException(
287: "XML binding read exception ", e);
288: }
289: }
290:
291: public boolean hasFault(MessageContext msgContext) {
292: XMLMessage msg = ((XMLMessageContext) msgContext).getMessage();
293: assert msg != null;
294: return msg.hasFault();
295: }
296:
297: public void updateMessageContext(MessageContext msgContext) {
298: // TODO
299: }
300:
301: private void getParts(Node xmlNode, DataBindingCallback callback,
302: ObjectMessageContext objCtx, boolean isOutBound)
303: throws XMLBindingException {
304: DataReader<Node> reader = null;
305: for (Class<?> cls : callback.getSupportedFormats()) {
306: if (cls == Node.class) {
307: reader = callback.createReader(Node.class);
308: break;
309: }
310: }
311:
312: if (reader == null) {
313: throw new XMLBindingException(
314: "Could not figure out how to marshal data");
315: }
316: if (callback.getSOAPStyle() == Style.DOCUMENT
317: && callback.getSOAPParameterStyle() == ParameterStyle.WRAPPED) {
318: reader.readWrapper(objCtx, isOutBound, xmlNode);
319: return;
320: }
321:
322: Node childNode = NodeUtils.getChildElementNode(xmlNode);
323:
324: if (isOutBound && callback.getWebResult() != null) {
325: Object retVal = reader.read(callback.getWebResultQName(),
326: -1, childNode);
327: objCtx.setReturn(retVal);
328: childNode = childNode.getNextSibling();
329: }
330:
331: WebParam.Mode ignoreParamMode = isOutBound ? WebParam.Mode.IN
332: : WebParam.Mode.OUT;
333: int noArgs = callback.getParamsLength();
334: Object[] methodArgs = objCtx.getMessageObjects();
335:
336: for (int idx = 0; idx < noArgs; idx++) {
337: WebParam param = callback.getWebParam(idx);
338: if (param.mode() != ignoreParamMode) {
339: QName elName = (callback.getSOAPStyle() == Style.DOCUMENT) ? new QName(
340: param.targetNamespace(), param.name())
341: : new QName("", param.partName());
342:
343: Object obj = reader.read(elName, idx, childNode);
344: if (param.mode() != WebParam.Mode.IN) {
345: try {
346: // TO avoid type safety warning the Holder
347: // needs tobe set as below.
348: methodArgs[idx].getClass().getField("value")
349: .set(methodArgs[idx], obj);
350: } catch (Exception ex) {
351: throw new XMLBindingException(
352: "Can not set the part value into the Holder field.",
353: ex);
354: }
355: } else {
356: methodArgs[idx] = obj;
357: }
358: childNode = childNode.getNextSibling();
359: }
360: }
361: }
362:
363: private void addWrapperRoot(XMLMessage xmlMessage,
364: DataBindingCallback callback) throws WSDLException {
365: BindingOperation operation = getBindingOperation(callback
366: .getOperationName());
367:
368: BindingInput input = operation.getBindingInput();
369:
370: TBody xmlBinding = null;
371: Iterator ite = input.getExtensibilityElements().iterator();
372: while (ite.hasNext()) {
373: Object obj = ite.next();
374: if (obj instanceof TBody) {
375: xmlBinding = (TBody) obj;
376: }
377: }
378:
379: if (needRootNode(operation, false)) {
380: if (xmlBinding == null || xmlBinding.getRootNode() == null) {
381: throw new XMLBindingException(
382: "Bare style must define the rootNode in this case!");
383: }
384: QName rootNode = xmlBinding.getRootNode();
385: Document doc = xmlMessage.getRoot();
386: String targetNamespace = rootNode.getNamespaceURI() == null ? callback
387: .getTargetNamespace()
388: : rootNode.getNamespaceURI();
389: Element operationNode = doc.createElementNS(
390: targetNamespace, rootNode.getLocalPart());
391: xmlMessage.appendChild(operationNode);
392: }
393: }
394:
395: private void addReturnWrapperRoot(XMLMessage xmlMessage,
396: DataBindingCallback callback) throws WSDLException {
397: BindingOperation operation = getBindingOperation(callback
398: .getOperationName());
399:
400: BindingOutput output = operation.getBindingOutput();
401: TBody xmlBinding = null;
402: Iterator ite = output.getExtensibilityElements().iterator();
403: while (ite.hasNext()) {
404: Object obj = ite.next();
405: if (obj instanceof TBody) {
406: xmlBinding = (TBody) obj;
407: }
408: }
409: if (needRootNode(operation, true)) {
410: if (xmlBinding == null || xmlBinding.getRootNode() == null) {
411: throw new XMLBindingException(
412: "Bare style must define the rootNode in this case!");
413: }
414: QName rootNode = xmlBinding.getRootNode();
415: Document doc = xmlMessage.getRoot();
416: String targetNamespace = rootNode.getNamespaceURI() == null ? callback
417: .getTargetNamespace()
418: : rootNode.getNamespaceURI();
419: Element operationNode = doc.createElementNS(
420: targetNamespace, rootNode.getLocalPart());
421: xmlMessage.appendChild(operationNode);
422: }
423: }
424:
425: private BindingOperation getBindingOperation(String operationName)
426: throws WSDLException {
427: WSDLHelper helper = new WSDLHelper();
428: Port port = EndpointReferenceUtils.getPort(this .bus
429: .getWSDLManager(), this .endpointRef);
430: return helper.getBindingOperation(port.getBinding(),
431: operationName);
432: }
433:
434: private boolean needRootNode(BindingOperation operation, boolean out) {
435: WSDLHelper helper = new WSDLHelper();
436: Map parts = helper.getParts(operation.getOperation(), out);
437: return parts.size() != 1;
438: }
439:
440: private void addParts(Node xmlNode, ObjectMessageContext objCtx,
441: boolean isOutBound, DataBindingCallback callback) {
442: DataWriter<Node> writer = callback.createWriter(Node.class);
443: if (writer == null) {
444: throw new XMLBindingException(
445: "Could not figure out how to marshal data");
446: }
447:
448: if (callback.getSOAPStyle() == Style.DOCUMENT
449: && callback.getSOAPParameterStyle() == ParameterStyle.WRAPPED) {
450: writer.writeWrapper(objCtx, isOutBound, xmlNode);
451: return;
452: }
453:
454: // Add the Return Type
455: if (isOutBound && callback.getWebResult() != null) {
456: writer.write(objCtx.getReturn(), callback
457: .getWebResultQName(), xmlNode);
458: }
459: // Add the in,inout,out args depend on the inputMode
460: WebParam.Mode ignoreParamMode = isOutBound ? WebParam.Mode.IN
461: : WebParam.Mode.OUT;
462: int noArgs = callback.getParamsLength();
463: Object[] args = objCtx.getMessageObjects();
464: for (int idx = 0; idx < noArgs; idx++) {
465: WebParam param = callback.getWebParam(idx);
466: if (param.mode() != ignoreParamMode) {
467: Object partValue = args[idx];
468: if (param.mode() != WebParam.Mode.IN) {
469: partValue = ((Holder) args[idx]).value;
470: }
471:
472: QName elName = (callback.getSOAPStyle() == Style.DOCUMENT) ? new QName(
473: param.targetNamespace(), param.name())
474: : new QName("", param.partName());
475: writer.write(partValue, elName, xmlNode);
476: }
477: }
478: }
479: }
|