/*
* 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.eclipse.core.runtime.jobs.ILock;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipsetrader.core.instruments.ISecurity;
import org.eclipsetrader.core.internal.CoreActivator;
/**
* Default implementation of the <code>IPricingEnvironment</code> interface.
* <p>Clients sets pricing values using setters methods.</p>
*
* @since 1.0
*/
public class PricingEnvironment implements IPricingEnvironment {
private ListenerList listeners = new ListenerList(ListenerList.IDENTITY);
private boolean doNotify = true;
class PricingStatus {
ITrade trade;
IQuote quote;
ITodayOHL todayOHL;
ILastClose lastClose;
IBook book;
List<PricingDelta> deltas = new ArrayList<PricingDelta>();
}
private Map<ISecurity, PricingStatus> map = new HashMap<ISecurity, PricingStatus>();
private final ILock lock;
public PricingEnvironment() {
lock = Job.getJobManager().newLock();
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#dispose()
*/
@Override
public void dispose() {
listeners.clear();
map.clear();
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#addPricingEnvironmentListener(org.eclipsetrader.core.feed.IPricingListener)
*/
@Override
public void addPricingListener(IPricingListener listener) {
listeners.add(listener);
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#removePricingEnvironmentListener(org.eclipsetrader.core.feed.IPricingListener)
*/
@Override
public void removePricingListener(IPricingListener listener) {
listeners.remove(listener);
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#getTrade(org.eclipsetrader.core.instruments.ISecurity)
*/
@Override
public ITrade getTrade(ISecurity security) {
return map.get(security) != null ? map.get(security).trade : null;
}
/**
* Sets a new trade for a security.
*
* @param security the security.
* @param trade the new trade value.
*/
public void setTrade(ISecurity security, ITrade trade) {
PricingStatus status = map.get(security);
if (status == null) {
status = new PricingStatus();
map.put(security, status);
}
Object oldValue = status.trade;
if (oldValue == null && trade != null || oldValue != null && !oldValue.equals(trade)) {
status.trade = trade;
status.deltas.add(new PricingDelta(oldValue, trade));
if (doNotify) {
notifyListeners();
}
}
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#getQuote(org.eclipsetrader.core.instruments.ISecurity)
*/
@Override
public IQuote getQuote(ISecurity security) {
return map.get(security) != null ? map.get(security).quote : null;
}
/**
* Sets a new quote for a security.
*
* @param security the security.
* @param quote the new quote value.
*/
public void setQuote(ISecurity security, IQuote quote) {
PricingStatus status = map.get(security);
if (status == null) {
status = new PricingStatus();
map.put(security, status);
}
Object oldValue = status.quote;
if (oldValue == null && quote != null || oldValue != null && !oldValue.equals(quote)) {
status.quote = quote;
status.deltas.add(new PricingDelta(oldValue, quote));
if (doNotify) {
notifyListeners();
}
}
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#getTodayOHL(org.eclipsetrader.core.instruments.ISecurity)
*/
@Override
public ITodayOHL getTodayOHL(ISecurity security) {
return map.get(security) != null ? map.get(security).todayOHL : null;
}
/**
* Sets a new today's OHL for a security.
*
* @param security the security.
* @param todayOHL the new OHL value.
*/
public void setTodayOHL(ISecurity security, ITodayOHL todayOHL) {
PricingStatus status = map.get(security);
if (status == null) {
status = new PricingStatus();
map.put(security, status);
}
Object oldValue = status.todayOHL;
if (oldValue == null && todayOHL != null || oldValue != null && !oldValue.equals(todayOHL)) {
status.todayOHL = todayOHL;
status.deltas.add(new PricingDelta(oldValue, todayOHL));
if (doNotify) {
notifyListeners();
}
}
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#getLastClose(org.eclipsetrader.core.instruments.ISecurity)
*/
@Override
public ILastClose getLastClose(ISecurity security) {
return map.get(security) != null ? map.get(security).lastClose : null;
}
/**
* Sets a new last close price for a security.
*
* @param security the security.
* @param lastClose the new last close value.
*/
public void setLastClose(ISecurity security, ILastClose lastClose) {
PricingStatus status = map.get(security);
if (status == null) {
status = new PricingStatus();
map.put(security, status);
}
Object oldValue = status.lastClose;
if (oldValue == null && lastClose != null || oldValue != null && !oldValue.equals(lastClose)) {
status.lastClose = lastClose;
status.deltas.add(new PricingDelta(oldValue, lastClose));
if (doNotify) {
notifyListeners();
}
}
}
/* (non-Javadoc)
* @see org.eclipsetrader.core.feed.IPricingEnvironment#getBook(org.eclipsetrader.core.instruments.ISecurity)
*/
@Override
public IBook getBook(ISecurity security) {
return map.get(security) != null ? map.get(security).book : null;
}
/**
* Sets the new level II book values for a security.
*
* @param security the security.
* @param book the new book values.
*/
public void setBook(ISecurity security, IBook book) {
PricingStatus status = map.get(security);
if (status == null) {
status = new PricingStatus();
map.put(security, status);
}
Object oldValue = status.book;
if (oldValue == null && book != null || oldValue != null && !oldValue.equals(book)) {
status.book = book;
status.deltas.add(new PricingDelta(oldValue, book));
if (doNotify) {
notifyListeners();
}
}
}
public void setBarOpen(ISecurity security, IBarOpen bar) {
PricingStatus status = map.get(security);
if (status == null) {
status = new PricingStatus();
map.put(security, status);
}
status.deltas.add(new PricingDelta(null, bar));
if (doNotify) {
notifyListeners();
}
}
public void setBar(ISecurity security, IBar bar) {
PricingStatus status = map.get(security);
if (status == null) {
status = new PricingStatus();
map.put(security, status);
}
status.deltas.add(new PricingDelta(null, bar));
if (doNotify) {
notifyListeners();
}
}
/**
* Updates a set of quotes in a single batch. Events are notified to the listeners
* when the runnable returns.
*
* @param runnable the runnable to run.
*/
public void runBatch(Runnable runnable) {
try {
lock.acquire();
doNotify = false;
try {
runnable.run();
} catch (Exception e) {
Status status = new Status(IStatus.ERROR, CoreActivator.PLUGIN_ID, 0, "Error running pricing environment batch", e); //$NON-NLS-1$
CoreActivator.getDefault().getLog().log(status);
} catch (LinkageError e) {
Status status = new Status(IStatus.ERROR, CoreActivator.PLUGIN_ID, 0, "Error running pricing environment batch", e); //$NON-NLS-1$
CoreActivator.getDefault().getLog().log(status);
}
notifyListeners();
doNotify = true;
} catch (Exception e) {
Status status = new Status(IStatus.ERROR, CoreActivator.PLUGIN_ID, 0, "Error running pricing environment batch", e); //$NON-NLS-1$
CoreActivator.getDefault().getLog().log(status);
} finally {
lock.release();
}
}
/**
* Notify all listeners of changes occurred since the last notification.
*/
protected void notifyListeners() {
Object[] l = listeners.getListeners();
for (ISecurity security : map.keySet()) {
PricingStatus status = map.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.log(status);
}
});
}
status.deltas.clear();
}
}
PricingStatus getStatus(ISecurity security) {
return map.get(security);
}
}