/*
* 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.ui.internal.charts;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.internal.runtime.AdapterManager;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.osgi.util.NLS;
import org.eclipsetrader.core.feed.History;
import org.eclipsetrader.core.feed.HistoryDay;
import org.eclipsetrader.core.feed.IBackfillConnector;
import org.eclipsetrader.core.feed.IConnectorOverride;
import org.eclipsetrader.core.feed.IDividend;
import org.eclipsetrader.core.feed.IFeedIdentifier;
import org.eclipsetrader.core.feed.IHistory;
import org.eclipsetrader.core.feed.IOHLC;
import org.eclipsetrader.core.feed.ISplit;
import org.eclipsetrader.core.feed.TimeSpan;
import org.eclipsetrader.core.instruments.ISecurity;
import org.eclipsetrader.core.instruments.Stock;
import org.eclipsetrader.core.internal.CoreActivator;
import org.eclipsetrader.core.markets.IMarket;
import org.eclipsetrader.core.markets.IMarketService;
import org.eclipsetrader.core.repositories.IRepository;
import org.eclipsetrader.core.repositories.IRepositoryService;
import org.eclipsetrader.core.repositories.IStoreObject;
import org.eclipsetrader.ui.internal.UIActivator;
@SuppressWarnings("restriction")
public class DataImportJob extends Job {
public static final int FULL = 0;
public static final int INCREMENTAL = 1;
public static final int FULL_INCREMENTAL = 2;
private ISecurity[] securities;
private int mode;
private TimeSpan[] timeSpan;
private Date fromDate;
private Date toDate;
private List<IStatus> results = new ArrayList<IStatus>();
IPreferenceStore preferences;
public DataImportJob(ISecurity security, int mode, Date fromDate, Date toDate, TimeSpan[] timeSpan) {
super(Messages.DataImportJob_Name);
this.securities = new ISecurity[] {
security
};
this.mode = mode;
this.fromDate = fromDate;
this.toDate = toDate;
this.timeSpan = timeSpan;
}
public DataImportJob(ISecurity[] securities, int mode, Date fromDate, Date toDate, TimeSpan[] timeSpan) {
super(Messages.DataImportJob_Name);
this.securities = securities;
this.mode = mode;
this.fromDate = fromDate;
this.toDate = toDate;
this.timeSpan = timeSpan;
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
protected IStatus run(IProgressMonitor monitor) {
ISecurity[] filteredList = getFilteredSecurities(securities);
monitor.beginTask(getName(), filteredList.length);
preferences = UIActivator.getDefault().getPreferenceStore();
IBackfillConnector defaultBackfillConnector = CoreActivator.getDefault().getDefaultBackfillConnector();
IBackfillConnector defaultIntradayBackfillConnector = CoreActivator.getDefault().getDefaultBackfillConnector();
try {
IRepositoryService repositoryService = UIActivator.getDefault().getRepositoryService();
IMarketService marketService = UIActivator.getDefault().getMarketService();
for (ISecurity security : filteredList) {
if (monitor.isCanceled()) {
if (results.size() != 0) {
return new MultiStatus(UIActivator.PLUGIN_ID, 0, results.toArray(new IStatus[results.size()]), Messages.DataImportJob_DownloadErrorMessage, null);
}
return Status.CANCEL_STATUS;
}
monitor.subTask(security.getName().replace("&", "&&")); //$NON-NLS-1$ //$NON-NLS-2$
try {
IStoreObject storeObject = (IStoreObject) security.getAdapter(IStoreObject.class);
IRepository defaultRepository = storeObject.getStore().getRepository();
IFeedIdentifier identifier = (IFeedIdentifier) security.getAdapter(IFeedIdentifier.class);
IBackfillConnector backfillConnector = defaultBackfillConnector;
IBackfillConnector intradayBackfillConnector = defaultIntradayBackfillConnector;
IMarket market = marketService.getMarketForSecurity(security);
if (market != null && market.getBackfillConnector() != null) {
backfillConnector = market.getBackfillConnector();
intradayBackfillConnector = market.getIntradayBackfillConnector() != null ? market.getIntradayBackfillConnector() : market.getBackfillConnector();
}
IConnectorOverride override = (IConnectorOverride) AdapterManager.getDefault().getAdapter(security, IConnectorOverride.class);
if (override != null) {
if (override.getBackfillConnector() != null) {
backfillConnector = override.getBackfillConnector();
intradayBackfillConnector = override.getBackfillConnector();
}
if (override.getIntradayBackfillConnector() != null) {
intradayBackfillConnector = override.getIntradayBackfillConnector();
}
}
Date beginDate = fromDate;
Date endDate = toDate;
if (beginDate == null) {
beginDate = getDefaultStartDate();
}
if (endDate == null) {
endDate = new Date();
}
IHistory history = repositoryService.getHistoryFor(security);
Map<Date, IOHLC> dailyDataMap = new HashMap<Date, IOHLC>(2048);
if (history != null && mode != FULL) {
for (IOHLC d : history.getOHLC()) {
dailyDataMap.put(d.getDate(), d);
}
if (mode == INCREMENTAL) {
if (history.getLast() != null) {
beginDate = history.getLast().getDate();
}
endDate = Calendar.getInstance().getTime();
}
}
Map<TimeSpan, IOHLC[]> dataMap = new HashMap<TimeSpan, IOHLC[]>();
for (TimeSpan currentTimeSpan : timeSpan) {
if (monitor.isCanceled()) {
if (results.size() != 0) {
return new MultiStatus(UIActivator.PLUGIN_ID, 0, results.toArray(new IStatus[results.size()]), Messages.DataImportJob_DownloadErrorMessage, null);
}
return Status.CANCEL_STATUS;
}
if (currentTimeSpan.equals(TimeSpan.days(1))) {
IOHLC[] ohlc = backfillConnector.backfillHistory(identifier, beginDate, endDate, currentTimeSpan);
if (ohlc != null && ohlc.length != 0) {
dataMap.put(currentTimeSpan, ohlc);
}
}
else if (intradayBackfillConnector.canBackfill(identifier, currentTimeSpan)) {
IOHLC[] ohlc = intradayBackfillConnector.backfillHistory(identifier, beginDate, endDate, currentTimeSpan);
if (ohlc != null && ohlc.length != 0) {
dataMap.put(currentTimeSpan, ohlc);
}
}
else {
dataMap.put(currentTimeSpan, null);
}
if (!dataMap.containsKey(currentTimeSpan)) {
String message = NLS.bind(Messages.DataImportJob_DownloadDataErrorMessage, new Object[] {
currentTimeSpan.toString(),
security.getName()
});
Status status = new Status(IStatus.ERROR, UIActivator.PLUGIN_ID, 0, message, null);
results.add(status);
}
}
if (dataMap.size() == timeSpan.length) {
for (TimeSpan currentTimeSpan : dataMap.keySet()) {
IOHLC[] ohlc = dataMap.get(currentTimeSpan);
if (ohlc == null) {
continue;
}
if (currentTimeSpan.equals(TimeSpan.days(1))) {
for (IOHLC d : ohlc) {
dailyDataMap.put(d.getDate(), d);
}
ohlc = dailyDataMap.values().toArray(new IOHLC[dailyDataMap.values().size()]);
if (history == null) {
history = new History(security, ohlc);
}
else if (history instanceof History) {
((History) history).setOHLC(ohlc);
}
if (security instanceof Stock && history instanceof History) {
ISplit[] splits = backfillConnector.backfillSplits(identifier, beginDate, endDate);
if (splits != null && splits.length != 0) {
Map<Date, ISplit> splitsMap = new HashMap<Date, ISplit>();
ISplit[] currentSplits = history.getSplits();
if (currentSplits != null && mode != FULL) {
for (ISplit s : currentSplits) {
splitsMap.put(s.getDate(), s);
}
}
for (int i = 0; i < splits.length; i++) {
splitsMap.put(splits[i].getDate(), splits[i]);
}
Collection<ISplit> c = splitsMap.values();
((History) history).setSplits(c.toArray(new ISplit[c.size()]));
}
}
repositoryService.saveAdaptable(new IHistory[] {
history
}, defaultRepository);
}
else {
if (history == null) {
history = new History(security, ohlc);
IHistory intradayHistory = history.getSubset(beginDate, endDate, currentTimeSpan);
if (intradayHistory instanceof HistoryDay) {
((HistoryDay) intradayHistory).setOHLC(ohlc);
}
repositoryService.saveAdaptable(new IHistory[] {
history, intradayHistory
}, defaultRepository);
}
else {
IHistory intradayHistory = history.getSubset(beginDate, endDate, currentTimeSpan);
if (intradayHistory instanceof HistoryDay) {
((HistoryDay) intradayHistory).setOHLC(ohlc);
}
repositoryService.saveAdaptable(new IHistory[] {
intradayHistory
}, defaultRepository);
}
}
}
if (security instanceof Stock) {
IDividend[] dividends = backfillConnector.backfillDividends(identifier, beginDate, endDate);
if (dividends != null && dividends.length != 0) {
Map<Date, IDividend> dividendsMap = new HashMap<Date, IDividend>();
IDividend[] currentDividends = ((Stock) security).getDividends();
if (currentDividends != null && mode != FULL) {
for (IDividend d : currentDividends) {
dividendsMap.put(d.getExDate(), d);
}
}
for (int i = 0; i < dividends.length; i++) {
dividendsMap.put(dividends[i].getExDate(), dividends[i]);
}
if (dividendsMap.size() != 0) {
((Stock) security).setDividends(dividendsMap.values().toArray(new IDividend[dividendsMap.values().size()]));
repositoryService.saveAdaptable(new ISecurity[] {
security
});
}
}
}
}
} catch (Exception e) {
Status status = new Status(IStatus.ERROR, UIActivator.PLUGIN_ID, 0, Messages.DataImportJob_SecurityDownloadErrorMessage + security.getName(), e);
results.add(status);
}
monitor.worked(1);
}
} catch (Exception e) {
Status status = new Status(IStatus.ERROR, UIActivator.PLUGIN_ID, 0, Messages.DataImportJob_DataErrorMessage, e);
results.add(status);
} finally {
monitor.done();
}
if (results.size() != 0) {
return new MultiStatus(UIActivator.PLUGIN_ID, 0, results.toArray(new IStatus[results.size()]), Messages.DataImportJob_DownloadErrorMessage, null);
}
return Status.OK_STATUS;
}
Date getDefaultStartDate() throws ParseException {
int method = preferences.getInt(UIActivator.PREFS_INITIAL_BACKFILL_METHOD);
if (method == 0) {
String s = preferences.getString(UIActivator.PREFS_INITIAL_BACKFILL_START_DATE);
return new SimpleDateFormat("yyyyMMdd").parse(s);
}
else if (method == 1) {
Calendar c = Calendar.getInstance();
c.set(Calendar.MILLISECOND, 0);
c.add(Calendar.YEAR, -preferences.getInt(UIActivator.PREFS_INITIAL_BACKFILL_YEARS));
return c.getTime();
}
throw new IllegalArgumentException("Invalid initial backfill method " + method);
}
protected ISecurity[] getFilteredSecurities(ISecurity[] list) {
List<ISecurity> l = new ArrayList<ISecurity>();
for (ISecurity security : list) {
IFeedIdentifier identifier = (IFeedIdentifier) security.getAdapter(IFeedIdentifier.class);
if (identifier != null) {
l.add(security);
}
}
Collections.sort(l, new Comparator<ISecurity>() {
@Override
public int compare(ISecurity o1, ISecurity o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
});
return l.toArray(new ISecurity[l.size()]);
}
}