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);
}
}
}