| 1 | package tmcsim.common; |
|---|
| 2 | |
|---|
| 3 | import java.util.TreeMap; |
|---|
| 4 | import java.util.Vector; |
|---|
| 5 | import java.util.logging.Level; |
|---|
| 6 | import java.util.logging.Logger; |
|---|
| 7 | |
|---|
| 8 | import org.xml.sax.Attributes; |
|---|
| 9 | import org.xml.sax.SAXParseException; |
|---|
| 10 | import org.xml.sax.helpers.DefaultHandler; |
|---|
| 11 | |
|---|
| 12 | import tmcsim.client.cadclientgui.data.Incident; |
|---|
| 13 | import tmcsim.client.cadclientgui.data.IncidentEvent; |
|---|
| 14 | import tmcsim.cadmodels.IncidentInquiryDetails; |
|---|
| 15 | import tmcsim.cadmodels.IncidentInquiryHeader; |
|---|
| 16 | import tmcsim.cadmodels.IncidentInquiryModel_obj; |
|---|
| 17 | import tmcsim.cadmodels.IncidentInquiryServices; |
|---|
| 18 | import tmcsim.cadmodels.IncidentInquiryTows; |
|---|
| 19 | import tmcsim.cadmodels.IncidentInquiryUnitsAssigned; |
|---|
| 20 | import tmcsim.cadmodels.IncidentInquiryWitnesses; |
|---|
| 21 | import tmcsim.common.CADScriptTags.AUDIO_TAGS; |
|---|
| 22 | import tmcsim.common.CADScriptTags.CAD_INCIDENT_DATA_TAGS; |
|---|
| 23 | import tmcsim.common.CADScriptTags.CCTV_TAGS; |
|---|
| 24 | import tmcsim.common.CADScriptTags.INCIDENT_HEADER_TAGS; |
|---|
| 25 | import tmcsim.common.CADScriptTags.LOCATION_INFO_TAGS; |
|---|
| 26 | import tmcsim.common.CADScriptTags.PARAMICS_TAGS; |
|---|
| 27 | import tmcsim.common.CADScriptTags.SCRIPT_EVENT_TAGS; |
|---|
| 28 | import tmcsim.common.CADScriptTags.SCRIPT_LEVEL_TAGS; |
|---|
| 29 | import tmcsim.common.CADScriptTags.SERVICE_TAGS; |
|---|
| 30 | import tmcsim.common.CADScriptTags.TOW_TAGS; |
|---|
| 31 | import tmcsim.common.CADScriptTags.UNIT_TAGS; |
|---|
| 32 | import tmcsim.common.CADScriptTags.WITNESS_TAGS; |
|---|
| 33 | |
|---|
| 34 | /** |
|---|
| 35 | * SAX Handler that parses a script file and creates a list of Incident objects |
|---|
| 36 | * containing all script information that will be used by the CAD. |
|---|
| 37 | * |
|---|
| 38 | * @author Matthew Cechini |
|---|
| 39 | * @version |
|---|
| 40 | */ |
|---|
| 41 | public class ScriptHandler extends DefaultHandler { |
|---|
| 42 | |
|---|
| 43 | /** Error Logger. */ |
|---|
| 44 | private Logger scriptLogger = Logger.getLogger("tmcsim.common"); |
|---|
| 45 | |
|---|
| 46 | /** |
|---|
| 47 | * Enumeration used to keep track of the current tab level that the |
|---|
| 48 | * parser is reading data in. |
|---|
| 49 | */ |
|---|
| 50 | private static enum LEVEL { NONE, TMC_SCRIPT, SCRIPT_EVENT, CAD_DATA, |
|---|
| 51 | HEADER_INFO, LOCATION_INFO, CAD_INCIDENT_EVENT, PARAMICS }; |
|---|
| 52 | |
|---|
| 53 | /** |
|---|
| 54 | * Map containing all parsed Incidents. Keys = Incident Log Number. |
|---|
| 55 | * Values = Incident object. |
|---|
| 56 | */ |
|---|
| 57 | private TreeMap<Integer, Incident> incidentMap; |
|---|
| 58 | |
|---|
| 59 | /** Buffer used to hold parsed tag content */ |
|---|
| 60 | private StringBuffer parsedValue = new StringBuffer(); |
|---|
| 61 | |
|---|
| 62 | /** Current Tag level within the script that is being parsed */ |
|---|
| 63 | private LEVEL currentLevel = LEVEL.NONE; |
|---|
| 64 | |
|---|
| 65 | /** Log number for the current ScriptEvent being parsed */ |
|---|
| 66 | private Integer currentLogNumber = 0; |
|---|
| 67 | |
|---|
| 68 | /** Incident description for the current ScriptEvent being parsed */ |
|---|
| 69 | private String currentIncidentDesc = ""; |
|---|
| 70 | |
|---|
| 71 | /** Time index value (in seconds) for the current ScriptEvent being parsed */ |
|---|
| 72 | private long currentEventTime = 0; |
|---|
| 73 | |
|---|
| 74 | /** ParamicsLocation object for current script event */ |
|---|
| 75 | private ParamicsLocation currLoc = null; |
|---|
| 76 | |
|---|
| 77 | /** IncidentInquiryHeader object for current script event */ |
|---|
| 78 | private IncidentInquiryHeader currIIH = null; |
|---|
| 79 | |
|---|
| 80 | /** IncidentEvent object for current script event */ |
|---|
| 81 | private IncidentEvent currEvent = null; |
|---|
| 82 | |
|---|
| 83 | /** XMLIncident object for current script event */ |
|---|
| 84 | private XMLIncident currXMLInc = null; |
|---|
| 85 | |
|---|
| 86 | |
|---|
| 87 | |
|---|
| 88 | /** Constructor. Initializes incident map. */ |
|---|
| 89 | public ScriptHandler() { |
|---|
| 90 | incidentMap = new TreeMap<Integer, Incident>(); |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | /** |
|---|
| 94 | * Get the list of incidents that have been parsed from the script file. |
|---|
| 95 | * |
|---|
| 96 | * @returns Vector of Incident objects. |
|---|
| 97 | */ |
|---|
| 98 | public Vector<Incident> getIncidents() { |
|---|
| 99 | return new Vector<Incident>(incidentMap.values()); |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | /** SAX Handler method. Clear incident map and reset the error flag. */ |
|---|
| 103 | public void startDocument() { |
|---|
| 104 | incidentMap.clear(); |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | /** SAX Handler method. */ |
|---|
| 108 | public void startElement(String uri, String localName, String qName, Attributes attributes) { |
|---|
| 109 | |
|---|
| 110 | try { |
|---|
| 111 | if(qName.equals(SCRIPT_LEVEL_TAGS.TMC_SCRIPT.tag)) { |
|---|
| 112 | currentLevel = LEVEL.TMC_SCRIPT; |
|---|
| 113 | } |
|---|
| 114 | else if(qName.equals(SCRIPT_LEVEL_TAGS.SCRIPT_EVENT.tag)) { |
|---|
| 115 | currentLevel = LEVEL.SCRIPT_EVENT; |
|---|
| 116 | } |
|---|
| 117 | else if(qName.equals(SCRIPT_LEVEL_TAGS.CAD_DATA.tag)) { |
|---|
| 118 | currentLevel = LEVEL.CAD_DATA; |
|---|
| 119 | } |
|---|
| 120 | else if(qName.equals(SCRIPT_LEVEL_TAGS.HEADER_INFO.tag)) { |
|---|
| 121 | currIIH = new IncidentInquiryHeader(); |
|---|
| 122 | currIIH.logNumber = currentLogNumber; |
|---|
| 123 | |
|---|
| 124 | currentLevel = LEVEL.HEADER_INFO; |
|---|
| 125 | } |
|---|
| 126 | else if(qName.equals(SCRIPT_LEVEL_TAGS.LOCATION_INFO.tag)) { |
|---|
| 127 | currLoc = new ParamicsLocation(attributes.getValue( |
|---|
| 128 | LOCATION_INFO_TAGS.ID.tag)); |
|---|
| 129 | currentLevel = LEVEL.LOCATION_INFO; |
|---|
| 130 | } |
|---|
| 131 | else if(qName.equals(SCRIPT_LEVEL_TAGS.CAD_INCIDENT_EVENT.tag)) { |
|---|
| 132 | currEvent = new IncidentEvent(currentEventTime - incidentMap.get( |
|---|
| 133 | currentLogNumber).getSecondsToStart()); |
|---|
| 134 | currentLevel = LEVEL.CAD_INCIDENT_EVENT; |
|---|
| 135 | } |
|---|
| 136 | else if(qName.equals(SCRIPT_LEVEL_TAGS.PARAMICS.tag)) { |
|---|
| 137 | String locationID = attributes.getValue( |
|---|
| 138 | PARAMICS_TAGS.LOCATION_ID.tag); |
|---|
| 139 | |
|---|
| 140 | currXMLInc = new XMLIncident(locationID, incidentMap.get( |
|---|
| 141 | currentLogNumber).locationMap.get(locationID)); |
|---|
| 142 | currentLevel = LEVEL.PARAMICS; |
|---|
| 143 | } |
|---|
| 144 | else if(qName.equals(SCRIPT_EVENT_TAGS.INCIDENT.tag)) { |
|---|
| 145 | try { |
|---|
| 146 | currentLogNumber = Integer.parseInt(attributes.getValue( |
|---|
| 147 | SCRIPT_EVENT_TAGS.LOG_NUMBER.tag)); |
|---|
| 148 | } |
|---|
| 149 | catch (Exception e) { |
|---|
| 150 | scriptLogger.logp(Level.SEVERE, "ScriptHandler", "startElement", |
|---|
| 151 | "Invalid LogNumber " + attributes.getValue( |
|---|
| 152 | SCRIPT_EVENT_TAGS.LOG_NUMBER.tag), e); |
|---|
| 153 | currentLogNumber = 0; |
|---|
| 154 | } |
|---|
| 155 | } |
|---|
| 156 | else if(qName.equals(CAD_INCIDENT_DATA_TAGS.UNIT.tag)) { |
|---|
| 157 | IncidentInquiryUnitsAssigned iiu = new IncidentInquiryUnitsAssigned(IncidentInquiryModel_obj.SCRIPT_POS_INFO); |
|---|
| 158 | |
|---|
| 159 | iiu.beat = attributes.getValue(UNIT_TAGS.UNIT_NUMBER.tag); |
|---|
| 160 | iiu.statusType = attributes.getValue(UNIT_TAGS.UNIT_STATUS.tag); |
|---|
| 161 | iiu.isPrimary = new Boolean(attributes.getValue(UNIT_TAGS.UNIT_PRIMARY.tag)).booleanValue(); |
|---|
| 162 | iiu.isActive = new Boolean(attributes.getValue(UNIT_TAGS.UNIT_ACTIVE.tag)).booleanValue(); |
|---|
| 163 | |
|---|
| 164 | currEvent.eventInfo.addUnit(iiu); |
|---|
| 165 | } |
|---|
| 166 | else if(qName.equals(CAD_INCIDENT_DATA_TAGS.WITNESS.tag)) { |
|---|
| 167 | IncidentInquiryWitnesses iiw = new IncidentInquiryWitnesses(IncidentInquiryModel_obj.SCRIPT_POS_INFO); |
|---|
| 168 | |
|---|
| 169 | iiw.reportingParty = attributes.getValue(WITNESS_TAGS.WITNESS_NAME.tag); |
|---|
| 170 | iiw.telephoneNum = attributes.getValue(WITNESS_TAGS.WITNESS_PHONE.tag); |
|---|
| 171 | iiw.address = attributes.getValue(WITNESS_TAGS.WITNESS_ADDRESS.tag); |
|---|
| 172 | |
|---|
| 173 | currEvent.eventInfo.addWitness(iiw); |
|---|
| 174 | } |
|---|
| 175 | else if(qName.equals(CAD_INCIDENT_DATA_TAGS.TOW.tag)) { |
|---|
| 176 | IncidentInquiryTows iit = new IncidentInquiryTows(IncidentInquiryModel_obj.SCRIPT_POS_INFO); |
|---|
| 177 | |
|---|
| 178 | iit.towCompany = attributes.getValue(TOW_TAGS.TOW_COMPANY_NAME.tag); |
|---|
| 179 | iit.confPhoneNum = attributes.getValue(TOW_TAGS.CONF_PHONE_NUM.tag); |
|---|
| 180 | iit.publicPhoneNum = attributes.getValue(TOW_TAGS.PUBLIC_PHONE_NUM.tag); |
|---|
| 181 | iit.beat = attributes.getValue(TOW_TAGS.BEAT.tag); |
|---|
| 182 | |
|---|
| 183 | currEvent.eventInfo.addTow(iit); |
|---|
| 184 | } |
|---|
| 185 | else if(qName.equals(CAD_INCIDENT_DATA_TAGS.SERVICE.tag)) { |
|---|
| 186 | IncidentInquiryServices iis = new IncidentInquiryServices(IncidentInquiryModel_obj.SCRIPT_POS_INFO); |
|---|
| 187 | |
|---|
| 188 | iis.serviceName = attributes.getValue(SERVICE_TAGS.SERVICE_NAME.tag); |
|---|
| 189 | iis.confPhoneNum = attributes.getValue(SERVICE_TAGS.CONF_PHONE_NUM.tag); |
|---|
| 190 | iis.publicPhoneNum = attributes.getValue(SERVICE_TAGS.PUBLIC_PHONE_NUM.tag); |
|---|
| 191 | |
|---|
| 192 | currEvent.eventInfo.addService(iis); |
|---|
| 193 | } |
|---|
| 194 | else if(qName.equals(CAD_INCIDENT_DATA_TAGS.AUDIO.tag)) { |
|---|
| 195 | currEvent.waveFile = attributes.getValue(AUDIO_TAGS.FILE_PATH.tag); |
|---|
| 196 | currEvent.waveLength = new Integer(attributes.getValue(AUDIO_TAGS.FILE_LENGTH.tag)).intValue(); |
|---|
| 197 | } |
|---|
| 198 | else if(qName.equals(CAD_INCIDENT_DATA_TAGS.CCTV_INFO.tag)) { |
|---|
| 199 | CCTVInfo newInfo = new CCTVInfo(); |
|---|
| 200 | |
|---|
| 201 | try { |
|---|
| 202 | newInfo.cctv_id = Integer.parseInt(attributes.getValue(CCTV_TAGS.CCTV_ID.tag)); |
|---|
| 203 | newInfo.direction = CCTVDirections.fromChar(attributes.getValue(CCTV_TAGS.CCTV_DIR.tag).charAt(0)); |
|---|
| 204 | newInfo.toggle = Boolean.parseBoolean(attributes.getValue(CCTV_TAGS.CCTV_TOGGLE.tag)); |
|---|
| 205 | |
|---|
| 206 | currEvent.cctvInfos.add(newInfo); |
|---|
| 207 | } |
|---|
| 208 | catch (Exception e) { |
|---|
| 209 | scriptLogger.logp(Level.SEVERE, "ScriptHandler", "startElement", |
|---|
| 210 | "Exception in parsing CCTV_INFO node.", e); |
|---|
| 211 | } |
|---|
| 212 | |
|---|
| 213 | } |
|---|
| 214 | |
|---|
| 215 | } catch (Exception e) { |
|---|
| 216 | scriptLogger.logp(Level.SEVERE, "ScriptHandler", "startElement", |
|---|
| 217 | "Exception in starting element <" + qName + ">.", e); |
|---|
| 218 | } |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | /** SAX Handler method. Append read characters to local buffer. */ |
|---|
| 222 | public void characters(char[] ch, int start, int length) { |
|---|
| 223 | parsedValue.append(new String(ch, start, length).trim()); |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | /** SAX Handler method. */ |
|---|
| 227 | public void endElement(String uri, String localName, String qName) { |
|---|
| 228 | |
|---|
| 229 | try { |
|---|
| 230 | if(qName.equals(SCRIPT_LEVEL_TAGS.SCRIPT_EVENT.tag)) { |
|---|
| 231 | currentLevel = LEVEL.TMC_SCRIPT; |
|---|
| 232 | } |
|---|
| 233 | else if(qName.equals(SCRIPT_LEVEL_TAGS.CAD_DATA.tag)) { |
|---|
| 234 | currentLevel = LEVEL.SCRIPT_EVENT; |
|---|
| 235 | } |
|---|
| 236 | else if(qName.equals(SCRIPT_LEVEL_TAGS.HEADER_INFO.tag)) { |
|---|
| 237 | incidentMap.get(currentLogNumber).header = currIIH; |
|---|
| 238 | currentLevel = LEVEL.CAD_DATA; |
|---|
| 239 | } |
|---|
| 240 | else if(qName.equals(SCRIPT_LEVEL_TAGS.LOCATION_INFO.tag)) { |
|---|
| 241 | incidentMap.get(currentLogNumber).locationMap.put(currLoc.locationID, currLoc); |
|---|
| 242 | currentLevel = LEVEL.CAD_DATA; |
|---|
| 243 | } |
|---|
| 244 | else if(qName.equals(SCRIPT_LEVEL_TAGS.CAD_INCIDENT_EVENT.tag)) { |
|---|
| 245 | incidentMap.get(currentLogNumber).addEvent(currEvent); |
|---|
| 246 | currentLevel = LEVEL.CAD_DATA; |
|---|
| 247 | } |
|---|
| 248 | else if(qName.equals(SCRIPT_LEVEL_TAGS.PARAMICS.tag)) { |
|---|
| 249 | currEvent.XMLIncidents.add(currXMLInc); |
|---|
| 250 | currentLevel = LEVEL.CAD_INCIDENT_EVENT; |
|---|
| 251 | } |
|---|
| 252 | else if(qName.equals(SCRIPT_EVENT_TAGS.INCIDENT.tag)) { |
|---|
| 253 | currentIncidentDesc = parsedValue.toString(); |
|---|
| 254 | |
|---|
| 255 | if(incidentMap.get(currentLogNumber) == null) { |
|---|
| 256 | |
|---|
| 257 | incidentMap.put(currentLogNumber, |
|---|
| 258 | new Incident(currentLogNumber, |
|---|
| 259 | currentIncidentDesc, |
|---|
| 260 | currentEventTime)); |
|---|
| 261 | } |
|---|
| 262 | } |
|---|
| 263 | else if(qName.equals(SCRIPT_EVENT_TAGS.TIME_INDEX.tag)) { |
|---|
| 264 | currentEventTime = timeBytesToSeconds(parsedValue.toString().trim()); |
|---|
| 265 | } |
|---|
| 266 | else if(qName.equals(INCIDENT_HEADER_TAGS.TYPE.tag)){ |
|---|
| 267 | currIIH.type = parsedValue.toString(); |
|---|
| 268 | } |
|---|
| 269 | else if(qName.equals(INCIDENT_HEADER_TAGS.BEAT.tag)){ |
|---|
| 270 | currIIH.beat = parsedValue.toString(); |
|---|
| 271 | } |
|---|
| 272 | else if(qName.equals(INCIDENT_HEADER_TAGS.FULL_LOCATION.tag)){ |
|---|
| 273 | currIIH.fullLocation = parsedValue.toString(); |
|---|
| 274 | } |
|---|
| 275 | else if(qName.equals(INCIDENT_HEADER_TAGS.TRUNC_LOCATION.tag)){ |
|---|
| 276 | currIIH.truncLocation = parsedValue.toString(); |
|---|
| 277 | } |
|---|
| 278 | else if(qName.equals(INCIDENT_HEADER_TAGS.LOG_NUMBER.tag)){ |
|---|
| 279 | currIIH.logNumber = Integer.parseInt(parsedValue.toString()); |
|---|
| 280 | } |
|---|
| 281 | else if(qName.equals(CAD_INCIDENT_DATA_TAGS.DETAIL.tag)) { |
|---|
| 282 | currEvent.eventInfo.addDetail(new IncidentInquiryDetails( |
|---|
| 283 | IncidentInquiryModel_obj.SCRIPT_POS_INFO, |
|---|
| 284 | parsedValue.toString(), false)); |
|---|
| 285 | } |
|---|
| 286 | else if(currentLevel == LEVEL.PARAMICS) { |
|---|
| 287 | try { |
|---|
| 288 | currXMLInc.readXMLNode(qName, parsedValue.toString()); |
|---|
| 289 | } |
|---|
| 290 | catch (Exception e) { |
|---|
| 291 | scriptLogger.logp(Level.SEVERE, "ScriptHandler", "endElement", |
|---|
| 292 | "Exception in parsing PARAMICS node.", e); |
|---|
| 293 | } |
|---|
| 294 | } |
|---|
| 295 | else if(currentLevel == LEVEL.LOCATION_INFO) { |
|---|
| 296 | currLoc.readXMLNode(qName, parsedValue.toString()); |
|---|
| 297 | } |
|---|
| 298 | |
|---|
| 299 | parsedValue.setLength(0); |
|---|
| 300 | } catch (Exception e) { |
|---|
| 301 | scriptLogger.logp(Level.SEVERE, "ScriptHandler", "endElement", |
|---|
| 302 | "Exception in ending element <" + qName + ">.", e); |
|---|
| 303 | } |
|---|
| 304 | } |
|---|
| 305 | |
|---|
| 306 | public void endDocument() { |
|---|
| 307 | } |
|---|
| 308 | |
|---|
| 309 | public void error(SAXParseException e) { |
|---|
| 310 | scriptLogger.logp(Level.SEVERE, "ScriptHandler", "error", |
|---|
| 311 | "SAX Parsing error.", e); |
|---|
| 312 | } |
|---|
| 313 | |
|---|
| 314 | public void fatalError(SAXParseException e) { |
|---|
| 315 | scriptLogger.logp(Level.SEVERE, "ScriptHandler", "fatalError", |
|---|
| 316 | "SAX Parsing fatal error.", e); |
|---|
| 317 | } |
|---|
| 318 | |
|---|
| 319 | public void warning(SAXParseException e) { |
|---|
| 320 | scriptLogger.logp(Level.SEVERE, "ScriptHandler", "warning", |
|---|
| 321 | "SAX Parsing warning.", e); |
|---|
| 322 | } |
|---|
| 323 | |
|---|
| 324 | |
|---|
| 325 | /** |
|---|
| 326 | * Private method to convert a time object from format HH:MM:SS to a long value of the |
|---|
| 327 | * corresponding number of seconds. |
|---|
| 328 | * |
|---|
| 329 | * @param time String time representation of format HH:MM:SS |
|---|
| 330 | * @return long Number of seconds |
|---|
| 331 | * @throws StringIndexOutOfBoundsException if the input parameter is not valid |
|---|
| 332 | */ |
|---|
| 333 | private long timeBytesToSeconds(String time) |
|---|
| 334 | throws StringIndexOutOfBoundsException |
|---|
| 335 | { |
|---|
| 336 | long seconds = 0; |
|---|
| 337 | |
|---|
| 338 | seconds = ((long) Character.digit(time.charAt(0), 10) * 36000 + |
|---|
| 339 | Character.digit(time.charAt(1), 10) * 3600 + |
|---|
| 340 | Character.digit(time.charAt(3), 10) * 600 + |
|---|
| 341 | Character.digit(time.charAt(4), 10) * 60 + |
|---|
| 342 | Character.digit(time.charAt(6), 10) * 10 + |
|---|
| 343 | Character.digit(time.charAt(7), 10)); |
|---|
| 344 | |
|---|
| 345 | |
|---|
| 346 | return seconds; |
|---|
| 347 | } |
|---|
| 348 | |
|---|
| 349 | |
|---|
| 350 | } |
|---|