/* * Author: Balch * Created: 9/4/14 12:26 AM * * This file is part of MockTrade. * * MockTrade is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MockTrade is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MockTrade. If not, see <http://www.gnu.org/licenses/>. * * Copyright (C) 2014 */ package com.balch.mocktrade.finance; import android.content.Context; import android.util.Log; import com.android.volley.Request; import com.android.volley.toolbox.RequestFuture; import com.android.volley.toolbox.StringRequest; import com.balch.mocktrade.NetworkRequestProvider; import com.balch.mocktrade.settings.Settings; import org.json.JSONArray; import org.json.JSONException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; public class GoogleFinanceModel implements FinanceModel { private static final String TAG = GoogleFinanceModel.class.getSimpleName(); private final static String GOOGLE_BASE_URL = "http://www.google.com/finance/info?infotype=infoquoteall&q="; private final NetworkRequestProvider networkRequestProvider; private final FinanceManager mFinanceManager; public GoogleFinanceModel(Context context, NetworkRequestProvider networkRequestProvider, Settings settings) { this.networkRequestProvider = networkRequestProvider; this.mFinanceManager = new FinanceManager(context.getApplicationContext(), settings); } private String getGoogleQueryUrl(String symbols) throws UnsupportedEncodingException { return GOOGLE_BASE_URL + URLEncoder.encode(symbols, "UTF-8"); } @Override public Quote getQuote(final String symbol) { Map<String, Quote> quoteMap = getQuotes(Collections.singletonList(symbol)); return (quoteMap != null) ? quoteMap.get(symbol) : null; } @Override public Map<String, Quote> getQuotes(final List<String> symbols) { Set<String> uniqueSymbols = getUniqueSymbols(symbols); String symbolString = getDelimitedSymbols(uniqueSymbols); Map<String, Quote> quoteMap = null; try { final String url = getGoogleQueryUrl(symbolString); RequestFuture<String> future = RequestFuture.newFuture(); networkRequestProvider.addRequest(new StringRequest(Request.Method.GET, url, future, future)); String response = future.get(); response = response.trim(); if (response.startsWith("//")) { response = response.substring(2); } JSONArray jsonQuotes = new JSONArray(response); if (jsonQuotes.length() == uniqueSymbols.size()) { quoteMap = new HashMap<>(uniqueSymbols.size()); Iterator<String> symbolIterator = uniqueSymbols.iterator(); for (int x = 0; x < jsonQuotes.length(); x++) { try { Quote quote = GoogleQuote.fromJSONObject(jsonQuotes.getJSONObject(x)); // fix issue when returned symbol does not match, check LMT.WD quote.setSymbol(symbolIterator.next()); quoteMap.put(quote.getSymbol(), quote); } catch (Exception e) { Log.e(TAG, e.getMessage(), e); } } } else { Log.e(TAG, "Wrong number of quotes returned"); } } catch (JSONException | InterruptedException | ExecutionException | UnsupportedEncodingException ex) { Log.e(TAG, "GoogleFinanceModel.getQuotes exception", ex); quoteMap = null; } return quoteMap; } @Override public boolean isMarketOpen() { return mFinanceManager.isMarketOpen(); } @Override public Date nextMarketOpen() { return mFinanceManager.nextMarketOpen(); } @Override public boolean isInPollTime() { return mFinanceManager.isInPollTime(); } @Override public void setQuoteServiceAlarm() { mFinanceManager.setQuoteServiceAlarm(); } private Set<String> getUniqueSymbols(List<String> symbols) { Set<String> uniqueSymbols = new HashSet<>(symbols.size()); uniqueSymbols.addAll(symbols); return uniqueSymbols; } private String getDelimitedSymbols(Set<String> symbols) { StringBuilder builder = new StringBuilder(); boolean isFirst = true; for (String s : symbols) { if (!isFirst) { builder.append(","); } builder.append(s.toUpperCase()); isFirst = false; } return builder.toString(); } }