| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.ode.jbi.msgmap; |
| |
| import java.util.Collection; |
| import java.util.Set; |
| |
| import javax.jbi.messaging.MessagingException; |
| import javax.jbi.messaging.NormalizedMessage; |
| import javax.wsdl.Fault; |
| import javax.wsdl.Operation; |
| import javax.wsdl.Part; |
| import javax.xml.namespace.QName; |
| import javax.xml.transform.dom.DOMSource; |
| |
| import org.apache.ode.bpel.iapi.Message; |
| import org.apache.ode.utils.DOMUtils; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| |
| /** |
| * Message mapper for dealing with the degenerate messages that servicemix components such as servicemix-http provide. These |
| * messages are not normalized and hence do not conform to the JBI specification. They are in fact whatever the SOAP body element |
| * happens to be. This mapper will make a reasonable attempt to handle these messages, which means don't count on it working. |
| * |
| */ |
| public class ServiceMixMapper extends BaseXmlMapper implements Mapper { |
| |
| @SuppressWarnings("unchecked") |
| public Recognized isRecognized(NormalizedMessage nmsMsg, Operation op) { |
| // First of all, if we are not in ServiceMix, we exclude this |
| // as a possibility. |
| if (nmsMsg.getClass().getName().indexOf("servicemix") == -1) { |
| __log.debug("Unrecognized message class: " + nmsMsg.getClass()); |
| return Recognized.FALSE; |
| } |
| |
| Element msg; |
| try { |
| msg = parse(nmsMsg.getContent()); |
| if (__log.isDebugEnabled()) { |
| __log.debug("isRecognized() message: " + prettyPrint(msg)); |
| } |
| } catch (MessageTranslationException e) { |
| __log.warn("Unable to parse message: ", e); |
| return Recognized.FALSE; |
| } |
| |
| if (op.getInput() == null) { |
| __log.debug("no input def - unrecognized"); |
| return Recognized.FALSE; |
| } |
| |
| if (op.getInput().getMessage() == null) { |
| __log.debug("no message def - unrecognized"); |
| return Recognized.FALSE; |
| } |
| |
| if (op.getInput().getMessage().getParts().size() == 0) { |
| __log.debug("no message parts def - unsure"); |
| return Recognized.UNSURE; |
| } |
| |
| for (String pname : ((Set<String>) op.getInput().getMessage().getParts().keySet())) { |
| Part part = op.getInput().getMessage().getPart(pname); |
| Element pdata = null; |
| // servicemix-http has a (bad) habit of placing the SOAP body content directly in the normalized message |
| QName elementName = part.getElementName(); |
| if (elementName != null && elementName.getLocalPart().equals(msg.getLocalName()) |
| && elementName.getNamespaceURI().equals(msg.getNamespaceURI())) { |
| pdata = msg; |
| } |
| if (pdata == null) { |
| // with RPC semantic the body is wrapped by a partName which is same as bodyElementName |
| pdata = DOMUtils.findChildByName(msg, new QName(null, part.getName())); |
| } |
| if (pdata == null) { |
| __log.debug("no part data for " + part.getName() + " -- unrecognized."); |
| return Recognized.FALSE; |
| } |
| if (part.getElementName() != null) { |
| Element child = DOMUtils.getFirstChildElement(pdata); |
| if (child == null) { |
| __log.debug("element part " + part.getName() + " does not contain element " + part.getElementName() |
| + " -- unrecognized"); |
| return Recognized.FALSE; |
| } |
| |
| } |
| } |
| |
| return Recognized.TRUE; |
| |
| } |
| |
| public void toNMS(NormalizedMessage nmsMsg, Message odeMsg, javax.wsdl.Message msgdef, QName fault) throws MessagingException, |
| MessageTranslationException { |
| if (msgdef == null) |
| throw new NullPointerException("msdef must not be null."); |
| Element ode = odeMsg == null ? null : odeMsg.getMessage(); |
| Element part = ode == null ? null : DOMUtils.getFirstChildElement(ode); |
| Element firstPartEl = part == null ? null : DOMUtils.getFirstChildElement(part); |
| |
| if (fault != null) { |
| // We treat faults seperately as there are some assumption we can make, mainly that there is |
| // a single part and it is an element part. |
| |
| if (msgdef.getParts().size() != 1) |
| throw new MessageTranslationException("Message for fault \"" + fault + "\" does not contain exactly one part! Cannot map!"); |
| |
| Part partDef = (Part) msgdef.getParts().values().iterator().next(); |
| if (partDef.getElementName() == null) |
| throw new MessageTranslationException("Message for fault \"" + fault + "\" does not contain an element part."); |
| |
| if (firstPartEl == null) { |
| // Oooops, our assumption did not pan out; we'll do our best i.e. create empty content. |
| __log.warn("Proceessing fault \"" + fault + "\" with empty content (check your BPEL)."); |
| |
| Document doc = newDocument(); |
| Element content = doc.createElementNS(partDef.getElementName().getNamespaceURI(), partDef.getElementName().getLocalPart()); |
| doc.appendChild(content); |
| if (__log.isDebugEnabled()) |
| __log.debug("toNMS() ode message (fault, BS): " + prettyPrint(content)); |
| nmsMsg.setContent(new DOMSource(doc)); |
| } else { |
| if (__log.isDebugEnabled()) |
| __log.debug("toNMS() ode message (fault): " + prettyPrint(firstPartEl)); |
| nmsMsg.setContent(new DOMSource(firstPartEl)); |
| } |
| return; |
| } |
| |
| if (msgdef.getParts().size() > 1 || ((Part) msgdef.getParts().values().iterator().next()).getElementName() == null) { |
| // If we have more than one part, or a single non-element part, then we can't use the standard |
| // NMS doc-lit like convention. Instead we place the entire message on the bus and hope for the |
| // best. |
| if (__log.isDebugEnabled()) |
| __log.debug("toNMS() ode message (rpc-like): " + prettyPrint(ode)); |
| nmsMsg.setContent(new DOMSource(ode)); |
| return; |
| } |
| |
| if (__log.isDebugEnabled()) |
| __log.debug("toNMS() normalized message (doc-like):" + prettyPrint(firstPartEl)); |
| nmsMsg.setContent(new DOMSource(firstPartEl)); |
| } |
| |
| public void toODE(Message odeMsg, NormalizedMessage nmsMsg, javax.wsdl.Message msgdef) throws MessageTranslationException { |
| Element nms = parse(nmsMsg.getContent()); |
| boolean docLit = false; |
| |
| if (__log.isDebugEnabled()) { |
| __log.debug("toODE() normalized message:\n" + prettyPrint(nms)); |
| } |
| |
| for (String pname : ((Set<String>) msgdef.getParts().keySet())) { |
| Part part = msgdef.getPart(pname); |
| // servicemix-http has a (bad) habit of placing the SOAP body content directly in the normalized message |
| QName elementName = part.getElementName(); |
| if (elementName != null && elementName.getLocalPart().equals(nms.getLocalName()) |
| && elementName.getNamespaceURI().equals(nms.getNamespaceURI())) { |
| docLit = true; |
| break; |
| } |
| } |
| if (docLit) { |
| __log.debug("toODE() doc-like message "); |
| |
| Document doc = newDocument(); |
| Element message = doc.createElement("message"); |
| doc.appendChild(message); |
| |
| Part firstPart = (Part) msgdef.getOrderedParts(null).get(0); |
| Element p = doc.createElement(firstPart.getName()); |
| message.appendChild(p); |
| p.appendChild(doc.importNode(nms, true)); |
| odeMsg.setMessage(message); |
| } else { |
| __log.debug("toODE() rpc-like message "); |
| // Simple, just pass along the message |
| if (__log.isDebugEnabled()) { |
| __log.debug("toODE() ode message:\n" + prettyPrint(nms)); |
| } |
| odeMsg.setMessage(nms); |
| } |
| } |
| |
| public Fault toFaultType(javax.jbi.messaging.Fault jbiFlt, Collection<Fault> faults) throws MessageTranslationException { |
| if (faults.isEmpty()) |
| return null; |
| |
| // anynone's guess really |
| return faults.iterator().next(); |
| } |
| |
| private String prettyPrint(Element el) { |
| try { |
| return DOMUtils.prettyPrint(el); |
| } catch (java.io.IOException ioe) { |
| return ioe.getMessage(); |
| } |
| } |
| |
| } |