/***************************************************************************** * $Id: IOHandler.java,v 1.1.1.1 2000/03/29 22:58:14 kkeys Exp $ * * File: IOHandler.java Name: IOHandler * This should handle the IO for plankton. Including loading/saving * locally (only in stand alone) and remotely (both). In two * differnt formats. * * Modified:Jaeyeon Jung (2/13/98) * To load lat/long/city and stores them at DisplayObject object * * Animation Stuff * Should be able to download multi files and compress then into a * single list. Where each node and link has array of the values * for each file. * The first file is the base all other files are mapped on to it. * * The possble format for each line. The char should start each * line. * t number * (total number of nodes) * number - the number of nodes * there should be only one and it should be at the * end of the file. It tells you how many nodes there * are. Used to initailize the node array * T number * (total number of links) * number - the nubmer of links that will used * can't be less then the largest link index * d year month day * (date this file was created/last edited) * n node_index name (ip) [r] * (node) * node_index - the index of this node into the array * name - the name of the node * ip - the ip address * r - optional means it is a root node * N node_index name [r] * node_index - the index of this node into the array * name - the name of the node * r - optional means it is a root node * l link_index server client * (link) * link_index - the index of this link into an array * server - the index of the node that is the parent * client - the index of the node that is the child * L link_index n_index1 n_index2 * (link) * link_index - the index of this link into an array * n_index1 - the index of the node that is the parent * n_index2 - the index of the node that is the child * r node_index http icp * R link_index http icp * (node/link requests) * node_index/link_index - the index of this node/link * http - the number of http requests * icp - the number of icp requests * G node_index lat lon city * node_index - the index of this node * lat - the latitude * lon - the longitude * city - the city and country ****************************************************************************** ****************************************************************************** By accessing this software, IOHANDLER, you are duly informed of and agree to be bound by the conditions described below in this notice: This software product, IOHANDLER, is developed by Bradley Huffaker, and Jaeyeon Jung copyrighted(C) 1998 by the University of California, San Diego (UCSD), with all rights reserved. UCSD administers the NLANR Cache grants, NCR-9796082 and NCR-9616602, under which most of this code was developed. There is no charge for IOHANDLER software. You can redistribute it and/or modify it under the terms of the GNU General Public License, v. 2 dated June 1991 which is incorporated by reference herein. IOHANDLER is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use of it will not infringe on any third party's intellectual property rights. You should have received a copy of the GNU GPL along with the IOHANDLER program. Copies can also be obtained from http://www.gnu.org/copyleft/gpl.html or by writing to University of California, San Diego SDSC/CAIDA/NLANR 9500 Gilman Dr., MS-0505 La Jolla, CA 92093 - 0505 USA Or contact INFO@NLANR.NET *****************************************************************************/ package bhuffake.plankton; import java.awt.*; import java.io.*; import java.net.*; import java.util.Date; public class IOHandler extends Thread { // The type of formats final char TOTAL_NODES = 't'; final char TOTAL_LINKS = 'T'; final char NODE = 'n'; final char NODE_JUST_NAME = 'N'; final char NODE_ROOT = 'r'; final char LINK_ONE = 'l'; final char LINK_TWO = 'L'; final char DATE = 'd'; final char REQUEST_NODE = 'r'; final char REQUEST_LINK = 'R'; //jjung final char GEO = 'G'; boolean setGEO; // Holds the two kinds of formats // floating : the is not x,y for the nodes // fixed : the nodes have a fixed x,y static final public int FLOATING = 0; static final public int FIXED = 1; protected int format = FLOATING; // The location of where to store the file // Local : On the local file system // remote: On so file system across the web // will need to either talk to ftp or have a cgi script // for saving remotely static final public int LOCAL = 0; static final public int REMOTE = 1; protected int type = LOCAL; //jjung Map image Image image; // The nodes,links, and the main list Node[] nodes; int num_nodes = 0; Link[] links; int num_links= 0; DList list = new DList(); // The date of file if given. Date[] dates; // The parent for whom the files are loaded IOInterface parent; // The filename of the file to load String filename; String directory; String address; int linenum; // Checks to see if it is still loading boolean loading = false; boolean saving = false; // Used to select from the list of possible local files //FileDailog dialogbox = new FileDialog(this, "Select File"); // Max number of useful tokens in any given line protected final int MAX_NUM_TOKENS= 2; // Used to initial the node location int start_x = 10; int start_y = 10; // Used to tell one file from another //----------------------- Animation Stuff ------------------- boolean mutli_file_mode; // The current file loading int fileIndex = 0; // The list of urls to load (Applet) String[] urls; // The list of of directories and files (StandAlone) String[] dirs; String[] files; // The index mapping from one file to the next int[] node_mapping; int[] link_mapping; // The num_files that need to be loaded int num_files; public IOHandler(IOInterface parent_input) { super(); parent = parent_input; setGEO = false; } public void setStart(int x, int y) { start_x = x; start_y = y; } // Sets up all the needed state varialbes public void setUpLoad() { fileIndex = 0; num_nodes = 0; num_links = 0; } public void Load(String address_input) { //stop(); type = REMOTE; if (address_input == null) parent.FinishedLoading(list,setGEO,dates); urls = new String[1]; dates = new Date[1]; urls[0] = address_input; start(); } public void Load(String filename_input,String directory_input) { fileIndex = 0; num_nodes = 0; num_links = 0; //Stop(); type = LOCAL; files = new String[1]; dates = new Date[1]; files[0] = filename_input; dirs = new String[1]; dirs[0] = directory_input; loading = true; start(); } // Animatiom: requires the loading of multiple files public void Load(String[] urls_input) { type = REMOTE; urls = urls_input; dates = new Date[urls_input.length]; if (urls == null || urls.length < 1) parent.FinishedLoading(list,setGEO,dates); num_files = urls.length; start(); } public void Load(String[] files_input, String[] dirs_input) { type = LOCAL; dirs = dirs_input; if (dirs_input == null || files_input == null || dirs_input.length < 1 || dirs_input.length < files_input.length) parent.FinishedLoading(list,setGEO,dates); dirs = dirs_input; files = files_input; dates = new Date[files.length]; start(); } public void setGEO(boolean flag) { setGEO = flag; } public boolean isGEO() { return setGEO; } public void Stop() { if (loading) { loading = false; parent.FinishedLoading(list,setGEO,dates); } else if (saving) { saving = false; parent.FinishedSaving(); } super.stop(); } public void run() { fileIndex = 0; num_nodes = 0; num_links = 0; loading = true; if (type == LOCAL) num_files= files.length; else num_files = urls.length; while (fileIndex < num_files) { // Reseting mapping for a new file node_mapping = null; link_mapping = null; if (type == LOCAL) { filename = files[fileIndex]; directory = dirs[fileIndex]; } else address = urls[fileIndex]; try { linenum = 1; if (loading) StartLoading(); else if (saving) StartSaving(); } catch (IOException e1) { Error("IOHandler.run()",e1.toString()); Stop(); } fileIndex++; if (type == LOCAL) parent.printMessage("Loaded File:" +filename); else parent.printMessage("Loaded URL:" +address); } loading = false; parent.FinishedLoading(list,setGEO,dates); } public void StartLoading() throws IOException { // The buffer that holds the tokens string char[] buffer = new char[256]; // control flag that ends the loop boolean working = true; // the curent length of the string in buffer int current_length = 0; // The number of byte read into byte_buffer int length; byte[] byte_buffer = new byte[256]; // the input Stream InputStream is = getInputStream(); // A comment charater has been reached and the rest of the // the line should be ignored. boolean is_comment = false; if (is == null) { Error("IOHandler.StartLoading()","InputStream is null"); Stop(); } do { length = is.read(byte_buffer); if (length < 0) { length = 0; byte_buffer[length++] = '\n'; working = false; } for (int offset=0; offset < length; offset++) { if (current_length == buffer.length) { char[] temp = new char[(int)(buffer.length*1.1)]; for (int index=0; index < buffer.length; index++) temp[index] = buffer[index]; buffer = temp; } buffer[current_length] = (char) byte_buffer[offset]; if (buffer[current_length] == '\n') { ParseString(current_length,buffer); current_length= 0; linenum++; is_comment = false; } else if (buffer[current_length] == '#') is_comment = true; else if (!is_comment) current_length++; } } while (working); if (links != null) { for (int index=0; index < links.length;index++) if (links[index] != null) { list.enqueue(links[index]); } } if (nodes != null) { for (int index=0; index < nodes.length;index++) if (nodes[index] != null) { list.enqueue(nodes[index]); } } } // The tricky part of the following is mapping nodes/links with // diffrent indexs across files to the same node/link. So here is how it // will work. // Assume that the number of nodes that are in the first file // are the number it will use. So set the number of nodes equal to it. // Then assume map any new nodes you find to the index of that next node // when you run out of nodes grow the array. All mapping from the // file index to the local index will be handled by mapping. // Where the location in the int array is the mapping of the node. public void ParseString(int length, char[] buffer) { //System.err.println("ParesString["+filename+"]"+new String(buffer,0,length)); // checks for empty strings if (length <= 0) return; int node_index1; int node_index2; // Skip the first char it should be format int index = 2; char format = buffer[0]; while (index < length && buffer[index] >= '0' && buffer[index] <= '9') index++; if (index == 2) { Error("IOHandler.ParseString()", "node_index not found"); return; } node_index1 = Integer.parseInt(new String(buffer,2,index-2)); if (format == TOTAL_NODES) { if (node_mapping != null) { Error("IOHandler.ParseString()" , "A second nodes total was found"); return; } if (nodes == null) { nodes = new Node[node_index1]; num_nodes = node_index1; } // Grows the node array if it will not be // large enough even if all the nodes are repeats else if (nodes.length < node_index1) { Node[] temp = new Node[node_index1]; for(int i=0;i < num_nodes;i++) temp[i] = nodes[i]; nodes = temp; } node_mapping = new int[node_index1]; for(int y=0; y< node_index1; y++) node_mapping[y] = -1; list.clear(); return; } else if (format == TOTAL_LINKS) { if (link_mapping != null) { Error("IOHandler.ParseString()" , "A second links total was found"); return; } if (links == null) { links = new Link[node_index1]; num_links= node_index1; } // Grows the node array if it will not be // large enough even if all the nodes are repeats else if (links.length < node_index1) { Link[] temp = new Link[node_index1]; for(int i=0;i < num_links;i++) temp[i] = links[i]; links = temp; } link_mapping = new int[node_index1]; for(int x=0; x< node_index1; x++) link_mapping[index] = -1; return; } index++; if (format == NODE || format == NODE_JUST_NAME) { if (nodes==null) { Error("IOHandler.ParseString","Attempt"+ " access nodes with out a 't ##' line."); return; } if (node_index1 >= node_mapping.length) { Error("IOHandler.PraseString()" ,"Node index '" + node_index1 +"'" + " is greater then size "+ nodes.length); return; } if (node_mapping[node_index1] >= 0) { Error("IOHandler.PraseString()", "That node is already is use for this file."); return; } int start = index; while (index < length && buffer[index] != ' ') index++; if (format == NODE) while (index < length && buffer[index] != ')' && buffer[index] != ' ') index++; if (buffer[index] != ' ' && index < length) index++; String name = new String(buffer,start,index-start); //index++; boolean is_root = false; // This captures any special sysmbols while (index < length) { switch (buffer[index]) { case NODE_ROOT: is_root = true; } index++; } int map = 0; Node node = null; boolean notFound = true; if (fileIndex > 0) while (map < nodes.length && notFound) { node = nodes[map]; if (node != null && node.name.equals(name)) notFound = false; else map++; } if (notFound) { node = new Node(name,start_x,start_y, fileIndex,num_files); if (nodes[node_index1] == null) { nodes[node_index1] = node; map = node_index1; } else { if (num_nodes == nodes.length) { Node[] temp = new Node[(int)( nodes.length*1.1)]; for(int x=0;x < nodes.length;x++) temp[x] = nodes[x]; nodes = temp; } nodes[num_nodes] = node; map = num_nodes; num_nodes++; } } else { node.setExists(fileIndex); } node_mapping[node_index1] = map; if (is_root) { node.setRoot(true); } } else if (format == LINK_ONE || format == LINK_TWO) { if (links == null) { Error("IOHandler.ParseString()", "Attempt to create link before 'T #'"); return; } int start = index; while (index < length && buffer[index] >= '0' && buffer[index] <= '9') index++; int link_index = node_index1; node_index1 = Integer.parseInt(new String(buffer,start,index-start)); if (link_index >= links.length) { Error("IOHandler.PraseString()" ,"Link index '" + link_index+"'" + " is greater then size "+ links.length); return; } start = ++index; while (index < length && buffer[index] >= '0' && buffer[index] <= '9') index++; if (index == start) { Error("IOHandler.ParseString()" , "There is no second node index"); return; } node_index2 = Integer.parseInt(new String(buffer,start,index-start)); if (node_index1 >= node_mapping.length) { Error("IOHandler.PraseString()" ,"Node index '" + node_index1 +"'" + " is greater then size "+ node_mapping.length); return; } else if (node_mapping[node_index1] < 0) { Error("IOHandler.PraseString()" ,"Undefined node:" + node_index1); return; } else if (node_index2 >= node_mapping.length) { Error("IOHandler.PraseString()" ,"Node index '" + node_index2 +"'" + " is greater then size "+ node_mapping.length); return; } else if (node_mapping[node_index2] < 0) { Error("IOHandler.PraseString()" ,"Undefined node:" + node_index2); return; } Node client = nodes[node_mapping[node_index1]]; Node server = nodes[node_mapping[node_index2]]; int type = Link.ONE; if (format == LINK_TWO) type = Link.TWO; Link link = null; int map = 0; boolean notFound = true; if (fileIndex > 0) while(map < links.length && notFound) { link = links[map]; if (link != null && link.equals(server,client)) notFound = false; else map++; } if (notFound) { link = new Link(server,client,type,fileIndex ,num_files); if (links[link_index] == null) { links[link_index] = link; map = link_index; } else { if (links.length == num_links) { Link[] temp = new Link[(int)( links.length*1.1)]; for(int x=0;x < links.length;x++) temp[x] = links[x]; links= temp; } links[num_links] = link; map = num_links; num_links++; } } else link.setExists(fileIndex); link_mapping[link_index] = map; } else if (format == DATE) { int start = index; while (index < length && buffer[index] >= '0' && buffer[index] <= '9') index++; int month = Integer.parseInt(new String(buffer,start,index-start)); start = ++index; while (index < length && buffer[index] >= '0' && buffer[index] <= '9') index++; int day = Integer.parseInt(new String(buffer,start,index-start)); if (dates[fileIndex] != null) { Error("IOHandler.ParseString()", "Secound date found."); return; } dates[fileIndex] = new Date(node_index1-1900,month,day); } else if (format == REQUEST_NODE || format == REQUEST_LINK) { int start = index; while (index < length && buffer[index] >= '0' && buffer[index] <= '9') index++; if (start == index) { Error("IOHandler.ParseString()", "Error parseing HTTP request number"); return; } int http = Integer.parseInt(new String(buffer,start,index-start)); start = ++index; while (index < length && buffer[index] >= '0' && buffer[index] <= '9') index++; if (start == index) { Error("IOHandler.ParseString()", "Error parseing ICP request number"); return; } int icp = Integer.parseInt(new String(buffer,start,index-start)); DisplayObject object = null; String type = ""; if (format == REQUEST_NODE) { type = "node"; if (node_index1 < node_mapping.length && node_mapping[node_index1] >= 0) { object = nodes[node_mapping[node_index1]]; } } else { type = "link"; if (node_index1 < link_mapping.length && link_mapping[node_index1] >= 0) { object = links[link_mapping[node_index1]]; } } if (object == null) { Error("IOHandler.ParseString()", "Undefined "+type+" ["+node_index1+"]"); return; } object.setRequest(http,icp,fileIndex); } //jjung else if (format == GEO) { setGEO(true); int start = index; while (index < length && (buffer[index] >= '0' && buffer[index] <= '9' || buffer[index] == '.' || buffer[index] == '-')) index++; if (start == index) { //not found return; } String temp = new String(buffer,start,index-start); double lat = GetDouble(temp,"Latitude"); start = ++index; while (index < length && (buffer[index] >= '0' && buffer[index] <= '9' || buffer[index] == '.' || buffer[index] == '-')) index++; if (start == index) { Error("IOHandler.ParseString()", "Error parsing longtude request number"); return; } temp = new String(buffer,start,index-start); double lon = GetDouble(temp,"Longitude"); start = ++index; while (index < length && buffer[index] != '\n') index++; if (start == index) { Error("IOHandler.ParseString()", "Error parseing longtude request number"); return; } String city = new String(buffer,start,index-start); DisplayObject object = null; if (node_index1 < node_mapping.length && node_mapping[node_index1] >= 0) { object = nodes[node_mapping[node_index1]]; } if (object == null) { Error("IOHandler.ParseString()", "Undefined "+type+" ["+node_index1+"]"); return; } //System.err.println(lat +" " + lon + " " +city); object.setGeo(lat,lon,city); } //jjung else Error("IOHandler.ParseString()","Unknow formate '" + format +"'"); } public InputStream getInputStream() { InputStream is = null; if (type == LOCAL) { /************************************** dailogbox.show(); filename = dialogbox.getFile(); **************************************/ try { File file = new File(directory, filename); if (!file.canRead()) Error("IOHandler.getInputStream()", "can't read file"); is = new FileInputStream(file); } catch (FileNotFoundException e1) { Error("IOHandler.getInputStream()", e1.toString()); Stop(); } } else { try { URL url = new URL(address); is = url.openStream(); } catch (MalformedURLException e0) { Error("IOHandler.getInputSteam()",e0.toString()); } catch (IOException e1) { Error("IOHandler.getInputSteam()",e1.toString()); } } return is; } public void StartSaving() {} public void Error(String where, String msg) { String source; if (type == LOCAL) source = directory + "/" + filename; else source = address; System.err.println("FILE ERROR<"+where+"> [" + linenum +"]" + source + "\n --->" + msg); if (type == LOCAL) source = filename; parent.printMessage("FILE ERROR ["+linenum +"]" +source + "::" +msg); } //jjung protected double GetDouble(String value,String msg) { try { return Double.valueOf(value).doubleValue(); } catch (NumberFormatException e) { System.err.println(" Data file `" + address + "' is curroputed\n" + ": "+msg+ ":"+ e.toString()+"\n"); } return 0; } }