I could be wrong but I think when camel-cxf PAYLOAD mode was developed,
the CXF Dispatch/Provider interface support wasn't quite ready (or we
haven't done enough due diligence). I agreed with you the benefit. We
could rewriting it using the Dispatch/Provider APIs. However, I
seriously doubt that we could integrate with CXF without directly
invoking the non-APIs classes. I mean that would be nice. There is a
soap component in camel-cxf which is pretty much not being used and that
makes it look more complex then it really is. A good chunk of the
"complexity" are doing with header filtering, converting/binding Camel
to CXF message, standard Camel Producer/Consumer/Endpoint/Spring which
you need either way. The CXF interceptor stuff which I agree we should
avoid actually only accounts for small portion of the code (10 classes
in org.apache.camel.component.cxf.intercepters and 2 of the 10 XML* are
not used and two of them are Abstract classes).
Daniel Kulp wrote:
Quite honestly, I'm not sure why the CXF stuff in Camel has to be so
complex. To me, it should be based more on the technology in CXF that
supports the JAX-WS Dispatch/Provider stuff (or implemented via the JAX-WS
Dispatch/Provider stuff). In this case, if it was a "PAYLOAD" mode
Provider, it ends up as essentially the same thing. You get the payload as
a "Source" (in some cases, a StaxSource so streaming can be maintained) and
all the "soap" stuff is not there. If camel needs the whole message, the
Provider is put in MESSAGE mode.
The benefit of the Provider/Dispatch stuff is that you DO get all the
complext WS-* processing and things like schema validation and other
important things that CXF provides, but you don't have to do all the code
generation and things like that.
Dan
Christian Schneider wrote:
Hi all,
I am thinking about how to make one way services easier. Currently I
generate code for the service using cxf codegen and use the camel-cxf
module to create a client or endpoint that can be routed over jms using
the camel-jms component. Using CXF for this task is a little overkill as
very few features of CXF are used and quite a lot of configuration has
to be done. I wonder if this can be done easier.
I have experimented with a possible solution for the server part. It
looks like this:
from("jms:myqueue").process(new
SoapProcessor("com.example.customerservice")).to("bean:serviceHandler");
The idea is that a soap message for the service comes in over jms. The
soap processor parses the soap xml, strips the Envelope and Body and
unmarshals the content using JAXB. The processor needs the package name
of the generated stub code for the service. The advantage over using
camel-cxf is that there is much less configuration and you do not need
cxf at runtime (which means much less jars). Additionally the
serviceHandler bean only needs to have a method with the expected classs
type as input parameter it does not need to implement a service
interface. I have added the code of SoapProcessor to the mail as it is
quite small.
So what do you think? Does it make sense to have such small scale SOAP
functionality in camel?
I am thinking about turning my Processor into a DataFormat and provide
marshalling and unmarshalling. Does this make sense or is a processor
better?
Greetings
Christian
--
Christian Schneider
---
http://www.liquid-reality.de
----
import java.io.InputStream;
import java.util.Iterator;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
public class SoapProcessor implements Processor {
private XPathExpression xpathExpression;
private Unmarshaller unmarshaller;
public SoapProcessor(String jaxbPackage) {
super();
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new SoapNameSpaceContext());
try {
xpathExpression =
xpath.compile("/soap:Envelope/soap:Body/*");
JAXBContext jContext =
JAXBContext.newInstance(jaxbPackage);
unmarshaller = jContext.createUnmarshaller();
} catch (XPathExpressionException e) {
throw new RuntimeException(e.getMessage(), e);
} catch (JAXBException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
private final class SoapNameSpaceContext implements NamespaceContext {
private static final String SOAP_NAMESPACE =
"http://schemas.xmlsoap.org/soap/envelope/";
public Iterator<?> getPrefixes(String namespaceURI) {
return null;
}
public String getPrefix(String namespaceURI) {
return null;
}
public String getNamespaceURI(String prefix) {
return SOAP_NAMESPACE;
}
}
public void process(Exchange exchange) throws Exception {
InputStream request =
exchange.getIn().getBody(InputStream.class);
InputSource is = new InputSource(request);
Element payload = (Element) xpathExpression.evaluate(is,
XPathConstants.NODE);
JAXBElement<?> el = (JAXBElement<?>)
unmarshaller.unmarshal(payload);
Object o = el.getValue();
exchange.getIn().setBody(o);
}
}