/*
* Copyright (c) 2004-2011 Marco Maccaferri and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Marco Maccaferri - initial API and implementation
*/
package org.eclipsetrader.core.feed;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipsetrader.core.instruments.ISecurity;
import org.eclipsetrader.core.internal.CoreActivator;
public class SingleFeedPricingEnvironment implements IPricingEnvironment {
private IFeedConnector connector;
class PricingStatus {
ITrade trade;
IQuote quote;
ITodayOHL todayOHL;
ILastClose lastClose;
IBook book;
List<PricingDelta> deltas = new ArrayList<PricingDelta>();
IFeedSubscription subscription;
}
class SubscriptionStatus {
IFeedSubscription subscription;
List<ISecurity> securities = new ArrayList<ISecurity>();
}
Map<ISecurity, PricingStatus> securitiesMap = new HashMap<ISecurity, PricingStatus>();
Map<IFeedIdentifier, SubscriptionStatus> identifiersMap = new HashMap<IFeedIdentifier, SubscriptionStatus>();
private ListenerList listeners = new ListenerList(ListenerList.IDENTITY);
private ISubscriptionListener listener = new ISubscriptionListener() {
@Override
public void quoteUpdate(QuoteEvent event) {
processUpdateQuotes(event.getIdentifier(), event.getDelta());
}
};
protected SingleFeedPricingEnvironment() {
}
public SingleFeedPricingEnvironment(IFeedConnector connector) {
this.connector = connector;
}
public void addSecurity(ISecurity security) {
IFeedIdentifier identifier = (IFeedIdentifier) security.getAdapter(IFeedIdentifier.class);
PricingStatus pricingStatus = securitiesMap.get(security);
if (pricingStatus == null) {
pricingStatus = new PricingStatus();
securitiesMap.put(security, pricingStatus);
}
if (identifier != null) {
SubscriptionStatus subscriptionStatus = identifiersMap.get(identifier);
if (subscriptionStatus == null) {
subscriptionStatus = new SubscriptionStatus();
identifiersMap.put(identifier, subscriptionStatus);
}
subscriptionStatus.securities.add(security);
if (subscriptionStatus.subscription == null) {
subscriptionStatus.subscription = connector.subscribe(identifier);
subscriptionStatus.subscription.addSubscriptionListener(listener);
}
pricingStatus.trade = subscriptionStatus.subscription.getTrade();
pricingStatus.quote = subscriptionStatus.subscription.getQuote();
pricingStatus.todayOHL = subscriptionStatus.subscription.getTodayOHL();
pricingStatus.lastClose = subscriptionStatus.subscription.getLastClose();
}
}
public void addSecurities(ISecurity[] securities) {
for (ISecurity security : securities) {
addSecurity(security);
}
}
public void removeSecurity(ISecurity security) {
IFeedIdentifier identifier = (IFeedIdentifier) security.getAdapter(IFeedIdentifier.class);
securitiesMap.remove(security);
if (identifier != null) {
SubscriptionStatus subscriptionStatus = identifiersMap.get(identifier);
if (subscriptionStatus != null) {
subscriptionStatus.securities.remove(security);
if (subscriptionStatus.securities.size() == 0) {
subscriptionStatus.subscription.removeSubscriptionListener(listener);
identifiersMap.remove(identifier);
subscriptionStatus.subscription.dispose();
}
}
}
}
public void removeSecurities(ISecurity[] securities) {
for (ISecurity security : securities) {
removeSecurity(security);
}
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#addPricingListener(org.eclipsetrader.core.feed.IPricingListener)
*/
@Override
public void addPricingListener(IPricingListener listener) {
listeners.add(listener);
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#removePricingListener(org.eclipsetrader.core.feed.IPricingListener)
*/
@Override
public void removePricingListener(IPricingListener listener) {
listeners.remove(listener);
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#dispose()
*/
@Override
public void dispose() {
listeners.clear();
for (SubscriptionStatus pricingStatus : identifiersMap.values()) {
if (pricingStatus.subscription != null) {
pricingStatus.subscription.removeSubscriptionListener(listener);
}
}
identifiersMap.clear();
securitiesMap.clear();
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#getTrade(org.eclipsetrader.core.instruments.ISecurity)
*/
@Override
public ITrade getTrade(ISecurity security) {
return securitiesMap.get(security) != null ? securitiesMap.get(security).trade : null;
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#getQuote(org.eclipsetrader.core.instruments.ISecurity)
*/
@Override
public IQuote getQuote(ISecurity security) {
return securitiesMap.get(security) != null ? securitiesMap.get(security).quote : null;
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#getTodayOHL(org.eclipsetrader.core.instruments.ISecurity)
*/
@Override
public ITodayOHL getTodayOHL(ISecurity security) {
return securitiesMap.get(security) != null ? securitiesMap.get(security).todayOHL : null;
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#getLastClose(org.eclipsetrader.core.instruments.ISecurity)
*/
@Override
public ILastClose getLastClose(ISecurity security) {
return securitiesMap.get(security) != null ? securitiesMap.get(security).lastClose : null;
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#getBook(org.eclipsetrader.core.instruments.ISecurity)
*/
@Override
public IBook getBook(ISecurity security) {
return securitiesMap.get(security) != null ? securitiesMap.get(security).book : null;
}
protected void processUpdateQuotes(IFeedIdentifier identifier, QuoteDelta[] delta) {
SubscriptionStatus subscriptionStatus = identifiersMap.get(identifier);
if (subscriptionStatus != null) {
for (ISecurity security : subscriptionStatus.securities) {
PricingStatus pricingStatus = securitiesMap.get(security);
if (pricingStatus != null) {
for (QuoteDelta d : delta) {
if (d.getNewValue() instanceof ITrade) {
pricingStatus.trade = (ITrade) d.getNewValue();
}
if (d.getNewValue() instanceof IQuote) {
pricingStatus.quote = (IQuote) d.getNewValue();
}
if (d.getNewValue() instanceof ITodayOHL) {
pricingStatus.todayOHL = (ITodayOHL) d.getNewValue();
}
if (d.getNewValue() instanceof ILastClose) {
pricingStatus.lastClose = (ILastClose) d.getNewValue();
}
if (d.getNewValue() instanceof IBook) {
pricingStatus.book = (IBook) d.getNewValue();
}
pricingStatus.deltas.add(new PricingDelta(d.getOldValue(), d.getNewValue()));
}
}
}
notifyListeners();
}
}
protected void notifyListeners() {
Object[] l = listeners.getListeners();
for (ISecurity security : securitiesMap.keySet()) {
PricingStatus status = securitiesMap.get(security);
if (status == null || status.deltas.size() == 0) {
continue;
}
final PricingEvent event = new PricingEvent(security, status.deltas.toArray(new PricingDelta[status.deltas.size()]));
for (int i = 0; i < l.length; i++) {
final IPricingListener listener = (IPricingListener) l[i];
SafeRunner.run(new ISafeRunnable() {
@Override
public void run() throws Exception {
listener.pricingUpdate(event);
}
@Override
public void handleException(Throwable exception) {
Status status = new Status(IStatus.ERROR, CoreActivator.PLUGIN_ID, 0, "Error running pricing environment listener", exception); //$NON-NLS-1$
CoreActivator.getDefault().getLog().log(status);
}
});
}
status.deltas.clear();
}
}
PricingStatus getPricingStatus(ISecurity security) {
return securitiesMap.get(security);
}
SubscriptionStatus getSubscriptionStatus(ISecurity security) {
IFeedIdentifier identifier = (IFeedIdentifier) security.getAdapter(IFeedIdentifier.class);
return identifier != null ? identifiersMap.get(identifier) : null;
}
}