/*******************************************************************************
* Copyright (c) 2013 Luigi Sgro. 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:
* Luigi Sgro - initial API and implementation
******************************************************************************/
package com.quantcomponents.tradingcalendars;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import com.quantcomponents.core.calendar.FlatCalendar;
import com.quantcomponents.core.calendar.ITradingCalendar;
import com.quantcomponents.core.calendar.ITradingCalendarManager;
import com.quantcomponents.core.model.IContract;
import com.quantcomponents.tradingcalendars.TradingCalendarFactoryBean.SpecificTradingDay;
import com.quantcomponents.tradingcalendars.TradingCalendarFactoryBean.WeekTradingDay;
public class TradingCalendarRegistry implements ITradingCalendarManager, BundleListener {
private static final ITradingCalendar FLAT_CALENDAR = new FlatCalendar();
private final Map<String, Set<URL>> urlByBundleLocation = new HashMap<String, Set<URL>>();
private final Map<URL, ITradingCalendar> calendars = new ConcurrentHashMap<URL, ITradingCalendar>();
@Override
public List<ITradingCalendar> findTradingCalendars(IContract contract, Boolean includeAfterHours) {
List<ITradingCalendar> result = new LinkedList<ITradingCalendar>();
String exchange = contract.getPrimaryExchange();
if (exchange == null) {
exchange = contract.getExchange();
}
for (ITradingCalendar calendar : calendars.values()) {
if (calendar.getExchanges().length > 0 && exchange != null) {
if (Arrays.binarySearch(calendar.getExchanges(), exchange) < 0) {
continue;
}
}
if (includeAfterHours != null && calendar.isIncludeAfterHours() != null && calendar.isIncludeAfterHours() != includeAfterHours) {
continue;
}
result.add(calendar);
}
result.add(FLAT_CALENDAR);
return result;
}
@Override
public ITradingCalendar tradingCalendarByName(String name) {
for (ITradingCalendar calendar : calendars.values()) {
if (calendar.getName().equals(name)) {
return calendar;
}
}
return null;
}
@Override
public void bundleChanged(BundleEvent event) {
if (event.getType() == BundleEvent.INSTALLED) {
addBundleCalendars(event.getBundle());
} else if (event.getType() == BundleEvent.UNINSTALLED) {
synchronized (urlByBundleLocation) {
String bundleLocation = event.getBundle().getLocation();
Set<URL> bundleUrlSet = urlByBundleLocation.get(bundleLocation);
if (bundleUrlSet != null) {
for (URL url : bundleUrlSet) {
calendars.remove(url);
}
urlByBundleLocation.remove(bundleLocation);
}
}
}
}
void addBundleCalendars(Bundle bundle) {
Enumeration<URL> urls = findCalendarData(bundle);
while (urls != null && urls.hasMoreElements()) {
URL url = urls.nextElement();
try {
TradingCalendarFactoryBean factory = createFactoryFromCalendarData(url);
calendars.put(url, factory.createTradingCalendar());
synchronized (urlByBundleLocation) {
Set<URL> bundleUrlSet = urlByBundleLocation.get(bundle.getLocation());
if (bundleUrlSet == null) {
bundleUrlSet = new HashSet<URL>();
urlByBundleLocation.put(bundle.getLocation(), bundleUrlSet);
}
bundleUrlSet.add(url);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private TradingCalendarFactoryBean createFactoryFromCalendarData(URL calendarData) throws JAXBException, IOException {
TradingCalendarFactoryBean result = null;
JAXBContext context = JAXBContext.newInstance(TradingCalendarFactoryBean.class, WeekTradingDay.class, SpecificTradingDay.class);
Unmarshaller m = context.createUnmarshaller();
Object o = null;
o = m.unmarshal(calendarData.openStream());
result = (TradingCalendarFactoryBean) o;
return result;
}
private Enumeration<URL> findCalendarData(Bundle bundle) {
return bundle.findEntries("/tradingCalendars", "*.xml", false);
}
}