| 1 | package paramsim.paramicssimulator; |
|---|
| 2 | |
|---|
| 3 | import java.awt.event.WindowEvent; |
|---|
| 4 | import java.awt.event.WindowListener; |
|---|
| 5 | import java.io.File; |
|---|
| 6 | import java.io.FileInputStream; |
|---|
| 7 | import java.io.FileWriter; |
|---|
| 8 | import java.io.IOException; |
|---|
| 9 | import java.util.ArrayList; |
|---|
| 10 | import java.util.List; |
|---|
| 11 | import java.util.Observable; |
|---|
| 12 | import java.util.Properties; |
|---|
| 13 | import java.util.logging.Level; |
|---|
| 14 | import java.util.logging.Logger; |
|---|
| 15 | |
|---|
| 16 | import javax.swing.JOptionPane; |
|---|
| 17 | |
|---|
| 18 | import paramsim.paramicssimulator.ParamicsSimulatorLogMessage.PARAMICS_SIMULATOR_LOG; |
|---|
| 19 | import paramsim.paramicssimulator.gui.ParamicsSimulatorGUI; |
|---|
| 20 | |
|---|
| 21 | /** |
|---|
| 22 | * ParamicsSimulator is the main class for this module. The ParamicsSimulator |
|---|
| 23 | * can be used to simulate the Paramics device.<br><br> |
|---|
| 24 | * The properties file for the ParamicsCommunicator class contains the following data.<br> |
|---|
| 25 | * <code> |
|---|
| 26 | * -----------------------------------------------------------------------------<br> |
|---|
| 27 | * WorkingDirectory The working directory of the Paramics Communicator<br> |
|---|
| 28 | * ParamicsStatusLog The Paramics status log file <br> |
|---|
| 29 | * CameraStatusLog The camera status log file <br> |
|---|
| 30 | * ExchangeLog The exchange log file <br> |
|---|
| 31 | * CameraControlConfig The camera control file which maps the camera information <br> |
|---|
| 32 | * DVDPlayersConfig The DVD Players XML file which contains camera information <br> |
|---|
| 33 | * -----------------------------------------------------------------------------<br> |
|---|
| 34 | * Example File: <br> |
|---|
| 35 | * WorkingDirectory = c:/paramics/out <br> |
|---|
| 36 | * ParamicsStatusLog = paramics_status.log <br> |
|---|
| 37 | * CameraStatusLog = camera_status.log <br> |
|---|
| 38 | * IncidentLog = exchange.log <br> |
|---|
| 39 | * CameraControlConfig = camera_control.txt |
|---|
| 40 | * DVDPlayersConfig = dvdplayers.xml |
|---|
| 41 | * -----------------------------------------------------------------------------<br> |
|---|
| 42 | * </code> |
|---|
| 43 | * |
|---|
| 44 | * @author Greg Eddington (geddingt@calpoly.edu) |
|---|
| 45 | */ |
|---|
| 46 | public class ParamicsSimulator extends Observable implements Runnable |
|---|
| 47 | { |
|---|
| 48 | /** Error Log **/ |
|---|
| 49 | private static Logger paramLogger = Logger.getLogger("paramsim.paramicssimulator"); |
|---|
| 50 | |
|---|
| 51 | /** Incident file **/ |
|---|
| 52 | private static final String INCIDENT_FILE = "exchange.xml"; |
|---|
| 53 | |
|---|
| 54 | /** Paramics Status file **/ |
|---|
| 55 | private static final String PARAM_STATUS_FILE = "paramics_status.xml"; |
|---|
| 56 | |
|---|
| 57 | /** Camera Status file **/ |
|---|
| 58 | private static final String CAMERA_STATUS_FILE = "camera_status.xml"; |
|---|
| 59 | |
|---|
| 60 | /** Sleep Time (10 seconds) **/ |
|---|
| 61 | private static final int SLEEP_TIME = 10000; |
|---|
| 62 | |
|---|
| 63 | /** |
|---|
| 64 | * Enumeration containing property names. |
|---|
| 65 | * @author Greg Eddington |
|---|
| 66 | */ |
|---|
| 67 | private static enum PROPERTIES |
|---|
| 68 | { |
|---|
| 69 | /** The working directory for Paramics **/ |
|---|
| 70 | WORKING_DIR ("WorkingDirectory"), |
|---|
| 71 | |
|---|
| 72 | /** The Paramics log **/ |
|---|
| 73 | PARAM_STATUS_LOG ("ParamicsStatusLog"), |
|---|
| 74 | |
|---|
| 75 | /** The camera status log **/ |
|---|
| 76 | CAMERA_STATUS_LOG ("CameraStatusLog"), |
|---|
| 77 | |
|---|
| 78 | /** The exchange log **/ |
|---|
| 79 | INCIDENT_LOG ("IncidentLog"), |
|---|
| 80 | |
|---|
| 81 | /** The camera control file **/ |
|---|
| 82 | CAMERA_CONTROL ("CameraControlConfig"), |
|---|
| 83 | |
|---|
| 84 | /** The still images XML file **/ |
|---|
| 85 | DVD_PLAYERS ("DVDPlayersConfig"); |
|---|
| 86 | |
|---|
| 87 | public String name; |
|---|
| 88 | |
|---|
| 89 | private PROPERTIES(String n) |
|---|
| 90 | { |
|---|
| 91 | name = n; |
|---|
| 92 | } |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | /** |
|---|
| 96 | * Enumeration of network statuses. |
|---|
| 97 | * @author Greg Eddington |
|---|
| 98 | **/ |
|---|
| 99 | public static enum NETWORK_STATUS |
|---|
| 100 | { |
|---|
| 101 | LOADING ("LOADING"), |
|---|
| 102 | WARMING ("WARMING"), |
|---|
| 103 | LOADED ("LOADED"), |
|---|
| 104 | UNKNOWN ("UNKNOWN"); |
|---|
| 105 | |
|---|
| 106 | public String message; |
|---|
| 107 | |
|---|
| 108 | private NETWORK_STATUS(String n) |
|---|
| 109 | { |
|---|
| 110 | message = n; |
|---|
| 111 | } |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | /** Properties object. */ |
|---|
| 115 | private Properties paramicsSimProp = null; |
|---|
| 116 | |
|---|
| 117 | /** Working Directory **/ |
|---|
| 118 | private String workingDirectory = null; |
|---|
| 119 | |
|---|
| 120 | /** Incidents File **/ |
|---|
| 121 | private String incidentFile = null; |
|---|
| 122 | |
|---|
| 123 | /** Paramics Status File **/ |
|---|
| 124 | private String paramStatusFile = null; |
|---|
| 125 | |
|---|
| 126 | /** Camera Status File **/ |
|---|
| 127 | private String cameraStatusFile = null; |
|---|
| 128 | |
|---|
| 129 | /** Incidents Log **/ |
|---|
| 130 | private String incidentLog = null; |
|---|
| 131 | |
|---|
| 132 | /** Paramics Status Log **/ |
|---|
| 133 | private String paramStatusLog = null; |
|---|
| 134 | |
|---|
| 135 | /** Camera Status Log **/ |
|---|
| 136 | private String cameraStatusLog = null; |
|---|
| 137 | |
|---|
| 138 | /** Incident Reader **/ |
|---|
| 139 | private ParamicsIncidentReader incidentReader = null; |
|---|
| 140 | |
|---|
| 141 | /** The paramics simulator GUI **/ |
|---|
| 142 | private ParamicsSimulatorGUI theGUI; |
|---|
| 143 | |
|---|
| 144 | /** The network ID **/ |
|---|
| 145 | private int networkId = 1; |
|---|
| 146 | |
|---|
| 147 | /** Simulation Cameras **/ |
|---|
| 148 | private List<SimulationCamera> cameras; |
|---|
| 149 | |
|---|
| 150 | /** |
|---|
| 151 | * Creates a ParamicsSimulator object with properties defined in the propertiesFile |
|---|
| 152 | * parameter. It will initialize all file locations. |
|---|
| 153 | */ |
|---|
| 154 | public ParamicsSimulator(String propertiesFile) |
|---|
| 155 | { |
|---|
| 156 | try |
|---|
| 157 | { |
|---|
| 158 | paramicsSimProp = new Properties(); |
|---|
| 159 | paramicsSimProp.load(new FileInputStream(propertiesFile)); |
|---|
| 160 | |
|---|
| 161 | /** Check property file **/ |
|---|
| 162 | for (PROPERTIES property : PROPERTIES.values()) |
|---|
| 163 | { |
|---|
| 164 | if (paramicsSimProp.getProperty(property.name) == null || |
|---|
| 165 | paramicsSimProp.getProperty(property.name).length() == 0) |
|---|
| 166 | { |
|---|
| 167 | System.err.println("Invalid Configuration: Properties file missing " + |
|---|
| 168 | property.name + " property."); |
|---|
| 169 | System.exit(0); |
|---|
| 170 | } |
|---|
| 171 | } |
|---|
| 172 | |
|---|
| 173 | // Directory |
|---|
| 174 | workingDirectory = paramicsSimProp.getProperty(PROPERTIES.WORKING_DIR.name).trim(); |
|---|
| 175 | boolean endsWithSlash = workingDirectory.charAt(workingDirectory.length()-1) == '/' || |
|---|
| 176 | workingDirectory.charAt(workingDirectory.length()-1) == '\\'; |
|---|
| 177 | |
|---|
| 178 | // Files |
|---|
| 179 | paramStatusFile = workingDirectory + (endsWithSlash ? "" : "/") + PARAM_STATUS_FILE; |
|---|
| 180 | cameraStatusFile = workingDirectory + (endsWithSlash ? "" : "/") + CAMERA_STATUS_FILE; |
|---|
| 181 | incidentFile = workingDirectory + (endsWithSlash ? "" : "/") + INCIDENT_FILE; |
|---|
| 182 | |
|---|
| 183 | // Logs |
|---|
| 184 | incidentLog = paramicsSimProp.getProperty(PROPERTIES.INCIDENT_LOG.name).trim(); |
|---|
| 185 | paramStatusLog = paramicsSimProp.getProperty(PROPERTIES.PARAM_STATUS_LOG.name).trim(); |
|---|
| 186 | cameraStatusLog = paramicsSimProp.getProperty(PROPERTIES.CAMERA_STATUS_LOG.name).trim(); |
|---|
| 187 | |
|---|
| 188 | // Delete any old logs |
|---|
| 189 | File ilFile = new File(incidentLog); |
|---|
| 190 | File pslFile = new File(paramStatusLog); |
|---|
| 191 | File cslFile = new File(cameraStatusLog); |
|---|
| 192 | ilFile.delete(); |
|---|
| 193 | pslFile.delete(); |
|---|
| 194 | cslFile.delete(); |
|---|
| 195 | |
|---|
| 196 | // Cameras |
|---|
| 197 | String cameraConfig = paramicsSimProp.getProperty(PROPERTIES.CAMERA_CONTROL.name).trim(); |
|---|
| 198 | String stillImages = paramicsSimProp.getProperty(PROPERTIES.DVD_PLAYERS.name).trim(); |
|---|
| 199 | try |
|---|
| 200 | { |
|---|
| 201 | // Load the cameras |
|---|
| 202 | cameras = CameraParser.loadCameras(stillImages, cameraConfig); |
|---|
| 203 | } |
|---|
| 204 | catch (IOException e) |
|---|
| 205 | { |
|---|
| 206 | // Create an empty camera array |
|---|
| 207 | cameras = new ArrayList<SimulationCamera>(); |
|---|
| 208 | |
|---|
| 209 | // Log Error |
|---|
| 210 | paramLogger.logp(Level.SEVERE, "ParamicsSimulator", "Constructor", |
|---|
| 211 | "Error loading camera config from files \"" + stillImages + |
|---|
| 212 | "\" and \"" + cameraConfig + "\".", e); |
|---|
| 213 | } |
|---|
| 214 | |
|---|
| 215 | // Initialize GUI |
|---|
| 216 | theGUI = new ParamicsSimulatorGUI(this); |
|---|
| 217 | addObserver(theGUI); |
|---|
| 218 | theGUI.addWindowListener |
|---|
| 219 | ( |
|---|
| 220 | new WindowListener() |
|---|
| 221 | { |
|---|
| 222 | public void windowActivated(WindowEvent arg0) {}; |
|---|
| 223 | public void windowClosed(WindowEvent arg0) {}; |
|---|
| 224 | public void windowClosing(WindowEvent arg0) { System.exit(0); }; |
|---|
| 225 | public void windowDeactivated(WindowEvent arg0) {}; |
|---|
| 226 | public void windowDeiconified(WindowEvent arg0) {}; |
|---|
| 227 | public void windowIconified(WindowEvent arg0) {}; |
|---|
| 228 | public void windowOpened(WindowEvent arg0) {}; |
|---|
| 229 | } |
|---|
| 230 | ); |
|---|
| 231 | |
|---|
| 232 | // Write an initial packets |
|---|
| 233 | writeParamicsStatus(NETWORK_STATUS.LOADING); |
|---|
| 234 | writeCameraStatus(cameras); |
|---|
| 235 | } |
|---|
| 236 | catch (Exception e) |
|---|
| 237 | { |
|---|
| 238 | paramLogger.logp(Level.SEVERE, "ParamicsSimulator", "Constructor", |
|---|
| 239 | "Exception in reading properties file.", e); |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | incidentReader = new ParamicsIncidentReader(); |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | /** |
|---|
| 246 | * Appends a message to a log file. |
|---|
| 247 | * @param logName The name of the log file. |
|---|
| 248 | * @param message The message to append. |
|---|
| 249 | */ |
|---|
| 250 | private void writeToLog(String logName, String message) |
|---|
| 251 | { |
|---|
| 252 | try |
|---|
| 253 | { |
|---|
| 254 | FileWriter w = new FileWriter(logName, true); |
|---|
| 255 | w.write(message + "\n\n"); |
|---|
| 256 | w.close(); |
|---|
| 257 | } |
|---|
| 258 | catch (IOException e) |
|---|
| 259 | { |
|---|
| 260 | paramLogger.logp(Level.WARNING, "ParamicsSimulator", "writeToLog", |
|---|
| 261 | "Error writing to file " + logName + ".", e); |
|---|
| 262 | } |
|---|
| 263 | } |
|---|
| 264 | |
|---|
| 265 | /** |
|---|
| 266 | * Runs the Paramics simulator thread. |
|---|
| 267 | */ |
|---|
| 268 | public void run() |
|---|
| 269 | { |
|---|
| 270 | // Check for packets and update the simulator |
|---|
| 271 | for(;;) |
|---|
| 272 | { |
|---|
| 273 | // Flush the input file |
|---|
| 274 | ParamicsSimulationInfo psi = incidentReader.parse(incidentFile); |
|---|
| 275 | |
|---|
| 276 | // Update the network ID if a packet is received |
|---|
| 277 | if (psi != null) |
|---|
| 278 | { |
|---|
| 279 | networkId = psi.networkId; |
|---|
| 280 | writeToLog(incidentLog, psi.xmlMessage); |
|---|
| 281 | setChanged(); |
|---|
| 282 | notifyObservers(new ParamicsSimulatorLogMessage(PARAMICS_SIMULATOR_LOG.EXCHANGE, psi.xmlMessage)); |
|---|
| 283 | } |
|---|
| 284 | |
|---|
| 285 | // Write camera status |
|---|
| 286 | writeCameraStatus(cameras); |
|---|
| 287 | |
|---|
| 288 | // Sleep |
|---|
| 289 | try |
|---|
| 290 | { |
|---|
| 291 | Thread.sleep(SLEEP_TIME); |
|---|
| 292 | } |
|---|
| 293 | catch (InterruptedException ie) {} |
|---|
| 294 | } |
|---|
| 295 | } |
|---|
| 296 | |
|---|
| 297 | /** |
|---|
| 298 | * Writes the camera status to the camera status XML file read by the Paramics Communicator, |
|---|
| 299 | * as well as to the camera status log file. All observers are notified with the new status, |
|---|
| 300 | * so they can also log it. |
|---|
| 301 | * |
|---|
| 302 | * @param id Camera ID |
|---|
| 303 | * @param route Route |
|---|
| 304 | * @param direction The direction of traffic |
|---|
| 305 | * @param postmile The postmile |
|---|
| 306 | * @param averageSpeedNE The average speed North or East |
|---|
| 307 | * @param averageSpeedSW The average speed South or West |
|---|
| 308 | */ |
|---|
| 309 | public void writeCameraStatus(List<SimulationCamera> cameras) |
|---|
| 310 | { |
|---|
| 311 | StringBuilder message = new StringBuilder("<Camera_Status>\n"); |
|---|
| 312 | for (SimulationCamera camera : cameras) |
|---|
| 313 | { |
|---|
| 314 | message.append |
|---|
| 315 | ( |
|---|
| 316 | " <Camera>\n" + |
|---|
| 317 | " <Identifier>" + camera.id + "</Identifier>\n" + |
|---|
| 318 | " <Route>" + camera.route + "</Route>\n" + |
|---|
| 319 | " <Direction>" + camera.direction.xml + "</Direction>\n" + |
|---|
| 320 | " <Postmile>" + camera.postmile + "</Postmile>\n" + |
|---|
| 321 | " <Ave_Speed_NE>" + camera.averageSpeedNE + "</Ave_Speed_NE>\n" + |
|---|
| 322 | " <Ave_Speed_SW>" + camera.averageSpeedSW + "</Ave_Speed_SW>\n" + |
|---|
| 323 | " </Camera>\n" |
|---|
| 324 | ); |
|---|
| 325 | } |
|---|
| 326 | message.append("</Camera_Status>"); |
|---|
| 327 | |
|---|
| 328 | try |
|---|
| 329 | { |
|---|
| 330 | FileWriter w = new FileWriter(cameraStatusFile); |
|---|
| 331 | w.write(message.toString()); |
|---|
| 332 | w.close(); |
|---|
| 333 | } |
|---|
| 334 | catch (IOException e) |
|---|
| 335 | { |
|---|
| 336 | paramLogger.logp(Level.SEVERE, "ParamicsSimulator", "writeCameraStatus", |
|---|
| 337 | "Error writing to file " + cameraStatusFile + ".", e); |
|---|
| 338 | } |
|---|
| 339 | |
|---|
| 340 | writeToLog(cameraStatusLog, message.toString()); |
|---|
| 341 | |
|---|
| 342 | setChanged(); |
|---|
| 343 | notifyObservers(new ParamicsSimulatorLogMessage(PARAMICS_SIMULATOR_LOG.CAMERA_STATUS, message.toString())); |
|---|
| 344 | } |
|---|
| 345 | |
|---|
| 346 | /** |
|---|
| 347 | * Writes the Paramics status to the camera status XML file read by the Paramics Communicator, |
|---|
| 348 | * as well as to the Paramics status log file. All observers are notified with the new status, |
|---|
| 349 | * so they can also log it. |
|---|
| 350 | * |
|---|
| 351 | * @param status The current Paramics status |
|---|
| 352 | */ |
|---|
| 353 | public void writeParamicsStatus(NETWORK_STATUS status) |
|---|
| 354 | { |
|---|
| 355 | String message = "<Paramics>\n <Network_Status>" + status.message + |
|---|
| 356 | "</Network_Status>\n <Network_ID>" + networkId + "</Network_ID>\n</Paramics>"; |
|---|
| 357 | |
|---|
| 358 | try |
|---|
| 359 | { |
|---|
| 360 | FileWriter w = new FileWriter(paramStatusFile); |
|---|
| 361 | w.write(message); |
|---|
| 362 | w.close(); |
|---|
| 363 | } |
|---|
| 364 | catch (IOException e) |
|---|
| 365 | { |
|---|
| 366 | paramLogger.logp(Level.SEVERE, "TrafficSimulator", "writeParamicsStatus", |
|---|
| 367 | "Error writing to file " + paramStatusFile + ".", e); |
|---|
| 368 | } |
|---|
| 369 | |
|---|
| 370 | writeToLog(paramStatusLog, message); |
|---|
| 371 | |
|---|
| 372 | setChanged(); |
|---|
| 373 | notifyObservers(new ParamicsSimulatorLogMessage(PARAMICS_SIMULATOR_LOG.PARAMICS_STATUS, message)); |
|---|
| 374 | } |
|---|
| 375 | |
|---|
| 376 | /** |
|---|
| 377 | * Runs the Paramics simulator. |
|---|
| 378 | */ |
|---|
| 379 | public static void main(String[] args) |
|---|
| 380 | { |
|---|
| 381 | try |
|---|
| 382 | { |
|---|
| 383 | if(System.getProperty("PARAMICS_SIM_PROPERTIES") != null) |
|---|
| 384 | { |
|---|
| 385 | new Thread(new ParamicsSimulator(System.getProperty( |
|---|
| 386 | "PARAMICS_SIM_PROPERTIES"))).start(); |
|---|
| 387 | } |
|---|
| 388 | else |
|---|
| 389 | { |
|---|
| 390 | throw new Exception ("PARAMICS_SIM_PROPERTIES system property not defined."); |
|---|
| 391 | } |
|---|
| 392 | } |
|---|
| 393 | catch (Exception e) |
|---|
| 394 | { |
|---|
| 395 | paramLogger.logp(Level.SEVERE, "ParamicsSimulator", "Main", |
|---|
| 396 | "Error occured initializing application", e); |
|---|
| 397 | |
|---|
| 398 | JOptionPane.showMessageDialog(null, e.getMessage(), "Error - Program Exiting", JOptionPane.ERROR_MESSAGE); |
|---|
| 399 | |
|---|
| 400 | System.exit(-1); |
|---|
| 401 | } |
|---|
| 402 | } |
|---|
| 403 | |
|---|
| 404 | /** |
|---|
| 405 | * Gets the simulation cameras being used by the Paramics Simulator. |
|---|
| 406 | * @return A list of Simulation Cameras. |
|---|
| 407 | */ |
|---|
| 408 | public List<SimulationCamera> getCameras() |
|---|
| 409 | { |
|---|
| 410 | return cameras; |
|---|
| 411 | } |
|---|
| 412 | } |
|---|