package org.marketcetera.orderloader;
import java.util.concurrent.atomic.AtomicInteger;
import org.marketcetera.client.ClientInitException;
import org.marketcetera.client.ClientManager;
import org.marketcetera.client.ClientParameters;
import org.marketcetera.client.ConnectionException;
import org.marketcetera.client.ReportListener;
import org.marketcetera.trade.ExecutionReport;
import org.marketcetera.trade.FIXOrder;
import org.marketcetera.trade.Order;
import org.marketcetera.trade.OrderCancelReject;
import org.marketcetera.trade.OrderSingle;
import org.marketcetera.trade.Originator;
import org.marketcetera.util.log.I18NBoundMessage1P;
import org.marketcetera.util.misc.ClassVersion;
/* $License$ */
/**
* An order processor that sends orders to the server.
*
* @author anshul@marketcetera.com
* @version $Id: ServerOrderProcessor.java 16154 2012-07-14 16:34:05Z colin $
* @since 1.0.0
*/
@ClassVersion("$Id: ServerOrderProcessor.java 16154 2012-07-14 16:34:05Z colin $")
public class ServerOrderProcessor implements OrderProcessor {
/**
* The maximum time, in ms, to wait without receiving any
* acknowledgements from the ORS until delivery of all sent orders
* is acknowledged by the ORS.
*/
public static final long MAXIMUM_DELIVERY_WAIT=60000;
private AtomicInteger mOrdersOutstanding;
/**
* Counts ORS acknowledgements.
*/
private class CounterListener
implements ReportListener
{
@Override
public void receiveExecutionReport(ExecutionReport inReport)
{
if (inReport.getOriginator()==Originator.Server) {
mOrdersOutstanding.getAndDecrement();
}
}
@Override
public void receiveCancelReject(OrderCancelReject inReport)
{
if (inReport.getOriginator()==Originator.Server) {
mOrdersOutstanding.getAndDecrement();
}
}
}
/**
* Creates an instance.
*
* @param inParameter the parameters to connect to the server.
*
* @throws ClientInitException if there were unexpected issues initializing
* the client.
* @throws ConnectionException if there were network issues initializing
* the client.
*/
public ServerOrderProcessor(ClientParameters inParameter)
throws ClientInitException, ConnectionException {
mOrdersOutstanding=new AtomicInteger();
ClientManager.init(inParameter);
ClientManager.getInstance().addReportListener(new CounterListener());
}
@Override
public void processOrder(Order inOrder, int inOrderIndex) throws Exception {
if(inOrder instanceof OrderSingle) {
ClientManager.getInstance().sendOrder((OrderSingle)inOrder);
} else if(inOrder instanceof FIXOrder) {
ClientManager.getInstance().sendOrderRaw((FIXOrder)inOrder);
} else {
throw new OrderParsingException(new I18NBoundMessage1P(
Messages.UNEXPECTED_ORDER_TYPE, inOrder));
}
mOrdersOutstanding.getAndIncrement();
}
@Override
public void done() {
if (!ClientManager.isInitialized()) {
return;
}
// Wait until a certain timeout for the ORS to acknowledge
// receipt of orders sent. If we don't wait, because orders
// are sent via JMS which is asynchronous, we might close the
// client (a synchronous operation which results in
// invalidating the ORS session) before the ORS has a chance
// to see the orders we sent.
long end=System.currentTimeMillis()+MAXIMUM_DELIVERY_WAIT;
int lastOrdersOutstanding=mOrdersOutstanding.get();
while (lastOrdersOutstanding!=0) {
try {
// A short delay is used here so that we don't delay
// exiting for too long after all orders have been
// sent.
Thread.sleep(500);
} catch (InterruptedException ex) {
break;
}
long now=System.currentTimeMillis();
int ordersOutstanding=mOrdersOutstanding.get();
if (ordersOutstanding<lastOrdersOutstanding) {
// Extend the timeout if at least one order has been
// processed.
end=now+MAXIMUM_DELIVERY_WAIT;
lastOrdersOutstanding=ordersOutstanding;
} else if (now>end) {
break;
}
}
try {
ClientManager.getInstance().close();
} catch (ClientInitException ignore) {
}
}
}