package org.chartsy.main.managers; import java.util.HashMap; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.swing.event.EventListenerList; import org.chartsy.main.data.DataItem; import org.chartsy.main.data.DataProvider; import org.chartsy.main.data.Dataset; import org.chartsy.main.data.Stock; import org.chartsy.main.events.DataProviderEvent; import org.chartsy.main.events.DataProviderListener; import org.chartsy.main.intervals.Interval; /** * * @author Viorel */ public class DatasetUsage { private static DatasetUsage instance; private final static ScheduledExecutorService service = Executors.newScheduledThreadPool(1); private HashMap<String, Dataset> datasets; private HashMap<String, AtomicInteger> datasetsUsage; private HashMap<String, DatasetUpdaterExecutor> datasetsUpdaters; private EventListenerList eventListenerList; public static DatasetUsage getInstance() { if (instance == null) instance = new DatasetUsage(); return instance; } private DatasetUsage() { datasets = new HashMap<String, Dataset>(); datasetsUsage = new HashMap<String, AtomicInteger>(); datasetsUpdaters = new HashMap<String, DatasetUpdaterExecutor>(); eventListenerList = new EventListenerList(); } public void addDataProviderListener(DataProviderListener listener) { eventListenerList.add(DataProviderListener.class, listener); } public void removeDataProviderListener(DataProviderListener listener) { eventListenerList.remove(DataProviderListener.class, listener); } private void fireDataProviderEvent(DataProviderEvent event) { DataProviderListener[] listeners = eventListenerList.getListeners(DataProviderListener.class); for (DataProviderListener listener : listeners) listener.triggerDataProviderListener(event); } public void addDatasetUpdater(String dataProvider, Stock stock, Interval interval) { DataProvider provider = DataProviderManager.getDefault().getDataProvider(dataProvider); String key = provider.getDatasetKey(stock, interval); if (!datasetsUpdaters.containsKey(key)) { DatasetUpdaterExecutor updaterExecutor = new DatasetUpdaterExecutor(dataProvider, stock, interval); datasetsUpdaters.put(key, updaterExecutor); } } public void addDataset(String key, Dataset dataset) { datasets.put(key, dataset); } public void removeDataset(String key) { datasets.remove(key); datasetsUsage.remove(key); datasetsUpdaters.get(key).stop(); datasetsUpdaters.remove(key); System.gc(); } public boolean isDatasetInMemory(String key) { boolean exists = datasets.containsKey(key); return exists; } public Dataset getDatasetFromMemory(String key) { Dataset dataset = datasets.get(key); return dataset; } public void fetchDataset(String key) { if (!datasetsUsage.containsKey(key)) { AtomicInteger integer = new AtomicInteger(1); datasetsUsage.put(key, integer); } else { AtomicInteger integer = datasetsUsage.get(key); integer.incrementAndGet(); datasetsUsage.put(key, integer); } } public void chartClosed(String key) { AtomicInteger integer = datasetsUsage.get(key); if (integer != null) { int usage = integer.decrementAndGet(); if (usage == 0) removeDataset(key); else datasetsUsage.put(key, integer); } } public class DatasetUpdaterExecutor { private String dataProviderName; private Stock stock; private Interval interval; private ScheduledFuture future; public DatasetUpdaterExecutor(String dataProvider, Stock stock, Interval interval) { this.dataProviderName = dataProvider; this.stock = stock; this.interval = interval; initialize(); } private void initialize() { final DataProvider dataProvider = DataProviderManager.getDefault().getDataProvider(dataProviderName); int refreshInterval = dataProvider.getRefreshInterval(); final Runnable updater = new Runnable() { @Override public void run() { int itemsAdded = 0; boolean fireUpdate = false; String key = dataProvider.getDatasetKey(stock, interval); if (!interval.isIntraDay()) { DataItem newItem = dataProvider.getLastDataItem(stock, interval); if (newItem != null) { DataItem oldItem = getDatasetFromMemory(key).getLastDataItem(); long oldTime = oldItem.getTime(); long newTime = newItem.getTime(); if ( oldTime != newTime ) { getDatasetFromMemory(key).addDataItem(newItem); itemsAdded = 1; fireUpdate = true; } else { boolean updateClose = oldItem.updateClose(newItem); if ( updateClose ) { int index = getDatasetFromMemory(key).getLastIndex(); DatasetUsage.getInstance().getDatasetFromMemory(key).setDataItem(index, newItem); fireUpdate = true; } } } } else { int count = getDatasetFromMemory(key).getItemsCount(); List<DataItem> dataItems = dataProvider.getLastDataItems(stock, interval); if (dataItems.size() > 0) { fireUpdate = dataProvider.updateIntraDay(key, dataItems); itemsAdded = getDatasetFromMemory(key).getItemsCount() - count; } dataItems = null; } if ( fireUpdate ) { DataProviderEvent event = new DataProviderEvent(key, itemsAdded); fireDataProviderEvent(event); } } }; future = service.scheduleAtFixedRate(updater, refreshInterval, refreshInterval, TimeUnit.SECONDS); } public void stop() { future.cancel(true); } public ScheduledFuture getScheduledFuture() { return future; } } }