/* * Licensed Materials - Property of Perforce Software, Inc. * © Copyright Perforce Software, Inc. 2014, 2021 * © Copyright IBM Corp. 2009, 2014 * © Copyright ILOG 1996, 2009 * All Rights Reserved. * * Note to U.S. Government Users Restricted Rights: * The Software and Documentation were developed at private expense and * are "Commercial Items" as that term is defined at 48 CFR 2.101, * consisting of "Commercial Computer Software" and * "Commercial Computer Software Documentation", as such terms are * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4, * as applicable. */ package shared; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StreamTokenizer; import java.net.MalformedURLException; import java.net.URL; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.zip.DataFormatException; import ilog.views.chart.data.IlvDataReader; import ilog.views.chart.data.IlvDataSet; import ilog.views.chart.data.IlvDefaultDataSet; import ilog.views.chart.util.IlvDoubleArray; /** * A reader that reads quote values in CSV format. */ public class CSVDataReader implements IlvDataReader { private boolean reverse; static class Properties { String dataFile; String dateFomat; boolean transposed; } /** * Initializes a new reader. */ public CSVDataReader() { this(false); } /** * Initializes a new reader, specifying whether the read values should be * reversed. */ public CSVDataReader(boolean reverse) { this.reverse = reverse; } static int QUOTE_CHAR = '"'; private StreamTokenizer createTokenizer(Reader reader) { StreamTokenizer st = new StreamTokenizer(reader); st.quoteChar(QUOTE_CHAR); st.ordinaryChar(','); st.wordChars('-', '-'); st.eolIsSignificant(true); st.whitespaceChars(0, 32); return st; } /** * Returns a <code>Reader</code> object on the specified * <code>InputStream</code>. */ protected Reader makeReader(InputStream in) throws MalformedURLException, IOException { Reader res = new InputStreamReader(in); if (!(in instanceof BufferedInputStream)) res = new BufferedReader(res); return res; } /** * Loads data from the given <code>InputStream</code>. * * @return An array containing the data sets. * @throws ParseException * Parsing a date failed. * @throws NumberFormatException * Parsing a date failed. * @throws DataFormatException * The file is not a valid Yahoo CSV format; this exception is * thrown when a line is being parsed and something other than a * number has been read. * @throws IOException * Opening (in the case of a URL) or reading the input stream * failed. */ Override public IlvDataSet[] read(InputStream in) throws ParseException, NumberFormatException, DataFormatException, IOException { Reader reader = makeReader(in); StreamTokenizer st = createTokenizer(reader); boolean xDateSeries = false; List<String> seriesNames = readColumnHeaders(st); IlvDoubleArray[] values = new IlvDoubleArray[seriesNames.size()]; int seriesCount = values.length; for (int i = 0; i < seriesCount; ++i) { values[i] = new IlvDoubleArray(); } int i = 0; // == Recover the date. xDateSeries = true; DateFormat dateFormat = new SimpleDateFormat("dd-MMMM-yy", Locale.ENGLISH); Date date, minDate = new Date(0), maxDate = new Date(Long.MAX_VALUE); List<Date> dates = new ArrayList<Date>(); // Skip column names. int tok = st.nextToken(); StringBuffer dateBuffer = new StringBuffer(); while (tok != StreamTokenizer.TT_EOF) { if (tok == ',') { ++i; } else if (tok == StreamTokenizer.TT_EOL) { i = 0; } else { if ((i == 0) && xDateSeries) { if (tok == StreamTokenizer.TT_NUMBER) { dateBuffer.append(Integer.toString((int) st.nval)); dateBuffer.append("-"); } else if (tok == StreamTokenizer.TT_WORD) { dateBuffer.append(st.sval); } if (dateBuffer.length() > 3) { date = dateFormat.parse(dateBuffer.toString()); dates.add(date); values[0].add(date.getTime()); if (date.before(minDate)) minDate = date; else if (date.after(maxDate)) maxDate = date; dateBuffer.delete(0, 9); } } else if (tok == StreamTokenizer.TT_NUMBER) { values[i].add(st.nval); } else throw new DataFormatException("Expected number at line " + st.lineno()); } tok = st.nextToken(); } String[] names = new String[seriesCount - 1]; double[][] data = new double[seriesCount][]; for (int j = 0; j < seriesCount; ++j) { if (this.reverse) values[j].reverse(); values[j].trim(); data[j] = values[j].data(); if (j > 0) names[j - 1] = seriesNames.get(j); } return IlvDefaultDataSet.create(data, 0, names, null); } /** * Loads data from the given URL. */ Override public IlvDataSet[] read(String url) throws ParseException, NumberFormatException, DataFormatException, IOException { InputStream in = new BufferedInputStream(new URL(url).openStream()); IlvDataSet[] dataSets = read(in); in.close(); return dataSets; } private List<String> readColumnHeaders(StreamTokenizer st) throws IOException, DataFormatException { List<String> names = new ArrayList<String>(); while (st.nextToken() != StreamTokenizer.TT_EOL) { if (st.ttype == StreamTokenizer.TT_WORD) { names.add(st.sval); if (st.nextToken() == StreamTokenizer.TT_EOL) break; } else throw new DataFormatException("Expected word at line : " + st.lineno()); } return names; } }