package paramsim.paramicssimulator; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.StringReader; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; /** * A class which will read a FileReader stream, parsing it as an XML document, * and return a IncidentStatus object which contains the parsed information. * * @author Greg Eddington (geddingt@calpoly.edu) */ public class ParamicsIncidentReader { /** Error Log **/ private static Logger paramLogger = Logger.getLogger("paramsim.paramicssimulator"); /** A SAX Handler that is used to parse received Incident Status Node. **/ protected IncidentStatusHandler ish = null; /** The current networkId **/ private int networkId = 1; /** The Paramics Simulation Info for the most recent incident read **/ protected ParamicsSimulationInfo psi = null; /** Value (seconds since 1/1/1970) of input file's last modification time. */ protected long lastModified = 0; /** * Constructor. */ public ParamicsIncidentReader() { ish = new IncidentStatusHandler(); } /** * This method parses the received XML node with the local CameraStatusHandler. * All updated camera information is sent to the ParamicsSimulationManager. * * If a successful read of the file occurs, the file is written with an empty string * and the date of the last modification is stored. * * @param filename The file to check for message in. * @return A ParamicsSimulationInfo object containing the file's information * A null pointer on: * - The file does not exist * - No new modification * - An error opening file * - An empty file * - An error parsing the file * * The caller is able to call this function to check if there are any new messages * in the file. If there are, a PSI object is returned. If there aren't any new * messages, a null pointer is returned. */ public ParamicsSimulationInfo parse(String filename) { ParamicsSimulationInfo psi = null; File f = new File(filename); BufferedReader r = null; // File does not exist: No information if (!(f.exists())) { return null; } // File not modified: No new information if (f.lastModified() <= lastModified) { return null; } try { // Try to open the file r = new BufferedReader(new FileReader(f)); // Read the file to the end StringBuilder xml = new StringBuilder(""); String line = r.readLine(); while (line != null) { xml.append(line + "\n"); line = r.readLine(); } // If the file has contents in it, read them and returned a PSI describing the contents if(xml.length() > 0) { // Parse the file SAXParserFactory.newInstance().newSAXParser().parse(new InputSource(new StringReader(xml.toString())), ish); psi = new ParamicsSimulationInfo(networkId, xml.toString()); } else if (xml.length() == 0) { lastModified = modifyFile(f); r.close(); } } catch (FileNotFoundException fnfe) { paramLogger.logp(Level.SEVERE, "ParamicsIncidentReader", "parse", filename + " dissapeared before reading.", fnfe); psi = null; } catch (IOException ioe) { paramLogger.logp(Level.SEVERE, "ParamicsIncidentReader", "parse", "Error while reading file " + filename + ".", ioe); psi = null; } catch (SAXException saxe) { paramLogger.logp(Level.SEVERE, "ParamicsIncidentReader", "parse", "Error while parsing file " + filename + ".", saxe); psi = null; } catch (ParserConfigurationException pce) { paramLogger.logp(Level.SEVERE, "ParamicsIncidentReader", "parse", "Error while configuring parser.", pce); } // If a incident was read if (psi != null) { lastModified = modifyFile(f); try { r.close(); } catch (IOException e) { paramLogger.logp(Level.SEVERE, "ParamicsIncidentReader", "parse", "Error while closing file" + filename + ".", e); } } // Return no object if there was an error while reading, or the psi created from // parsing the file if the operation was successful. return psi; } private long modifyFile(File f) { FileWriter w = null; // Write to the file to show that it was read. try { w = new FileWriter(f); w.write(""); w.close(); } catch (IOException e) { paramLogger.logp(Level.SEVERE, "ParamicsIncidentReader", "parse", "Error while writing to file " + f.getName() + " to show that file was read.", e); } // Save the last modified time return f.lastModified(); } /** * Internal SAX Handler used to parse the Incident Status Document read by * the remote Status Reader. The schema for this document is:
* *
*
*
*
*
*
*
* * *
*
*
*
*
*
*

*
* * *
*
*
*
*
*
*
*
*

*
*
*
* ... *

*

* ... *
* * * * * * * * ... * * ... * * *
*/ protected class IncidentStatusHandler extends DefaultHandler { private final String NETWORK_ID = "Network_ID"; /** A buffer for reading characters **/ private StringBuffer parsedValue = new StringBuffer(); public void startDocument() { } /** Appends characters to the xmlMessage and parsedValue buffers **/ public void characters(char[] ch, int start, int length) { parsedValue.append(new String(ch, start, length).trim()); } public void startElement (String uri, String localName, String qName, Attributes attributes) throws SAXException { } public void endElement(String uri, String localName, String qName) { if(qName.equals(NETWORK_ID)) { networkId = Integer.parseInt(parsedValue.toString()); } parsedValue.setLength(0); } public void error(SAXParseException e) { paramLogger.logp(Level.SEVERE, "ParamicsIncidentReader", "error", "Error in parsing received incident status.", e); } public void fatalError(SAXParseException e) { paramLogger.logp(Level.SEVERE, "ParamicsIncidentReader", "fatalError", "Fatal error in parsing received incident status.", e); } public void warning(SAXParseException e) { paramLogger.logp(Level.WARNING, "ParamicsIncidentReader", "warning", "Warning in parsing received incident status.", e); } } }