001package jmri.managers.configurexml; 002 003import java.awt.GraphicsEnvironment; 004import java.util.List; 005import java.util.SortedSet; 006 007import jmri.InstanceManager; 008import jmri.Route; 009import jmri.RouteManager; 010import jmri.Sensor; 011import jmri.Turnout; 012import jmri.managers.DefaultRouteManager; 013import jmri.util.swing.JmriJOptionPane; 014 015import org.jdom2.Element; 016 017/** 018 * Provides the functionality for configuring RouteManagers. 019 * 020 * @author Dave Duchamp Copyright (c) 2004 021 * @author Daniel Boudreau Copyright (c) 2007 022 * @author Simon Reader Copyright (C) 2008 023 */ 024public class DefaultRouteManagerXml extends jmri.managers.configurexml.AbstractNamedBeanManagerConfigXML { 025 026 private static final String STR_ROUTE = "route"; 027 private static final String STR_ROUTES = "routes"; 028 029 private static final String STR_CONTROL_TURNOUT = "controlTurnout"; 030 private static final String STR_CONTROL_TURNOUT_FEEDBACK = "controlTurnoutFeedback"; 031 private static final String STR_CONTROL_TURNOUT_STATE = "controlTurnoutState"; 032 private static final String STR_CONTROL_LOCK_TURNOUT = "controlLockTurnout"; 033 private static final String STR_CONTROL_LOCK_TURNOUT_STATE = "controlLockTurnoutState"; 034 035 private static final String STR_ACTIVE = "ACTIVE"; 036 private static final String STR_INACTIVE = "INACTIVE"; 037 private static final String STR_ON_ACTIVE = "onActive"; 038 private static final String STR_ON_INACTIVE = "onInactive"; 039 private static final String STR_ON_CHANGE = "onChange"; 040 private static final String STR_VETO_ACTIVE = "vetoActive"; 041 private static final String STR_VETO_INACTIVE = "vetoInactive"; 042 043 private static final String STR_THROWN = "THROWN"; 044 private static final String STR_CLOSED = "CLOSED"; 045 private static final String STR_CHANGE = "CHANGE"; 046 private static final String STR_TOGGLE = "TOGGLE"; 047 private static final String STR_VETO_CLOSED = "VETOCLOSED"; 048 private static final String STR_VETO_THROWN = "VETOTHROWN"; 049 private static final String STR_ADDED_DELAY = "addedDelay"; 050 051 private static final String STR_ROUTE_LOCKED = "routeLocked"; 052 private static final String STR_ROUTE_SENSOR = "routeSensor"; 053 private static final String STR_ROUTE_OUTPUT_SENSOR = "routeOutputSensor"; 054 private static final String STR_ROUTE_OUTPUT_TURNOUT = "routeOutputTurnout"; 055 private static final String STR_STATE = "state"; 056 private static final String STR_MODE = "mode"; 057 private static final String STR_NAME = "name"; 058 059 private static final String STR_ROUTE_SOUND_FILE = "routeSoundFile"; 060 private static final String STR_ROUTE_SCRIPT_FILE = "routeScriptFile"; 061 private static final String STR_TURNOUTS_ALIGNED_SENSOR = "turnoutsAlignedSensor"; 062 063 public DefaultRouteManagerXml() { 064 } 065 066 /** 067 * Default implementation for storing the contents of a RouteManager. 068 * 069 * @param o Object to store, of type RouteManager 070 * @return Element containing the complete info 071 */ 072 @Override 073 public Element store(Object o) { 074 Element routes = new Element(STR_ROUTES); 075 setStoreElementClass(routes); 076 RouteManager rm = (RouteManager) o; 077 if (rm != null) { 078 SortedSet<Route> routeList = rm.getNamedBeanSet(); 079 // don't return an element if there are no routes to include 080 if (routeList.isEmpty()) { 081 return null; 082 } 083 for (Route r : routeList) { 084 // store the routes 085 String rName = r.getSystemName(); 086 log.debug("system name is {}", rName); 087 088 String cTurnout = r.getControlTurnout(); 089 int addedDelay = r.getRouteCommandDelay(); 090 String cLockTurnout = r.getLockControlTurnout(); 091 092 Element elem = new Element(STR_ROUTE); 093 elem.addContent(new Element(STR_SYSTEM_NAME).addContent(rName)); 094 095 // As a work-around for backward compatibility, store systemName and userName as attribute. 096 // TODO Remove this in e.g. JMRI 4.11.1 and then update all the loadref comparison files 097 String uName = r.getUserName(); 098 if (uName != null && !uName.isEmpty()) { 099 elem.setAttribute(STR_USER_NAME, uName); 100 } 101 102 // store common parts 103 storeCommon(r, elem); 104 105 if (cTurnout != null && !cTurnout.isEmpty()) { 106 elem.setAttribute(STR_CONTROL_TURNOUT, cTurnout); 107 int state = r.getControlTurnoutState(); 108 switch (state) { 109 case Route.ONTHROWN: 110 elem.setAttribute(STR_CONTROL_TURNOUT_STATE, STR_THROWN); 111 break; 112 case Route.ONCHANGE: 113 elem.setAttribute(STR_CONTROL_TURNOUT_STATE, STR_CHANGE); 114 break; 115 case Route.VETOCLOSED: 116 elem.setAttribute(STR_CONTROL_TURNOUT_STATE, STR_VETO_CLOSED); 117 break; 118 case Route.VETOTHROWN: 119 elem.setAttribute(STR_CONTROL_TURNOUT_STATE, STR_VETO_THROWN); 120 break; 121 default: 122 elem.setAttribute(STR_CONTROL_TURNOUT_STATE, STR_CLOSED); 123 break; 124 } 125 126 if (r.getControlTurnoutFeedback()) { 127 elem.setAttribute(STR_CONTROL_TURNOUT_FEEDBACK, STR_TRUE); 128 } // don't write if not set, accept default 129 } 130 if (cLockTurnout != null && !cLockTurnout.isEmpty()) { 131 elem.setAttribute(STR_CONTROL_LOCK_TURNOUT, cLockTurnout); 132 int state = r.getLockControlTurnoutState(); 133 switch (state) { 134 case Route.ONTHROWN: 135 elem.setAttribute(STR_CONTROL_LOCK_TURNOUT_STATE, STR_THROWN); 136 break; 137 case Route.ONCHANGE: 138 elem.setAttribute(STR_CONTROL_LOCK_TURNOUT_STATE, STR_CHANGE); 139 break; 140 default: 141 elem.setAttribute(STR_CONTROL_LOCK_TURNOUT_STATE, STR_CLOSED); 142 break; 143 } 144 } 145 if (addedDelay > 0) { 146 elem.setAttribute(STR_ADDED_DELAY, Integer.toString(addedDelay)); 147 } 148 149 if ( r.getLocked() ) { 150 // TODO - For consistency in class, convert True to true 151 elem.setAttribute(STR_ROUTE_LOCKED, "True"); 152 } 153 // add route output Turnouts, if any 154 int index = 0; 155 String rTurnout; 156 while ((rTurnout = r.getOutputTurnoutByIndex(index)) != null) { 157 Element rElem = new Element(STR_ROUTE_OUTPUT_TURNOUT) 158 .setAttribute(STR_SYSTEM_NAME, rTurnout); 159 String sState = STR_CLOSED; 160 if (r.getOutputTurnoutSetState(rTurnout) == Turnout.THROWN) { 161 sState = STR_THROWN; 162 } else if (r.getOutputTurnoutSetState(rTurnout) == Route.TOGGLE) { 163 sState = STR_TOGGLE; 164 } 165 rElem.setAttribute(STR_STATE, sState); 166 elem.addContent(rElem); 167 index++; 168 } 169 // add route output Sensors, if any 170 index = 0; 171 String rSensor; 172 while ((rSensor = r.getOutputSensorByIndex(index)) != null) { 173 Element rElem = new Element(STR_ROUTE_OUTPUT_SENSOR) 174 .setAttribute(STR_SYSTEM_NAME, rSensor); 175 String sState = STR_INACTIVE; 176 if (r.getOutputSensorSetState(rSensor) == Sensor.ACTIVE) { 177 sState = STR_ACTIVE; 178 } else if (r.getOutputSensorSetState(rSensor) == Route.TOGGLE) { 179 sState = STR_TOGGLE; 180 } 181 rElem.setAttribute(STR_STATE, sState); 182 elem.addContent(rElem); 183 index++; 184 } 185 // add route control Sensors, if any 186 index = 0; 187 while ((rSensor = r.getRouteSensorName(index)) != null) { 188 Element rsElem = new Element(STR_ROUTE_SENSOR) 189 .setAttribute(STR_SYSTEM_NAME, rSensor); 190 int mode = r.getRouteSensorMode(index); 191 String modeName; 192 switch (mode) { 193 case Route.ONACTIVE: 194 modeName = STR_ON_ACTIVE; 195 break; 196 case Route.ONINACTIVE: 197 modeName = STR_ON_INACTIVE; 198 break; 199 case Route.ONCHANGE: 200 modeName = STR_ON_CHANGE; 201 break; 202 case Route.VETOACTIVE: 203 modeName = STR_VETO_ACTIVE; 204 break; 205 case Route.VETOINACTIVE: 206 modeName = STR_VETO_INACTIVE; 207 break; 208 default: 209 modeName = null; 210 } 211 if (modeName != null) { 212 rsElem.setAttribute(STR_MODE, modeName); 213 } 214 elem.addContent(rsElem); 215 index++; 216 } 217 // add sound and script file elements if needed 218 String osn = r.getOutputSoundName(); 219 if ( osn != null && !osn.isEmpty()) { 220 Element rsElem = new Element(STR_ROUTE_SOUND_FILE) 221 .setAttribute(STR_NAME, 222 jmri.util.FileUtil.getPortableFilename( 223 new java.io.File(osn)) 224 ); 225 elem.addContent(rsElem); 226 } 227 osn = r.getOutputScriptName(); 228 if ( osn != null && !osn.isEmpty()) { 229 Element rsElem = new Element(STR_ROUTE_SCRIPT_FILE) 230 .setAttribute(STR_NAME, 231 jmri.util.FileUtil.getPortableFilename( 232 new java.io.File(osn)) 233 ); 234 elem.addContent(rsElem); 235 } 236 237 // add turnouts aligned sensor if there is one 238 osn = r.getTurnoutsAlignedSensor(); 239 if ( osn != null && !osn.isEmpty()) { 240 Element rsElem = new Element(STR_TURNOUTS_ALIGNED_SENSOR) 241 .setAttribute(STR_NAME, osn); 242 elem.addContent(rsElem); 243 } 244 245 log.debug("store Route {}", rName); 246 routes.addContent(elem); 247 } 248 } 249 return routes; 250 } 251 252 /** 253 * Subclass provides implementation to create the correct top element, 254 * including the type information. Default implementation is to use the 255 * local class here. 256 * 257 * @param routes The top-level element being created 258 */ 259 public void setStoreElementClass(Element routes) { 260 routes.setAttribute(STR_CLASS, this.getClass().getName()); 261 } 262 263 /** 264 * Create a RouteManager object of the correct class, then register and fill 265 * it. 266 * 267 * @param sharedRoutes Top level Element to unpack. 268 * @param perNodeRoutes unused. 269 * @return true if successful 270 */ 271 @Override 272 public boolean load(Element sharedRoutes, Element perNodeRoutes) { 273 // create the master object 274 replaceRouteManager(); 275 // load individual sharedRoutes 276 loadRoutes(sharedRoutes); 277 return true; 278 } 279 280 /** 281 * Utility method to load the individual Route objects. If there's no 282 * additional info needed for a specific route type, invoke this with the 283 * parent of the set of Route elements. 284 * 285 * @param routes Element containing the Route elements to load. 286 */ 287 public void loadRoutes(Element routes) { 288 List<Element> routeList = routes.getChildren(STR_ROUTE); 289 log.debug("Found {} routes", routeList.size()); 290 RouteManager tm = InstanceManager.getDefault(RouteManager.class); 291 int namesChanged = 0; 292 293 for (Element el : routeList) { 294 295 String sysName = getSystemName(el); 296 if (sysName == null) { 297 log.warn("unexpected null in systemName {}", el); 298 break; 299 } 300 // convert typeLetter from R to tm.typeLetter() 301 if (sysName.startsWith(tm.getSystemPrefix() + 'R')) { 302 String old = sysName; 303 sysName = tm.getSystemNamePrefix() + sysName.substring(tm.getSystemNamePrefix().length()); 304 log.warn("Converting route system name {} to {}", old, sysName); 305 namesChanged++; 306 } 307 // prepend systemNamePrefix if missing 308 if (!sysName.startsWith(tm.getSystemNamePrefix())) { 309 String old = sysName; 310 sysName = tm.getSystemNamePrefix() + sysName; 311 log.warn("Converting route system name {} to {}", old, sysName); 312 namesChanged++; 313 } 314 315 String userName = getUserName(el); 316 String cTurnout = null; 317 String cTurnoutState = null; 318 boolean cTurnoutFeedback = false; 319 String routeLockedTxt = null; 320 String cLockTurnout = null; 321 String cLockTurnoutState = null; 322 int addedDelay = 0; 323 324 if (el.getAttribute(STR_CONTROL_TURNOUT) != null) { 325 cTurnout = el.getAttribute(STR_CONTROL_TURNOUT).getValue(); 326 } 327 if (el.getAttribute(STR_CONTROL_TURNOUT_STATE) != null) { 328 cTurnoutState = el.getAttribute(STR_CONTROL_TURNOUT_STATE).getValue(); 329 } 330 if (el.getAttribute(STR_CONTROL_TURNOUT_FEEDBACK) != null) { 331 cTurnoutFeedback = el.getAttribute(STR_CONTROL_TURNOUT_FEEDBACK).getValue().equals(STR_TRUE); 332 } 333 if (el.getAttribute(STR_CONTROL_LOCK_TURNOUT) != null) { 334 cLockTurnout = el.getAttribute(STR_CONTROL_LOCK_TURNOUT).getValue(); 335 } 336 if (el.getAttribute(STR_CONTROL_LOCK_TURNOUT_STATE) != null) { 337 cLockTurnoutState = el.getAttribute(STR_CONTROL_LOCK_TURNOUT_STATE).getValue(); 338 } 339 if (el.getAttribute(STR_ADDED_DELAY) != null) { 340 String addedDelayTxt = el.getAttribute(STR_ADDED_DELAY).getValue(); 341 if (addedDelayTxt != null) { 342 addedDelay = Integer.parseInt(addedDelayTxt); 343 } 344 } 345 if (el.getAttribute(STR_ROUTE_LOCKED) != null) { 346 routeLockedTxt = el.getAttribute(STR_ROUTE_LOCKED).getValue(); 347 } 348 349 log.debug("create route: ({})({})", sysName, (userName == null ? "<null>" : userName)); 350 351 Route r; 352 try { 353 r = tm.provideRoute(sysName, userName); 354 } catch (IllegalArgumentException ex) { 355 log.error("failed to create Route: {}", sysName); 356 return; 357 } 358 359 // load common parts 360 loadCommon(r, el); 361 362 // add control turnout if there is one 363 if (cTurnout != null) { 364 r.setControlTurnout(cTurnout); 365 if (cTurnoutState != null) { 366 switch (cTurnoutState) { 367 case STR_THROWN: 368 r.setControlTurnoutState(Route.ONTHROWN); 369 break; 370 case STR_CHANGE: 371 r.setControlTurnoutState(Route.ONCHANGE); 372 break; 373 case STR_VETO_CLOSED: 374 r.setControlTurnoutState(Route.VETOCLOSED); 375 break; 376 case STR_VETO_THROWN: 377 r.setControlTurnoutState(Route.VETOTHROWN); 378 break; 379 default: 380 r.setControlTurnoutState(Route.ONCLOSED); 381 } 382 } else { 383 log.error("cTurnoutState was null!"); 384 } 385 r.setControlTurnoutFeedback(cTurnoutFeedback); 386 } 387 // set added delay 388 r.setRouteCommandDelay(addedDelay); 389 390 // determine if route locked 391 if (routeLockedTxt != null && routeLockedTxt.equals("True")) { 392 r.setLocked(true); 393 } 394 395 // add lock control turout if there is one 396 if (cLockTurnout != null) { 397 r.setLockControlTurnout(cLockTurnout); 398 if (cLockTurnoutState != null) { 399 switch (cLockTurnoutState) { 400 case STR_THROWN: 401 r.setLockControlTurnoutState(Route.ONTHROWN); 402 break; 403 case STR_CHANGE: 404 r.setLockControlTurnoutState(Route.ONCHANGE); 405 break; 406 default: 407 r.setLockControlTurnoutState(Route.ONCLOSED); 408 break; 409 } 410 } else { 411 log.error("cLockTurnoutState was null!"); 412 } 413 } 414 415 // load output turnouts if there are any - old format first (1.7.6 and before) 416 List<Element> routeTurnoutList = el.getChildren("routeTurnout"); 417 if (!routeTurnoutList.isEmpty()) { 418 // This route has turnouts 419 for (Element element : routeTurnoutList) { 420 if (element.getAttribute(STR_SYSTEM_NAME) == null) { 421 log.warn("unexpected null in route turnout systemName {} {}", element, element.getAttributes()); 422 break; 423 } 424 String tSysName = element.getAttribute(STR_SYSTEM_NAME).getValue(); 425 String rState = element.getAttribute(STR_STATE).getValue(); 426 int tSetState = Turnout.CLOSED; 427 if (rState.equals(STR_THROWN)) { 428 tSetState = Turnout.THROWN; 429 } else if (rState.equals(STR_TOGGLE)) { 430 tSetState = Route.TOGGLE; 431 } 432 // Add turnout to route 433 r.addOutputTurnout(tSysName, tSetState); 434 } 435 } 436 // load output turnouts if there are any - new format 437 routeTurnoutList = el.getChildren(STR_ROUTE_OUTPUT_TURNOUT); 438 if (!routeTurnoutList.isEmpty()) { 439 // This route has turnouts 440 for (int k = 0; k < routeTurnoutList.size(); k++) { // index k is required later to get Locked state 441 if (routeTurnoutList.get(k).getAttribute(STR_SYSTEM_NAME) == null) { 442 log.warn("unexpected null in route turnout systemName {} {}", routeTurnoutList.get(k), 443 routeTurnoutList.get(k).getAttributes()); 444 break; 445 } 446 String tSysName = routeTurnoutList.get(k) 447 .getAttribute(STR_SYSTEM_NAME).getValue(); 448 String rState = routeTurnoutList.get(k) 449 .getAttribute(STR_STATE).getValue(); 450 int tSetState = Turnout.CLOSED; 451 if (rState.equals(STR_THROWN)) { 452 tSetState = Turnout.THROWN; 453 } else if (rState.equals(STR_TOGGLE)) { 454 tSetState = Route.TOGGLE; 455 } 456 // If the Turnout has already been added to the route and is the same as that loaded, 457 // we will not re add the turnout. 458 if (!r.isOutputTurnoutIncluded(tSysName)) { 459 460 // Add turnout to route 461 r.addOutputTurnout(tSysName, tSetState); 462 463 // determine if turnout should be locked 464 Turnout t = r.getOutputTurnout(k); 465 if ( t == null ) { 466 log.error("could not find output Turnout {}", tSysName); 467 } else if (r.getLocked()) { 468 t.setLocked(Turnout.CABLOCKOUT + Turnout.PUSHBUTTONLOCKOUT, true); 469 } 470 } 471 } 472 } 473 // load output sensors if there are any - new format 474 List<Element> routeSensorList = el.getChildren(STR_ROUTE_OUTPUT_SENSOR); 475 for (Element sen : routeSensorList) { // this route has output sensors 476 if (sen.getAttribute(STR_SYSTEM_NAME) == null) { 477 log.warn("unexpected null in systemName {} {}", sen, sen.getAttributes()); 478 break; 479 } 480 String tSysName = sen.getAttribute(STR_SYSTEM_NAME).getValue(); 481 String rState = sen.getAttribute(STR_STATE).getValue(); 482 int tSetState = Sensor.INACTIVE; 483 if (rState.equals(STR_ACTIVE)) { 484 tSetState = Sensor.ACTIVE; 485 } else if (rState.equals(STR_TOGGLE)) { 486 tSetState = Route.TOGGLE; 487 } 488 // If the Turnout has already been added to the route and is the same as that loaded, 489 // we will not re add the turnout. 490 if (r.isOutputSensorIncluded(tSysName)) { 491 break; 492 } 493 // Add turnout to route 494 r.addOutputSensor(tSysName, tSetState); 495 } 496 // load sound, script files if present 497 Element fileElement = el.getChild(STR_ROUTE_SOUND_FILE); 498 if (fileElement != null) { 499 // convert to absolute path name 500 r.setOutputSoundName( 501 jmri.util.FileUtil.getExternalFilename(fileElement.getAttribute(STR_NAME).getValue()) 502 ); 503 } 504 fileElement = el.getChild(STR_ROUTE_SCRIPT_FILE); 505 if (fileElement != null) { 506 r.setOutputScriptName( 507 jmri.util.FileUtil.getExternalFilename(fileElement.getAttribute(STR_NAME).getValue()) 508 ); 509 } 510 // load turnouts aligned sensor if there is one 511 fileElement = el.getChild(STR_TURNOUTS_ALIGNED_SENSOR); 512 if (fileElement != null) { 513 r.setTurnoutsAlignedSensor(fileElement.getAttribute(STR_NAME).getValue()); 514 } 515 516 // load route control sensors, if there are any 517 routeSensorList = el.getChildren(STR_ROUTE_SENSOR); 518 for (Element sen : routeSensorList) { // this route has sensors 519 if (sen.getAttribute(STR_SYSTEM_NAME) == null) { 520 log.warn("unexpected null in systemName {} {}", sen, sen.getAttributes()); 521 break; 522 } else { 523 int mode = Route.ONACTIVE; // default mode 524 if (sen.getAttribute(STR_MODE) == null) { 525 break; 526 } 527 String sm = sen.getAttribute(STR_MODE).getValue(); 528 switch (sm) { 529 case STR_ON_ACTIVE: 530 mode = Route.ONACTIVE; 531 break; 532 case STR_ON_INACTIVE: 533 mode = Route.ONINACTIVE; 534 break; 535 case STR_ON_CHANGE: 536 mode = Route.ONCHANGE; 537 break; 538 case STR_VETO_ACTIVE: 539 mode = Route.VETOACTIVE; 540 break; 541 case STR_VETO_INACTIVE: 542 mode = Route.VETOINACTIVE; 543 break; 544 default: 545 log.warn("unexpected sensor mode in route {} was {}", sysName, sm); 546 } 547 // Add Sensor to route 548 r.addSensorToRoute(sen.getAttribute(STR_SYSTEM_NAME).getValue(), mode); 549 } 550 } 551 // and start it working 552 r.activateRoute(); 553 } 554 if (namesChanged > 0) { 555 // TODO: replace the System property check with an in-application mechanism 556 // for notifying users of multiple changes that can be silenced as part of 557 // normal operations 558 if (!GraphicsEnvironment.isHeadless() && !Boolean.getBoolean("jmri.test.no-dialogs")) { 559 JmriJOptionPane.showMessageDialog(null, 560 Bundle.getMessage(namesChanged > 1 ? "RouteManager.SystemNamesChanged.Message" : 561 "RouteManager.SystemNameChanged.Message", namesChanged), 562 Bundle.getMessage("Manager.SystemNamesChanged.Title", 563 namesChanged, tm.getBeanTypeHandled(namesChanged > 1)), 564 JmriJOptionPane.WARNING_MESSAGE); 565 } 566 log.warn("System names for {} Routes changed; this may have operational impacts.", namesChanged); 567 } 568 } 569 570 /** 571 * Replace the current RouteManager, if there is one, with one newly created 572 * during a load operation. This is skipped if the present one is already of 573 * the right type. 574 */ 575 protected void replaceRouteManager() { 576 RouteManager current = InstanceManager.getNullableDefault(RouteManager.class); 577 if (current != null && current.getClass().getName() 578 .equals(DefaultRouteManager.class.getName())) { 579 return; 580 } 581 // if old manager exists, remove it from configuration process 582 if (current != null) { 583 InstanceManager.getDefault(jmri.ConfigureManager.class).deregister(current); 584 InstanceManager.deregister(current, RouteManager.class); 585 } 586 587 // register new one with InstanceManager 588 DefaultRouteManager pManager = InstanceManager.getDefault(DefaultRouteManager.class); 589 InstanceManager.store(pManager, RouteManager.class); 590 // register new one for configuration 591 InstanceManager.getDefault(jmri.ConfigureManager.class).registerConfig(pManager, jmri.Manager.ROUTES); 592 } 593 594 @Override 595 public int loadOrder() { 596 return InstanceManager.getDefault(RouteManager.class).getXMLOrder(); 597 } 598 599 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultRouteManagerXml.class); 600 601}