package org.knowm.xchange;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.knowm.xchange.currency.CurrencyPair;
import org.knowm.xchange.dto.meta.ExchangeMetaData;
import org.knowm.xchange.exceptions.ExchangeException;
import org.knowm.xchange.service.BaseExchangeService;
import org.knowm.xchange.service.account.AccountService;
import org.knowm.xchange.service.marketdata.MarketDataService;
import org.knowm.xchange.service.trade.TradeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
public abstract class BaseExchange implements Exchange {
protected abstract void initServices();
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected ExchangeSpecification exchangeSpecification;
protected ExchangeMetaData exchangeMetaData;
protected MarketDataService marketDataService;
protected TradeService tradeService;
protected AccountService accountService;
@Override
public void applySpecification(ExchangeSpecification exchangeSpecification) {
ExchangeSpecification defaultSpecification = getDefaultExchangeSpecification();
// Check if default is for everything
if (exchangeSpecification == null) {
this.exchangeSpecification = defaultSpecification;
} else {
// Using a configured exchange
// fill in null params with the default ones
if (exchangeSpecification.getExchangeName() == null) {
exchangeSpecification.setExchangeName(defaultSpecification.getExchangeName());
}
if (exchangeSpecification.getExchangeDescription() == null) {
exchangeSpecification.setExchangeDescription(defaultSpecification.getExchangeDescription());
}
if (exchangeSpecification.getSslUri() == null) {
exchangeSpecification.setSslUri(defaultSpecification.getSslUri());
}
if (exchangeSpecification.getHost() == null) {
exchangeSpecification.setHost(defaultSpecification.getHost());
}
if (exchangeSpecification.getPlainTextUri() == null) {
exchangeSpecification.setPlainTextUri(defaultSpecification.getPlainTextUri());
}
if (exchangeSpecification.getExchangeSpecificParameters() == null) {
exchangeSpecification.setExchangeSpecificParameters(defaultSpecification.getExchangeSpecificParameters());
} else {
// add default value unless it is overridden by current spec
for (Map.Entry<String, Object> entry : defaultSpecification.getExchangeSpecificParameters().entrySet()) {
if (exchangeSpecification.getExchangeSpecificParametersItem(entry.getKey()) == null) {
exchangeSpecification.setExchangeSpecificParametersItem(entry.getKey(), entry.getValue());
}
}
}
this.exchangeSpecification = exchangeSpecification;
}
if (this.exchangeSpecification.getMetaDataJsonFileOverride() != null) { // load the metadata from the file system
InputStream is = null;
try {
is = new FileInputStream(this.exchangeSpecification.getMetaDataJsonFileOverride());
loadExchangeMetaData(is);
} catch (FileNotFoundException e) {
logger.warn(
"An exception occured while loading the metadata file from the classpath. This is just a warning and can be ignored, but it may lead to unexpected results, so it's better to address it.",
e);
} finally {
IOUtils.closeQuietly(is);
}
} else if (this.exchangeSpecification.getExchangeName() != null) { // load the metadata from the classpath
InputStream is = null;
try {
is = BaseExchangeService.class.getClassLoader().getResourceAsStream(getMetaDataFileName(exchangeSpecification) + ".json");
loadExchangeMetaData(is);
} finally {
IOUtils.closeQuietly(is);
}
} else {
logger.warn(
"No \"exchange name\" found in the ExchangeSpecification. The name is used to load the meta data file from the classpath and may lead to unexpected results.");
}
initServices();
if (this.exchangeSpecification.isShouldLoadRemoteMetaData()) {
try {
logger.info("Calling Remote Init...");
remoteInit();
} catch (ExchangeException e) {
throw e;
} catch (IOException e) {
throw new ExchangeException(e);
}
}
}
@Override
public void remoteInit() throws IOException, ExchangeException {
logger.info(
"No remote initialization implemented for {}. The exchange meta data for this exchange is loaded from a json file containing hard-coded exchange meta-data. This may or may not be OK for you, and you should understand exactly how this works. Each exchange can either 1) rely on the hard-coded json file that comes packaged with XChange's jar, 2) provide your own override json file, 3) properly implement the `remoteInit()` method for the exchange (please submit a pull request so the whole community can benefit) or 4) a combination of hard-coded JSON and remote API calls. For more info see: https://github.com/timmolter/XChange/wiki/Design-Notes#exchange-metadata",
exchangeSpecification.getExchangeName());
}
protected void loadExchangeMetaData(InputStream is) {
exchangeMetaData = loadMetaData(is, ExchangeMetaData.class);
}
protected <T> T loadMetaData(InputStream is, Class<T> type) {
// Use Jackson to parse it
ObjectMapper mapper = new ObjectMapper();
try {
T result = mapper.readValue(is, type);
logger.debug(result.toString());
return result;
} catch (Exception e) {
logger.warn(
"An exception occured while loading the metadata file from the file system. This is just a warning and can be ignored, but it may lead to unexpected results, so it's better to address it.",
e);
return null;
}
}
@Override
public List<CurrencyPair> getExchangeSymbols() {
return new ArrayList<CurrencyPair>(getExchangeMetaData().getCurrencyPairs().keySet());
}
public String getMetaDataFileName(ExchangeSpecification exchangeSpecification) {
return exchangeSpecification.getExchangeName().toLowerCase().replace(" ", "").replace("-", "").replace(".", "");
}
@Override
public ExchangeSpecification getExchangeSpecification() {
return exchangeSpecification;
}
@Override
public ExchangeMetaData getExchangeMetaData() {
return exchangeMetaData;
}
public MarketDataService getMarketDataService() {
return marketDataService;
}
public TradeService getTradeService() {
return tradeService;
}
public AccountService getAccountService() {
return accountService;
}
@Override
public String toString() {
String name = exchangeSpecification != null ? exchangeSpecification.getExchangeName() : getClass().getName();
return name + "#" + hashCode();
}
}