/**
*
* Copyright 2005 LogicBlaze, Inc. http://www.logicblaze.com
*
* Licensed 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.servicemix.components.xfire;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.Iterator;
import javax.jbi.messaging.ExchangeStatus;
import javax.jbi.messaging.InOptionalOut;
import javax.jbi.messaging.InOut;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.messaging.MessagingException;
import javax.jbi.messaging.NormalizedMessage;
import javax.jbi.servicedesc.ServiceEndpoint;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.xfire.MessageContext;
import org.codehaus.xfire.XFire;
import org.codehaus.xfire.XFireException;
import org.codehaus.xfire.XFireFactory;
import org.codehaus.xfire.aegis.AegisBindingProvider;
import org.codehaus.xfire.annotations.AnnotationServiceFactory;
import org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations;
import org.codehaus.xfire.exchange.InMessage;
import org.codehaus.xfire.exchange.OutMessage;
import org.codehaus.xfire.handler.AbstractHandler;
import org.codehaus.xfire.handler.Phase;
import org.codehaus.xfire.jaxb2.JaxbTypeRegistry;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.ServiceFactory;
import org.codehaus.xfire.transport.AbstractChannel;
import org.codehaus.xfire.transport.AbstractWSDLTransport;
import org.codehaus.xfire.transport.Channel;
import org.codehaus.xfire.transport.DefaultEndpoint;
import org.codehaus.xfire.transport.Transport;
import org.codehaus.xfire.util.STAXUtils;
import org.servicemix.components.AbstractDeployableComponent;
import org.servicemix.components.ServiceUnit;
import org.servicemix.jbi.NoInMessageAvailableException;
import org.servicemix.jbi.jaxp.BytesSource;
public class XFireComponent extends AbstractDeployableComponent {
protected XFire xfire;
protected ServiceFactory factory;
protected ServiceUnit doDeploy(String serviceUnitName, String serviceUnitRootPath) throws Exception {
return new XFireServiceUnit(this, serviceUnitName, serviceUnitRootPath);
}
protected void process(MessageExchange me) throws Exception {
if (me.getStatus() == ExchangeStatus.DONE) {
return;
}
if (me.getStatus() == ExchangeStatus.ERROR) {
me.setStatus(ExchangeStatus.DONE);
getContext().getDeliveryChannel().send(me);
}
try {
ServiceEndpoint se = me.getEndpoint();
Service service = null;
for (Iterator it = serviceUnits.values().iterator(); it.hasNext();) {
XFireServiceUnit su = (XFireServiceUnit) it.next();
Service s = su.getService(se.getServiceName(), se.getEndpointName());
if (s != null) {
service = s;
break;
}
}
if (service == null) {
throw new MessagingException("Could not find endpoint for " + se);
}
NormalizedMessage in = me.getMessage("in");
if (in == null) {
throw new NoInMessageAvailableException(me);
}
Transport t = xfire.getTransportManager().getTransport(JbiTransport.JBI_BINDING);
ByteArrayOutputStream out = new ByteArrayOutputStream();
Channel c = t.createChannel();
MessageContext ctx = new MessageContext();
ctx.setXFire(xfire);
ctx.setService(service);
ctx.setProperty(Channel.BACKCHANNEL_URI, out);
InMessage msg = new InMessage();
XMLStreamReader xmlStreamReader = null;
try {
xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(in.getContent());
} catch (Exception e) {
// ignore, as this method is not mandatory in stax
}
if (xmlStreamReader == null) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
TransformerFactory.newInstance().newTransformer().transform(in.getContent(), new StreamResult(buffer));
xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(new ByteArrayInputStream(buffer.toByteArray()));
}
msg.setXMLStreamReader(xmlStreamReader);
c.receive(ctx, msg);
// Set response or DONE status
if (isInAndOut(me)) {
NormalizedMessage outMsg = me.createMessage();
outMsg.setContent(new BytesSource(out.toByteArray()));
me.setMessage(outMsg, "out");
} else {
me.setStatus(ExchangeStatus.DONE);
}
} catch (Exception e) {
me.setStatus(ExchangeStatus.ERROR);
me.setError(e);
logger.debug("Exception catch", e);
} catch (Throwable t) {
me.setStatus(ExchangeStatus.ERROR);
me.setError(new Exception(t));
logger.info("Throwable catch", t);
} finally {
getContext().getDeliveryChannel().send(me);
}
}
protected void doInit() throws Exception {
super.doInit();
if (xfire == null) {
xfire = createXFire();
}
if (factory == null) {
factory = createFactory();
}
}
protected boolean isInAndOut(MessageExchange exchange) {
return exchange instanceof InOut || exchange instanceof InOptionalOut;
}
protected XFire createXFire() {
XFire xfire = XFireFactory.newInstance().getXFire();
xfire.getTransportManager().register(new JbiTransport());
return xfire;
}
public XFire getXFire() {
return xfire;
}
public void setXFire(XFire xfire) {
this.xfire = xfire;
}
protected ServiceFactory createFactory() {
AnnotationServiceFactory factory = new AnnotationServiceFactory(
new Jsr181WebAnnotations(),
xfire.getTransportManager(),
new AegisBindingProvider(new JaxbTypeRegistry()));
return factory;
}
public ServiceFactory getFactory() {
return factory;
}
public void setFactory(ServiceFactory factory) {
this.factory = factory;
}
/**
* Simple jbi transport, similar to local transport,
* but without soap encoding.
*
*/
public static class JbiTransport extends AbstractWSDLTransport {
private static final Log log = LogFactory.getLog(JbiTransport.class);
public final static String JBI_TRANSPORT_NS = "http://java.sun.com/xml/ns/jbi/binding/service+engine";
public final static String JBI_BINDING = "http://java.sun.com/xml/ns/jbi/binding/service+engine";
private final static String URI_PREFIX = "urn:xfire:transport:jbi:";
public JbiTransport() {
addInHandler(new PrepareHandler());
}
protected String getName()
{
return "JBI";
}
public String getServiceURL(Service service) {
return "jbi://" + service.getName();
}
public String getTransportURI(Service service) {
return JBI_TRANSPORT_NS;
}
protected Channel createNewChannel(String uri) {
log.debug("Creating new channel for uri: " + uri);
JbiChannel c = new JbiChannel(uri, this);
c.setEndpoint(new DefaultEndpoint());
return c;
}
protected String getUriPrefix() {
return URI_PREFIX;
}
public String[] getSupportedBindings()
{
return new String[] { JBI_BINDING };
}
public String[] getKnownUriSchemes() {
return new String[] { "jbi://" };
}
/**
* Jbi channel, only support local invocations.
*/
public static class JbiChannel extends AbstractChannel {
public JbiChannel(String uri, JbiTransport transport) {
setTransport(transport);
setUri(uri);
}
public void open() throws Exception {
}
public void send(MessageContext context, OutMessage message) throws XFireException {
if (message.getUri().equals(Channel.BACKCHANNEL_URI)) {
final OutputStream out = (OutputStream) context.getProperty(Channel.BACKCHANNEL_URI);
if (out != null) {
final XMLStreamWriter writer = STAXUtils.createXMLStreamWriter(out, message.getEncoding());
message.getSerializer().writeMessage(message, writer, context);
try {
writer.close();
} catch (XMLStreamException e) {
throw new XFireException("Error closing output stream", e);
}
return;
}
}
throw new UnsupportedOperationException();
}
public void close() {
}
}
/**
* Handler to stat document parsing.
*/
public static class PrepareHandler extends AbstractHandler {
public String getPhase() {
return Phase.PARSE;
}
public void invoke(MessageContext context) throws Exception {
InMessage message = context.getInMessage();
XMLStreamReader reader = message.getXMLStreamReader();
while (reader.hasNext()) {
int event = reader.next();
switch (event)
{
case XMLStreamReader.START_DOCUMENT:
String encoding = reader.getCharacterEncodingScheme();
message.setEncoding(encoding);
break;
case XMLStreamReader.END_DOCUMENT:
return;
case XMLStreamReader.START_ELEMENT:
return;
default:
break;
}
}
}
}
}
}