package tmcsim.paramicslog;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.rmi.Naming;
import java.util.Observable;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import tmcsim.common.SimulationException;
import tmcsim.interfaces.CoordinatorInterface;
import tmcsim.paramicslog.gui.ParamicsLogGUI;
/**
* Logs communication from ParamicsCommunicator to ParamicsSimulator.
*
* The system property "PARAMICS_LOG_CONFIG" should be set to the path where the
* properties file for this class is located.
* The data for the properties file follows.
*
* -----------------------------------------------------------------
* Log File The file to write the communication to. CAD Simulator Host The host
* that runs the CAD Simulator. CAD Simulator RMI Port The port on the host that
* runs the CAD Simulator where the RMI Coordinator object is registered to.
* -----------------------------------------------------------------
* Example File:
* LogFile=c:\\log.txt CADSimulatorHost=localhost CADSimulatorRMIPort=4445
* -----------------------------------------------------------------
*
*
* @author Nathaniel Lehrer
* @version
*/
public class ParamicsLog extends Observable
{
/**
* Enmeration containing property names.
*
* @author Nathaniel Lehrer
*/
private enum PROPERTIES
{
LOG_FILE("LogFile"),
CAD_SIM_HOST("CADSimulatorHost"),
CAD_SIM_PORT("CADSimulatorRMIPort");
public String name;
private PROPERTIES(String n)
{
name = n;
}
}
private static final String CONFIG_FILE_NAME = "logging_paramics_communicator.properties";
/**
* Error logger.
*/
private static Logger paramLogger = Logger.getLogger("tmcsim.paramicslog");
/**
* Static instance.
*/
private static ParamicsLog instance;
/**
* Properties object.
*/
private Properties paramicsLogProp;
/**
* File log entries are written to
*/
private File logFile;
/**
* Stores the log entries. This contains the same information logFile.
*/
private StringBuilder log;
/**
* Remote reference to the simulation
*/
private CoordinatorInterface theCoorInt;
/**
* Object for synchronizing IO
*/
Object lock;
/**
* Creates the singleton instance of this class.
*/
static
{
try
{
if (System.getProperty("CONFIG_DIR") == null)
{
System.setProperty("CONFIG_DIR", "config");
}
instance = new ParamicsLog(System.getProperty("CONFIG_DIR") + System.getProperty("file.separator") + CONFIG_FILE_NAME);
} catch (Exception e)
{
instance = new ParamicsLog();
paramLogger.logp(Level.WARNING, "ParamicsLog", "static initializer",
"Error occured initializing application", e);
JOptionPane.showMessageDialog(null, e.getMessage(),
"Error - ParamicsLog will not save log to file.",
JOptionPane.ERROR_MESSAGE);
}
instance.addObserver(ParamicsLogGUI.getInstance());
}
/**
* Creates an instance of ParamicsLog that does not write to a file when
* writeToLog is called.
*/
private ParamicsLog()
{
lock = new Object();
log = new StringBuilder("");
}
/**
* Creates an instance of ParamicsLog that writes to a file when writeToLog
* is called.
*
* @param propertiesFile
*/
private ParamicsLog(String propertiesFile)
{
this();
String logFile = null;
String CADSIMHost = null;
String CADSIMPort = null;
try
{
paramicsLogProp = new Properties();
paramicsLogProp.load(new FileInputStream(propertiesFile));
if ((logFile = paramicsLogProp.getProperty(PROPERTIES.LOG_FILE.name)) == null)
{
throw new Exception("Properties file missing log file location.");
}
else if ((CADSIMHost = paramicsLogProp.getProperty(PROPERTIES.CAD_SIM_HOST.name)) == null)
{
throw new Exception("Properties file missing CAD Simulator host.");
}
else if ((CADSIMPort = paramicsLogProp.getProperty(PROPERTIES.CAD_SIM_PORT.name)) == null)
{
throw new Exception("Properties file missing CAD Simulator RMI port.");
}
try
{
connect(CADSIMHost, CADSIMPort);
} catch (Exception e)
{
JOptionPane.showMessageDialog(null,
"ParamicsLog: Could not connect to remote Coordinator object.",
"Network Error", JOptionPane.ERROR_MESSAGE);
}
try
{
createLogFile(logFile);
} catch (Exception e)
{
JOptionPane.showMessageDialog(null,
"ParamicsLog: Could not create new log file.",
"File Error", JOptionPane.ERROR_MESSAGE);
}
} catch (Exception e)
{
paramLogger.logp(Level.WARNING, "ParamicsLog", "ParamicsLog constructor",
"Properties file incorrect or missing.", e);
JOptionPane.showMessageDialog(null,
"ParamicsLog: Properties file invalid.",
"Invalid Configuration", JOptionPane.ERROR_MESSAGE);
}
}
/**
* Creates the log file.
*
* @param filePath The path to the file including the file name.
* @throws IOException If the log file could not be created.
*/
private void createLogFile(String filePath) throws IOException
{
try
{
logFile = new File(filePath);
if (logFile.exists())
{
logFile.delete();
}
logFile.createNewFile();
} catch (Exception e)
{
logFile = null;
paramLogger.logp(Level.WARNING, "ParamicsLog", "ParamicsLog constructor",
"Could not create new log file.", e);
throw new IOException("Could not create log file.");
}
}
/**
* Connect to the Coordinator's RMI object.
*
* @param hostname Host name of the CAD Simulator.
* @param portNumber Port number of the CAD Simulator RMI communication.
* @throws SimulationException if there is an error creating the RMI
* connection.
*/
private void connect(String hostname, String portNumber)
throws SimulationException
{
String coorIntURL = "";
try
{
coorIntURL = "rmi://" + hostname + ":" + portNumber + "/coordinator";
theCoorInt = (CoordinatorInterface) Naming.lookup(coorIntURL);
} catch (Exception e)
{
paramLogger.logp(Level.WARNING, "ParamicsLog",
"establishRMIConnection", "Unable to establish RMI "
+ "communication with the CAD Simulator. URL <" + coorIntURL + ">", e);
}
}
/**
* Accessor to the entries in the log. No file IO is used.
*
* @return The entries in the log.
*/
public String getLog()
{
return log.toString();
}
/**
* Writes an entry to the log. The simulator time when the message was sent
* is prepended to the entry. Entries are padded by a blank line before and
* after them. TODO: Ensure output is written in order of request.
*
* @param entry
*/
public void writeToLog(String entry)
{
String time = "?";
String formattedEntry;
if (theCoorInt != null)
{
try
{
time = formatTime(theCoorInt.getCurrentSimulationTime());
} catch (Exception e)
{
paramLogger.logp(Level.WARNING, "ParamicsLog",
"RMICommunication", "Unable to communicate with RMI object", e);
}
}
formattedEntry = "\n" + "\n" + entry + "\n";
log.append(formattedEntry);
if (logFile != null)
{
try
{
synchronized (lock)
{
FileWriter writer = new FileWriter(logFile, true);
writer.append(formattedEntry);
writer.flush();
writer.close();
}
} catch (IOException e)
{
paramLogger.logp(Level.WARNING, "ParamicsLog", "writeToLog",
"Could not write to log file.", e);
}
}
setChanged();
notifyObservers(entry);
}
/**
* Formats the time given in seconds to hh:mm:ss format.
*
* @param time The time in seconds.
*/
public String formatTime(long time)
{
long seconds = time % 60;
long minutes = (time - seconds) / 60;
long hours = (time - seconds - minutes * 60) / 60;
return padr(hours) + ":" + padr(minutes) + ":" + padr(seconds);
}
private String padr(long n)
{
if (n < 10)
{
return "0" + n;
}
{
return "" + n;
}
}
/**
* Accessor for static instance of this class.
*
* @return The instance of this class.
*/
public static ParamicsLog getInstance()
{
return instance;
}
}