package hu.ppke.itk.itkStock.client.historicData; import hu.ppke.itk.itkStock.client.watcherClient.SerializationTools; import hu.ppke.itk.itkStock.nio.protocol.ProtocolTools; import hu.ppke.itk.itkStock.nio.protocol.RecieveHistoricData; import hu.ppke.itk.itkStock.nio.core.NioClient; import hu.ppke.itk.itkStock.nio.core.RspHandler; import hu.ppke.itk.itkStock.server.db.historicData.StockData; import hu.ppke.itk.itkStock.server.db.historicData.StockDate; import hu.ppke.itk.itkStock.server.db.historicData.StockTime; import hu.ppke.itk.itkStock.server.db.historicData.Transaction; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; public class HistoricData { Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> memory; NioClient client; /** * There are 4 necessary step for using this class. First, we need the * Mapped stocks from the memory, as the first parameter of this class, and * secondly the client. For using this class we need to call the search * method, if it result with a null value, then we should call the server * thorugh requestFromServer. * * @param m * a map in the structure of the server.StockData.fecth * @param c * the NioClient */ HistoricData( Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> m, NioClient c) { memory = m; client = c; } /** * First it checks the memory, and after the archive file * * @param tickers * The ticker name of the stocks. * @param from * The start date of the request is StockDate format. * @param to * The end date * @return the necessary historical data, if it is null, than we should * request it from the server by {@link requestFromServer} * @throws ParseException * thrown if the date format is not yyyy-MM-dd */ public Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> search( String[] tickers, StockDate from, StockData to) throws ParseException { Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> result = new HashMap<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>>(); result = searchIn(memory, tickers, from, to); if (!result.isEmpty()) { return result; } try { result = searchIn(getArchive("archive"), tickers, from, to); } catch (IOException e) { // nem nagy kaland, �gyis lek�rj�k akkor a szervert�l } if (!result.isEmpty()) { return result; } return null; } /** * request the historical data form the server, and add a responsehandler * for the incoming datas, which will write the datas to the archive * * @param tickers * The ticker name of the stocks. * @param from * The start date of the request is StockDate format. * @param to * The end date * @throws IOException */ public void requestFromServer(String[] tickers, StockDate from, StockData to) throws IOException { StringBuilder msg = new StringBuilder(); msg.append((short) 301); msg.append("T("); for (String t : tickers) { msg.append(t); } msg.append(")S(").append(from.toString()).append(")E("); if (to == null) { msg.append("-)"); } else { msg.append(to.toString()).append(")"); } RspHandler rsp = new RspHandler(); ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); RecieveHistoricData reciever = new RecieveHistoricData(this); rsp.addProtocolCommandWorker(ProtocolTools.getHistoricalData, reciever); try { byteStream.write(ProtocolTools .shortToBytes(ProtocolTools.requestForHistoricalData)); byteStream.write(msg.toString().getBytes()); client.send(byteStream.toByteArray(), rsp); } catch (IOException e) { } rsp.waitForResponse(); } /** * This method looks up the map, and returns with just with the requested * data. * * @param in * The map where we should process. * @param tickers * The ticker name of the stocks. * @param from * The start date of the request is StockDate format. * @param to * The end date * @return Map with just the requested datas. * @throws ParseException * Thrown, if the time format is incorrect. */ private Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> searchIn( Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> in, String[] tickers, StockDate from, StockData to) throws ParseException { Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> result = new HashMap<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>>(); if (tickers == null || tickers.length < 1) { for (Map.Entry<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> entry : in .entrySet()) { String ticker = entry.getKey(); if (in.containsKey(ticker)) { SortedMap<StockDate, SortedMap<StockTime, Transaction>> depth1 = in .get(ticker); SortedMap<StockDate, SortedMap<StockTime, Transaction>> treeMap = new TreeMap<StockDate, SortedMap<StockTime, Transaction>>(); if (to == null) { if (depth1.containsKey(from)) { treeMap.put(from, depth1.get(from)); } } else { GregorianCalendar gcal = new GregorianCalendar(); SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd"); Date start = sdf.parse(from.toString()); Date end = sdf.parse(to.toString()); gcal.setTime(start); while (gcal.getTime().before(end)) { StockDate date = new StockDate((short) gcal .getTime().getYear(), (byte) gcal.getTime() .getMonth(), (byte) gcal.getTime().getDay()); if (depth1.containsKey(date)) { treeMap.put(date, depth1.get(date)); } gcal.add(Calendar.DAY_OF_WEEK, 1); } } } } } else { for (String ticker : tickers) { if (in.containsKey(ticker)) { SortedMap<StockDate, SortedMap<StockTime, Transaction>> depth1 = in .get(ticker); SortedMap<StockDate, SortedMap<StockTime, Transaction>> treeMap = new TreeMap<StockDate, SortedMap<StockTime, Transaction>>(); if (to == null) { if (depth1.containsKey(from)) { treeMap.put(from, depth1.get(from)); } } else { GregorianCalendar gcal = new GregorianCalendar(); SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd"); Date start = sdf.parse(from.toString()); Date end = sdf.parse(to.toString()); gcal.setTime(start); while (gcal.getTime().before(end)) { StockDate date = new StockDate((short) gcal .getTime().getYear(), (byte) gcal.getTime() .getMonth(), (byte) gcal.getTime().getDay()); if (depth1.containsKey(date)) { treeMap.put(date, depth1.get(date)); } gcal.add(Calendar.DAY_OF_WEEK, 1); } } } } } return result; } /** * @param filename * String. The name of the file, where the historic datas archive * are in a bytearray; * @return the map as in the StockData class * @throws IOException */ @SuppressWarnings("unchecked") private Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> getArchive( String filename) throws IOException { FileInputStream stream = null; byte[] bytearray = null; try { File file = new File(filename); stream = new FileInputStream(file); bytearray = new byte[(int) file.length()]; stream.read(bytearray); stream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (stream != null) { stream.close(); } } Object o = SerializationTools.bytesToObject(bytearray); return (Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>>) o; } /** * First, it puts all the datas[] to one big map, and the after a standard * serialization it writes everything to the "filename" file; * * @param datas * array of the maps, same as in the StockData class. * @param filename * String. The filename, where it should archive the datas. * @throws IOException */ private void makeArchive( ArrayList<Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>>> datas, String filename) throws IOException { Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> archive = new HashMap<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>>(); for (Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> map : datas) { archive.putAll(map); } byte[] bytearray = SerializationTools.objectToBytes(archive); FileOutputStream stream = null; try { stream = new FileOutputStream(filename); stream.write(bytearray); stream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (stream != null) { stream.close(); } } } public void addToArchive( Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>> data) { ArrayList<Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>>> list = new ArrayList<Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction>>>>(); list.add(memory); try { list.add(getArchive("archive")); } catch (IOException e) { e.printStackTrace(); } list.add(data); try { makeArchive(list, "archive"); } catch (IOException e) { e.printStackTrace(); } } }