package org.marketcetera.client;
import org.marketcetera.client.jms.JmsManager;
import org.marketcetera.util.ws.stateless.ServiceInterface;
import org.marketcetera.util.ws.stateful.Server;
import org.marketcetera.util.ws.stateful.SessionManager;
import org.marketcetera.util.misc.ClassVersion;
import org.marketcetera.util.log.SLF4JLoggerProxy;
import org.marketcetera.core.LoggerConfiguration;
import org.marketcetera.core.FIXVersionTestSuite;
import org.marketcetera.quickfix.FIXFieldConverterNotAvailable;
import org.marketcetera.quickfix.FIXMessageUtil;
import org.marketcetera.trade.Factory;
import org.marketcetera.trade.BrokerID;
import org.marketcetera.trade.Originator;
import org.marketcetera.trade.MessageCreationException;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.listener.SimpleMessageListenerContainer;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import quickfix.Message;
import quickfix.FieldNotFound;
import quickfix.InvalidMessage;
import quickfix.field.*;
import javax.jms.ConnectionFactory;
import javax.xml.bind.JAXBException;
import java.util.*;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/* $License$ */
/**
* A mock server for testing the Client.
* The server can be connected to at the URL {@link #URL}.
* Any username / password can be used to connect to the server as long
* as the username and password are identical.
*
* @author anshul@marketcetera.com
* @version $Id: MockServer.java 16614 2013-07-03 22:35:32Z colin $
* @since 1.0.0
*/
@ClassVersion("$Id: MockServer.java 16614 2013-07-03 22:35:32Z colin $") //$NON-NLS-1$
public class MockServer {
public static void main(String[] args)
throws InterruptedException, FIXFieldConverterNotAvailable {
LoggerConfiguration.logSetup();
FIXVersionTestSuite.initializeFIXDataDictionaryManager(
FIXVersionTestSuite.ALL_FIX_VERSIONS);
MockServer ms = new MockServer();
if(args.length > 0) {
File msgFile = new File(args[0]);
if(msgFile.canRead()) {
SLF4JLoggerProxy.debug(MockServer.class,
"Reading messages from file {}",
msgFile.getAbsolutePath());
ms.readMessagesFromFile(msgFile);
}
}
synchronized(ms) {
ms.wait();
}
ms.close();
}
public MockServer()
{
mContext = new ClassPathXmlApplicationContext
("mock_server.xml"); //$NON-NLS-1$
mContext.registerShutdownHook();
mContext.start();
mHandler = new MockMessageHandler();
JmsManager jmsMgr=new JmsManager
((ConnectionFactory)mContext.getBean
("metc_connection_factory_in"),
(ConnectionFactory)mContext.getBean
("metc_connection_factory_out"));
try {
mOrderEnvelopeListener = jmsMgr.getIncomingJmsFactory().
registerHandlerOEX
(mHandler,Service.REQUEST_QUEUE,false);
mOrderEnvelopeListener.start();
} catch (JAXBException ex) {
throw new IllegalStateException
("Cannot initialize request queue listener",ex);
}
try {
mStatusSender = jmsMgr.getOutgoingJmsFactory().
createJmsTemplateX
(Service.BROKER_STATUS_TOPIC,true);
} catch (JAXBException ex) {
throw new IllegalStateException
("Cannot initialize broker status sender",ex);
}
// Use default Server host and port
SessionManager<Object> sessionManager=new SessionManager<Object>
(new MockSessionFactory(jmsMgr,mHandler));
mServer=new Server<Object>
(new MockAuthenticator(),sessionManager);
mServiceImpl = new MockServiceImpl(sessionManager);
mServiceInterface = mServer.publish(mServiceImpl,Service.class);
}
public void close() {
mOrderEnvelopeListener.shutdown();
mContext.close();
mServiceInterface.stop();
mServer.stop();
}
MockServiceImpl getServiceImpl()
{
return mServiceImpl;
}
public ClassPathXmlApplicationContext getContext() {
return mContext;
}
public MockMessageHandler getHandler() {
return mHandler;
}
public JmsTemplate getStatusSender() {
return mStatusSender;
}
private void readMessagesFromFile(File inFile) {
BufferedReader reader = null;
String line;
List<Message> messages = new LinkedList<Message>();
try {
reader = new BufferedReader(new FileReader(inFile));
int lineNumber = 1;
while((line = reader.readLine()) != null) {
try {
messages.add(new Message(line));
} catch (InvalidMessage e) {
SLF4JLoggerProxy.warn(this, e,
"Ignoring Error @ line {} from message {}",
lineNumber, line);
}
lineNumber++;
}
sortAndAddMessages(messages);
} catch (IOException e) {
SLF4JLoggerProxy.warn(this, "Ignoring Error", e);
} finally {
if(reader != null) {
try {
reader.close();
} catch (IOException e) {
SLF4JLoggerProxy.warn(this, "Ignoring Error", e);
}
}
}
}
private void sortAndAddMessages(List<Message> inMessages) {
//Sort messages.
Collections.sort(inMessages,new Comparator<Message>(){
public int compare(Message o1, Message o2) {
try {
if(o1.isSetField(ClOrdID.FIELD) && o2.isSetField(ClOrdID.FIELD)) {
String s1 = o1.getString(ClOrdID.FIELD);
String s2 = o2.getString(ClOrdID.FIELD);
if(s1.equals(s2)) {
//Compare exec type
if(o1.isSetField(OrdStatus.FIELD) && o2.isSetField(OrdStatus.FIELD)) {
char c1 = o1.getChar(OrdStatus.FIELD);
char c2 = o2.getChar(OrdStatus.FIELD);
if(c1 == c2) {
if(o1.getHeader().isSetField(MsgSeqNum.FIELD) && o2.getHeader().isSetField(MsgSeqNum.FIELD)) {
int i1 = o1.getHeader().getInt(MsgSeqNum.FIELD);
int i2 = o2.getHeader().getInt(MsgSeqNum.FIELD);
return i1 - i2;
}
} else {
if (c1 == OrdStatus.PENDING_NEW) c1 = OrdStatus.NEW - 1;
if (c2 == OrdStatus.PENDING_NEW) c2 = OrdStatus.NEW - 1;
return c1 - c2;
}
}
} else {
return s1.compareTo(s2);
}
}
if(o1.getHeader().isSetField(SendingTime.FIELD) && o2.getHeader().isSetField(SendingTime.FIELD)) {
Date d1 = o1.getHeader().getUtcTimeStamp(SendingTime.FIELD);
Date d2 = o2.getHeader().getUtcTimeStamp(SendingTime.FIELD);
return d1.compareTo(d2);
}
} catch (FieldNotFound ignore) {
}
SLF4JLoggerProxy.error(this, "Message comparison failure:{} AND {}", o1, o2);
return 0;
}
});
for(Message message: inMessages) {
try {
if (FIXMessageUtil.isExecutionReport(message)) {
getHandler().addToSend(Factory.getInstance().createExecutionReport(
message, new BrokerID("default"),
Originator.Server, null, null));
} else if(FIXMessageUtil.isCancelReject(message)) {
getHandler().addToSend(Factory.getInstance().createOrderCancelReject(
message, new BrokerID("default"), Originator.Server, null, null));
} else {
getHandler().addToSend(Factory.getInstance().createFIXResponse(
message, new BrokerID("default"), Originator.Server, null, null));
}
} catch (MessageCreationException e) {
SLF4JLoggerProxy.warn(this, "Ignoring Error", e);
}
}
}
/**
* The URL for the broker hosted by this server.
* Do note that this URL is changed, the mock_server.xml & broker.xml
* files need to be updated as well.
*/
public static final String URL = "tcp://localhost:61616";
private final ClassPathXmlApplicationContext mContext;
private Server<?> mServer;
private ServiceInterface mServiceInterface;
private MockServiceImpl mServiceImpl;
private MockMessageHandler mHandler;
private SimpleMessageListenerContainer mOrderEnvelopeListener;
private JmsTemplate mStatusSender;
}