package org.marketcetera.client.jms;
import java.io.StringWriter;
import java.io.StringReader;
import javax.jms.*;
import javax.xml.bind.*;
import org.marketcetera.client.brokers.BrokerStatus;
import org.marketcetera.trade.FIXResponseImpl;
import org.marketcetera.trade.ReportBaseImpl;
import org.marketcetera.util.log.I18NBoundMessage1P;
import org.marketcetera.util.log.SLF4JLoggerProxy;
import org.marketcetera.util.misc.ClassVersion;
import org.springframework.jms.support.converter.MessageConversionException;
import org.springframework.jms.support.converter.MessageConverter;
import org.apache.commons.lang.ObjectUtils;
/* $License$ */
/**
* Converts messaging objects to an XML representation that can be
* sent over JMS. This class is not meant to be used by clients of
* this package.
*
* @author anshul@marketcetera.com
* @version $Id: JMSXMLMessageConverter.java 16841 2014-02-20 19:59:04Z colin $
* @since 1.5.0
*/
@ClassVersion("$Id: JMSXMLMessageConverter.java 16841 2014-02-20 19:59:04Z colin $")
public class JMSXMLMessageConverter implements MessageConverter {
/**
* Creates an instance.
*
* @throws JAXBException if there were errors initializing the
* XML marshalling / unmarshalling system.
*/
public JMSXMLMessageConverter() throws JAXBException {
mContext = JAXBContext.newInstance
(OrderEnvelope.class,
ReportBaseImpl.class,
FIXResponseImpl.class,
BrokerStatus.class);
}
/**
* Converts a JMS Message to a messaging object.
*
* @param message the received JMS message. It should be of type
* {@link javax.jms.ObjectMessage}.
*
* @return the messaging object converted from the supplied JMS message.
*
* @throws javax.jms.JMSException if there were errors extracting the contents
* of the JMS message.
* @throws org.springframework.jms.support.converter.MessageConversionException if there were errors converting
* the contents of the JMS message to a messaging object.
*/
@Override
public Object fromMessage(Message message)
throws JMSException, MessageConversionException {
SLF4JLoggerProxy.debug(this, "Converting from JMS {}", message); //$NON-NLS-1$
if(message instanceof TextMessage) {
Object object = null;
try {
object = fromXML(((TextMessage) message).getText());
} catch (JAXBException e) {
throw new MessageConversionException(new I18NBoundMessage1P(
Messages.ERROR_CONVERTING_MESSAGE_TO_OBJECT,
ObjectUtils.toString(object)).getText(), e);
}
if((object instanceof ReportBaseImpl) ||
(object instanceof FIXResponseImpl) ||
(object instanceof OrderEnvelope) ||
(object instanceof BrokerStatus)) {
return object;
} else {
throw new MessageConversionException(new I18NBoundMessage1P(
Messages.UNEXPECTED_MESSAGE_RECEIVED,
ObjectUtils.toString(object)).getText());
}
} else {
throw new MessageConversionException(new I18NBoundMessage1P(
Messages.UNEXPECTED_MESSAGE_RECEIVED,
ObjectUtils.toString(message)).getText());
}
}
/**
* Converts a messaging object to a JMS Message.
*
* @param inObject the message to be converted. It should either be
* an order or a report.
* @param session the JMS Session instance.
*
* @return the JMS message.
*
* @throws javax.jms.JMSException if there were errors serializing the
* messaging object.
* @throws org.springframework.jms.support.converter.MessageConversionException if the supplied object was not
* an acceptable messaging object.
*/
@Override
public Message toMessage(Object inObject, Session session)
throws JMSException, MessageConversionException {
SLF4JLoggerProxy.debug(this, "Converting to JMS {}", inObject); //$NON-NLS-1$
if ((inObject instanceof ReportBaseImpl) ||
(inObject instanceof FIXResponseImpl) ||
(inObject instanceof OrderEnvelope) ||
(inObject instanceof BrokerStatus)) {
try {
TextMessage message = session.createTextMessage(toXML(inObject));
//Set the type property for interoperability with .NET client.
message.setStringProperty(JMS_TYPE_PROPERTY,
inObject.getClass().getSimpleName());
return message;
} catch (JAXBException e) {
throw new MessageConversionException(new I18NBoundMessage1P(
Messages.ERROR_CONVERTING_OBJECT_TO_MESSAGE,
ObjectUtils.toString(inObject)).getText(), e);
}
} else {
throw new MessageConversionException(new I18NBoundMessage1P(
Messages.UNEXPECTED_MESSAGE_TO_SEND,
ObjectUtils.toString(inObject)).getText());
}
}
/**
* Marshall the supplied object to XML.
*
* @param inObject the object that needs to be marshalled.
*
* @return the XML representation.
*
* @throws JAXBException if there were was an error marshalling the object
* to XML.
*/
String toXML(Object inObject) throws JAXBException {
Marshaller marshaller = getMarshaller();
StringWriter writer = new StringWriter();
marshaller.marshal(inObject, writer);
//no need to close or flush the writer as they do nothing.
return writer.toString();
}
/**
* Unmarshall the supplied object from XML to an instance.
*
* @param inXML the object in XML.
*
* @return the unmarshalled object instance.
*
* @throws JAXBException if there were was an error unmarshalling the
* object from XML.
*/
Object fromXML(String inXML) throws JAXBException {
Unmarshaller unMarshaller = getUnMarshaller();
StringReader reader = new StringReader(inXML);
return unMarshaller.unmarshal(reader);
}
/**
* Returns the underlying JAXB context for testing.
*
* @return the underlying JAXB context.
*/
JAXBContext getContext() {
return mContext;
}
/**
* Gets cached copy of the marshaller to use for marshalling objects to XML.
*
* @return the marshaller to use for marshalling objects to XML.
*
* @throws JAXBException if there were errors getting the marshaller.
*/
private Marshaller getMarshaller() throws JAXBException {
Marshaller m = mMarshallers.get();
if(m == null) {
m = mContext.createMarshaller();
mMarshallers.set(m);
}
return m;
}
/**
* Gets the cached copy of the unmarshaller to use for unmarshalling objects
* from XML.
*
* @return the unmarshaller to use for unmarshalling objects from XML.
*
* @throws JAXBException if there were errors getting the unmarshaller.
*/
private Unmarshaller getUnMarshaller() throws JAXBException {
Unmarshaller u = mUnmarshallers.get();
if(u == null) {
u = mContext.createUnmarshaller();
mUnmarshallers.set(u);
}
return u;
}
private final ThreadLocal<Marshaller> mMarshallers =
new ThreadLocal<Marshaller>();
private final ThreadLocal<Unmarshaller> mUnmarshallers =
new ThreadLocal<Unmarshaller>();
private final JAXBContext mContext;
private static final String JMS_TYPE_PROPERTY = "metc_type"; //$NON-NLS-1$
}