001package jmri.jmrit.operations.rollingstock.cars; 002 003import java.beans.PropertyChangeEvent; 004import java.text.NumberFormat; 005import java.util.*; 006 007import org.jdom2.Element; 008import org.slf4j.Logger; 009import org.slf4j.LoggerFactory; 010 011import jmri.*; 012import jmri.jmrit.operations.locations.Track; 013import jmri.jmrit.operations.rollingstock.RollingStock; 014import jmri.jmrit.operations.rollingstock.RollingStockManager; 015import jmri.jmrit.operations.routes.Route; 016import jmri.jmrit.operations.routes.RouteLocation; 017import jmri.jmrit.operations.setup.OperationsSetupXml; 018import jmri.jmrit.operations.setup.Setup; 019import jmri.jmrit.operations.trains.Train; 020import jmri.jmrit.operations.trains.TrainManifestHeaderText; 021 022/** 023 * Manages the cars. 024 * 025 * @author Daniel Boudreau Copyright (C) 2008 026 */ 027public class CarManager extends RollingStockManager<Car> 028 implements InstanceManagerAutoDefault, InstanceManagerAutoInitialize { 029 030 public CarManager() { 031 } 032 033 /** 034 * Finds an existing Car or creates a new Car if needed requires car's road and 035 * number 036 * 037 * @param road car road 038 * @param number car number 039 * @return new car or existing Car 040 */ 041 @Override 042 public Car newRS(String road, String number) { 043 Car car = getByRoadAndNumber(road, number); 044 if (car == null) { 045 car = new Car(road, number); 046 register(car); 047 } 048 return car; 049 } 050 051 @Override 052 public void deregister(Car car) { 053 super.deregister(car); 054 InstanceManager.getDefault(CarManagerXml.class).setDirty(true); 055 } 056 057 /** 058 * Sort by rolling stock location 059 * 060 * @return list of cars ordered by the Car's location 061 */ 062 @Override 063 public List<Car> getByLocationList() { 064 List<Car> byFinal = getByList(getByNumberList(), BY_FINAL_DEST); 065 List<Car> byKernel = getByList(byFinal, BY_KERNEL); 066 return getByList(byKernel, BY_LOCATION); 067 } 068 069 /** 070 * Sort by car kernel names 071 * 072 * @return list of cars ordered by car kernel 073 */ 074 public List<Car> getByKernelList() { 075 return getByList(getByList(getByNumberList(), BY_BLOCKING), BY_KERNEL); 076 } 077 078 /** 079 * Sort by car loads 080 * 081 * @return list of cars ordered by car loads 082 */ 083 public List<Car> getByLoadList() { 084 return getByList(getByLocationList(), BY_LOAD); 085 } 086 087 /** 088 * Sort by car return when empty location and track 089 * 090 * @return list of cars ordered by car return when empty 091 */ 092 public List<Car> getByRweList() { 093 return getByList(getByLocationList(), BY_RWE); 094 } 095 096 public List<Car> getByRwlList() { 097 return getByList(getByLocationList(), BY_RWL); 098 } 099 100 public List<Car> getByRouteList() { 101 return getByList(getByLocationList(), BY_ROUTE); 102 } 103 104 public List<Car> getByDivisionList() { 105 return getByList(getByLocationList(), BY_DIVISION); 106 } 107 108 public List<Car> getByFinalDestinationList() { 109 return getByList(getByDestinationList(), BY_FINAL_DEST); 110 } 111 112 /** 113 * Sort by car wait count 114 * 115 * @return list of cars ordered by wait count 116 */ 117 public List<Car> getByWaitList() { 118 return getByList(getByIdList(), BY_WAIT); 119 } 120 121 public List<Car> getByPickupList() { 122 return getByList(getByDestinationList(), BY_PICKUP); 123 } 124 125 // The special sort options for cars 126 private static final int BY_LOAD = 30; 127 private static final int BY_KERNEL = 31; 128 private static final int BY_RWE = 32; // Return When Empty 129 private static final int BY_FINAL_DEST = 33; 130 private static final int BY_WAIT = 34; 131 private static final int BY_PICKUP = 35; 132 private static final int BY_HAZARD = 36; 133 private static final int BY_RWL = 37; // Return When loaded 134 private static final int BY_ROUTE = 38; 135 private static final int BY_DIVISION = 39; 136 137 // the name of the location and track is "split" 138 private static final int BY_SPLIT_FINAL_DEST = 40; 139 private static final int BY_SPLIT_LOCATION = 41; 140 private static final int BY_SPLIT_DESTINATION = 42; 141 142 // add car options to sort comparator 143 @Override 144 protected java.util.Comparator<Car> getComparator(int attribute) { 145 switch (attribute) { 146 case BY_LOAD: 147 return (c1, c2) -> (c1.getLoadName().compareToIgnoreCase(c2.getLoadName())); 148 case BY_KERNEL: 149 return (c1, c2) -> (c1.getKernelName().compareToIgnoreCase(c2.getKernelName())); 150 case BY_RWE: 151 return (c1, c2) -> (c1.getReturnWhenEmptyDestinationName() + c1.getReturnWhenEmptyDestTrackName()) 152 .compareToIgnoreCase( 153 c2.getReturnWhenEmptyDestinationName() + c2.getReturnWhenEmptyDestTrackName()); 154 case BY_RWL: 155 return (c1, c2) -> (c1.getReturnWhenLoadedDestinationName() + c1.getReturnWhenLoadedDestTrackName()) 156 .compareToIgnoreCase( 157 c2.getReturnWhenLoadedDestinationName() + c2.getReturnWhenLoadedDestTrackName()); 158 case BY_FINAL_DEST: 159 return (c1, c2) -> (c1.getFinalDestinationName() + c1.getFinalDestinationTrackName()) 160 .compareToIgnoreCase(c2.getFinalDestinationName() + c2.getFinalDestinationTrackName()); 161 case BY_ROUTE: 162 return (c1, c2) -> (c1.getRoutePath().compareToIgnoreCase(c2.getRoutePath())); 163 case BY_DIVISION: 164 return (c1, c2) -> (c1.getDivisionName().compareToIgnoreCase(c2.getDivisionName())); 165 case BY_WAIT: 166 return (c1, c2) -> (c1.getWait() - c2.getWait()); 167 case BY_PICKUP: 168 return (c1, c2) -> (c1.getPickupScheduleName().compareToIgnoreCase(c2.getPickupScheduleName())); 169 case BY_HAZARD: 170 return (c1, c2) -> ((c1.isHazardous() ? 1 : 0) - (c2.isHazardous() ? 1 : 0)); 171 case BY_SPLIT_FINAL_DEST: 172 return (c1, c2) -> (c1.getSplitFinalDestinationName() + c1.getSplitFinalDestinationTrackName()) 173 .compareToIgnoreCase( 174 c2.getSplitFinalDestinationName() + c2.getSplitFinalDestinationTrackName()); 175 case BY_SPLIT_LOCATION: 176 return (c1, c2) -> (c1.getStatus() + c1.getSplitLocationName() + c1.getSplitTrackName()) 177 .compareToIgnoreCase(c2.getStatus() + c2.getSplitLocationName() + c2.getSplitTrackName()); 178 case BY_SPLIT_DESTINATION: 179 return (c1, c2) -> (c1.getSplitDestinationName() + c1.getSplitDestinationTrackName()) 180 .compareToIgnoreCase(c2.getSplitDestinationName() + c2.getSplitDestinationTrackName()); 181 default: 182 return super.getComparator(attribute); 183 } 184 } 185 186 /** 187 * Return a list available cars (no assigned train or car already assigned 188 * to this train) on a route, cars are ordered least recently moved to most 189 * recently moved. Note that it is possible for a car to have a location, 190 * but no track assignment. 191 * 192 * @param train The Train to use. 193 * @return List of cars with no assigned train on a route 194 */ 195 public List<Car> getAvailableTrainList(Train train) { 196 List<Car> out = new ArrayList<>(); 197 Route route = train.getRoute(); 198 if (route == null) { 199 return out; 200 } 201 // get a list of locations served by this route 202 List<RouteLocation> routeList = route.getLocationsBySequenceList(); 203 // don't include Car at route destination 204 RouteLocation destination = null; 205 if (routeList.size() > 1) { 206 destination = routeList.get(routeList.size() - 1); 207 // However, if the destination is visited more than once, must 208 // include all cars 209 for (int i = 0; i < routeList.size() - 1; i++) { 210 if (destination.getName().equals(routeList.get(i).getName())) { 211 destination = null; // include cars at destination 212 break; 213 } 214 } 215 // pickup allowed at destination? Don't include cars in staging 216 if (destination != null && 217 destination.isPickUpAllowed() && 218 destination.getLocation() != null && 219 !destination.getLocation().isStaging()) { 220 destination = null; // include cars at destination 221 } 222 } 223 // get rolling stock by track priority, load priority and then by moves 224 List<Car> sortByPriority = sortByTrackPriority(sortByLoadPriority(getByMovesList())); 225 // now build list of available Car for this route 226 for (Car car : sortByPriority) { 227 // only use Car with a location 228 if (car.getLocation() == null) { 229 continue; 230 } 231 RouteLocation rl = route.getLastLocationByName(car.getLocationName()); 232 // get Car that don't have an assigned train, or the 233 // assigned train is this one 234 if (rl != null && rl != destination && (car.getTrain() == null || train.equals(car.getTrain()))) { 235 out.add(car); 236 } 237 } 238 return out; 239 } 240 241 // sorts the high priority cars to the start of the list 242 protected List<Car> sortByLoadPriority(List<Car> list) { 243 List<Car> out = new ArrayList<>(); 244 // move high priority cars to the start 245 for (Car car : list) { 246 if (car.getLoadPriority().equals(CarLoad.PRIORITY_HIGH)) { 247 out.add(car); 248 } 249 } 250 for (Car car : list) { 251 if (car.getLoadPriority().equals(CarLoad.PRIORITY_MEDIUM)) { 252 out.add(car); 253 } 254 } 255 // now load all of the remaining low priority cars 256 for (Car car : list) { 257 if (!out.contains(car)) { 258 out.add(car); 259 } 260 } 261 return out; 262 } 263 264 /** 265 * Provides a very sorted list of cars assigned to the train. Note that this 266 * isn't the final sort as the cars must be sorted by each location the 267 * train visits. 268 * <p> 269 * The sort priority is as follows: 270 * <ol> 271 * <li>Caboose or car with FRED to the end of the list, unless passenger. 272 * <li>Passenger cars have blocking numbers which places them relative to 273 * each other. Passenger cars with positive blocking numbers to the end of 274 * the list, but before cabooses or car with FRED. Passenger cars with 275 * negative blocking numbers are placed at the front of the train. 276 * <li>Car's destination (alphabetical by location and track name or by 277 * track blocking order) 278 * <li>Car is hazardous (hazardous placed after a non-hazardous car) 279 * <li>Car's current location (alphabetical by location and track name) 280 * <li>Car's final destination (alphabetical by location and track name) 281 * </ol> 282 * <p> 283 * Cars in a kernel are placed together by their kernel blocking numbers, 284 * except if they are type passenger. The kernel's position in the list is 285 * based on the lead car in the kernel. 286 * <p> 287 * If the train is to be blocked by track blocking order, all of the tracks 288 * at that location need a blocking number greater than 0. 289 * 290 * @param train The selected Train. 291 * @return Ordered list of cars assigned to the train 292 */ 293 public List<Car> getByTrainDestinationList(Train train) { 294 List<Car> byFinal = getByList(getList(train), BY_SPLIT_FINAL_DEST); 295 List<Car> byLocation = getByList(byFinal, BY_SPLIT_LOCATION); 296 List<Car> byHazard = getByList(byLocation, BY_HAZARD); 297 List<Car> byDestination = getByList(byHazard, BY_SPLIT_DESTINATION); 298 // now place cabooses, cars with FRED, and passenger cars at the rear of the 299 // train 300 List<Car> out = new ArrayList<>(); 301 int lastCarsIndex = 0; // incremented each time a car is added to the end of the list 302 for (Car car : byDestination) { 303 if (car.getKernel() != null && !car.isLead() && !car.isPassenger()) { 304 continue; // not the lead car, skip for now. 305 } 306 if (!car.isCaboose() && !car.hasFred() && !car.isPassenger()) { 307 // sort order based on train direction when serving track, low to high if West 308 // or North bound trains 309 if (car.getDestinationTrack() != null && car.getDestinationTrack().getBlockingOrder() > 0) { 310 for (int j = 0; j < out.size(); j++) { 311 if (out.get(j).getDestinationTrack() == null) { 312 continue; 313 } 314 if (car.getRouteDestination() != null && 315 (car.getRouteDestination().getTrainDirectionString().equals(RouteLocation.WEST_DIR) || 316 car.getRouteDestination().getTrainDirectionString() 317 .equals(RouteLocation.NORTH_DIR))) { 318 if (car.getDestinationTrack().getBlockingOrder() < out.get(j).getDestinationTrack() 319 .getBlockingOrder()) { 320 out.add(j, car); 321 break; 322 } 323 // Train is traveling East or South when setting out the car 324 } else { 325 if (car.getDestinationTrack().getBlockingOrder() > out.get(j).getDestinationTrack() 326 .getBlockingOrder()) { 327 out.add(j, car); 328 break; 329 } 330 } 331 } 332 } 333 if (!out.contains(car)) { 334 out.add(out.size() - lastCarsIndex, car); 335 } 336 } else if (car.isPassenger()) { 337 if (car.getBlocking() < 0) { 338 // block passenger cars with negative blocking numbers at 339 // front of train 340 int index; 341 for (index = 0; index < out.size(); index++) { 342 Car carTest = out.get(index); 343 if (!carTest.isPassenger() || carTest.getBlocking() > car.getBlocking()) { 344 break; 345 } 346 } 347 out.add(index, car); 348 } else { 349 // block passenger cars at end of list, but before cabooses 350 // or car with FRED 351 int index; 352 for (index = 0; index < lastCarsIndex; index++) { 353 Car carTest = out.get(out.size() - 1 - index); 354 log.debug("Car ({}) has blocking number: {}", carTest.toString(), carTest.getBlocking()); 355 if (carTest.isPassenger() && 356 !carTest.isCaboose() && 357 !carTest.hasFred() && 358 carTest.getBlocking() < car.getBlocking()) { 359 break; 360 } 361 } 362 out.add(out.size() - index, car); 363 lastCarsIndex++; 364 } 365 } else if (car.isCaboose() || car.hasFred()) { 366 out.add(car); // place at end of list 367 lastCarsIndex++; 368 } 369 // group the cars in the kernel together, except passenger 370 if (car.isLead()) { 371 int index = out.indexOf(car); 372 int numberOfCars = 1; // already added the lead car to the list 373 for (Car kcar : car.getKernel().getCars()) { 374 if (car != kcar && !kcar.isPassenger()) { 375 // Block cars in kernel 376 for (int j = 0; j < numberOfCars; j++) { 377 if (kcar.getBlocking() < out.get(index + j).getBlocking()) { 378 out.add(index + j, kcar); 379 break; 380 } 381 } 382 if (!out.contains(kcar)) { 383 out.add(index + numberOfCars, kcar); 384 } 385 numberOfCars++; 386 if (car.hasFred() || car.isCaboose() || car.isPassenger() && car.getBlocking() > 0) { 387 lastCarsIndex++; // place entire kernel at the end of list 388 } 389 } 390 } 391 } 392 } 393 return out; 394 } 395 396 /** 397 * Get a list of car road names where the car was flagged as a caboose. 398 * 399 * @return List of caboose road names. 400 */ 401 public List<String> getCabooseRoadNames() { 402 List<String> names = new ArrayList<>(); 403 Enumeration<String> en = _hashTable.keys(); 404 while (en.hasMoreElements()) { 405 Car car = getById(en.nextElement()); 406 if (car.isCaboose() && !names.contains(car.getRoadName())) { 407 names.add(car.getRoadName()); 408 } 409 } 410 java.util.Collections.sort(names); 411 return names; 412 } 413 414 /** 415 * Get a list of car road names where the car was flagged with FRED 416 * 417 * @return List of road names of cars with FREDs 418 */ 419 public List<String> getFredRoadNames() { 420 List<String> names = new ArrayList<>(); 421 Enumeration<String> en = _hashTable.keys(); 422 while (en.hasMoreElements()) { 423 Car car = getById(en.nextElement()); 424 if (car.hasFred() && !names.contains(car.getRoadName())) { 425 names.add(car.getRoadName()); 426 } 427 } 428 java.util.Collections.sort(names); 429 return names; 430 } 431 432 /** 433 * Replace car loads 434 * 435 * @param type type of car 436 * @param oldLoadName old load name 437 * @param newLoadName new load name 438 */ 439 public void replaceLoad(String type, String oldLoadName, String newLoadName) { 440 List<Car> cars = getList(); 441 for (Car car : cars) { 442 if (car.getTypeName().equals(type) && car.getLoadName().equals(oldLoadName)) { 443 if (newLoadName != null) { 444 car.setLoadName(newLoadName); 445 } else { 446 car.setLoadName(InstanceManager.getDefault(CarLoads.class).getDefaultEmptyName()); 447 } 448 } 449 if (car.getTypeName().equals(type) && car.getReturnWhenEmptyLoadName().equals(oldLoadName)) { 450 if (newLoadName != null) { 451 car.setReturnWhenEmptyLoadName(newLoadName); 452 } else { 453 car.setReturnWhenEmptyLoadName(InstanceManager.getDefault(CarLoads.class).getDefaultEmptyName()); 454 } 455 } 456 if (car.getTypeName().equals(type) && car.getReturnWhenLoadedLoadName().equals(oldLoadName)) { 457 if (newLoadName != null) { 458 car.setReturnWhenLoadedLoadName(newLoadName); 459 } else { 460 car.setReturnWhenLoadedLoadName(InstanceManager.getDefault(CarLoads.class).getDefaultLoadName()); 461 } 462 } 463 } 464 } 465 466 public List<Car> getCarsLocationUnknown() { 467 List<Car> mias = new ArrayList<>(); 468 for (Car car : getByIdList()) { 469 if (car.isLocationUnknown()) { 470 mias.add(car); // return unknown location car 471 } 472 } 473 return mias; 474 } 475 476 /** 477 * Determines a car's weight in ounces based on car's scale length 478 * 479 * @param carLength Car's scale length 480 * @return car's weight in ounces 481 * @throws NumberFormatException if length isn't a number 482 */ 483 public static String calculateCarWeight(String carLength) throws NumberFormatException { 484 double doubleCarLength = Double.parseDouble(carLength) * 12 / Setup.getScaleRatio(); 485 double doubleCarWeight = (Setup.getInitalWeight() + doubleCarLength * Setup.getAddWeight()) / 1000; 486 NumberFormat nf = NumberFormat.getNumberInstance(); 487 nf.setMaximumFractionDigits(1); 488 return nf.format(doubleCarWeight); // car weight in ounces. 489 } 490 491 /** 492 * Used to determine if any car has been assigned a division 493 * 494 * @return true if any car has been assigned a division, otherwise false 495 */ 496 public boolean isThereDivisions() { 497 for (Car car : getList()) { 498 if (car.getDivision() != null) { 499 return true; 500 } 501 } 502 return false; 503 } 504 505 /** 506 * Used to determine if there are clone cars. 507 * 508 * @return true if there are clone cars, otherwise false. 509 */ 510 public boolean isThereClones() { 511 for (Car car : getList()) { 512 if (car.isClone()) { 513 return true; 514 } 515 } 516 return false; 517 } 518 519 /** 520 * Creates a clone for the car, and clones if the car is part of a kernel. 521 * Note that a car have have multiple clones. 522 * 523 * @param car The car to clone 524 * @param track The destination track for the clones 525 * @param train The train transporting the clones 526 * @param startTime The date and time the clones were moved 527 * @return clone for this car 528 */ 529 public Car createClone(Car car, Track track, Train train, Date startTime) { 530 int cloneCreationOrder = getCloneCreationOrder(); 531 Car cloneCar = car.copy(); 532 cloneCar.setNumber(car.getNumber() + Car.CLONE + cloneCreationOrder); 533 cloneCar.setClone(true); 534 // register car before setting location so the car gets logged 535 register(cloneCar); 536 cloneCar.setLocation(car.getLocation(), car.getTrack(), RollingStock.FORCE); 537 // for reset 538 cloneCar.setPreviousFinalDestination(car.getPreviousFinalDestination()); 539 cloneCar.setPreviousFinalDestinationTrack(car.getPreviousFinalDestinationTrack()); 540 cloneCar.setPreviousScheduleId(car.getScheduleItemId()); 541 cloneCar.setLastRouteId(car.getLastRouteId()); 542 cloneCar.setMoves(car.getMoves()); 543 if (car.getKernel() != null) { 544 String kernelName = car.getKernelName() + Car.CLONE + cloneCreationOrder; 545 Kernel kernel = InstanceManager.getDefault(KernelManager.class).newKernel(kernelName); 546 cloneCar.setKernel(kernel); 547 for (Car kar : car.getKernel().getCars()) { 548 if (kar != car) { 549 Car nCar = kar.copy(); 550 nCar.setNumber(kar.getNumber() + Car.CLONE + cloneCreationOrder); 551 nCar.setClone(true); 552 nCar.setKernel(kernel); 553 nCar.setMoves(kar.getMoves()); 554 register(nCar); 555 nCar.setLocation(car.getLocation(), car.getTrack(), RollingStock.FORCE); 556 // for reset 557 nCar.setPreviousFinalDestination(car.getPreviousFinalDestination()); 558 nCar.setPreviousFinalDestinationTrack(car.getPreviousFinalDestinationTrack()); 559 // move car to new location for later pick up 560 kar.setLocation(track.getLocation(), track, RollingStock.FORCE); 561 kar.setLastTrain(train); 562 kar.setLastLocationId(car.getLocationId()); 563 kar.setLastTrackId(car.getTrackId()); 564 kar.setLastDate(startTime); 565 kar.setMoves(kar.getMoves() + 1); // bump count 566 kar.setCloneOrder(cloneCreationOrder); // for reset 567 } 568 } 569 } 570 // move car to new location for later pick up 571 car.setLocation(track.getLocation(), track, RollingStock.FORCE); 572 car.setLastTrain(train); 573 car.setLastLocationId(cloneCar.getLocationId()); 574 car.setLastTrackId(cloneCar.getTrackId()); 575 car.setLastRouteId(train.getRoute().getId()); 576 // this car was moved during the build process 577 car.setLastDate(startTime); 578 car.setMoves(car.getMoves() + 1); // bump count 579 car.setCloneOrder(cloneCreationOrder); // for reset 580 car.setDestination(null, null); 581 return cloneCar; 582 } 583 584 int _commentLength = 0; 585 586 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value="SLF4J_FORMAT_SHOULD_BE_CONST", 587 justification="I18N of Info Message") 588 public int getMaxCommentLength() { 589 if (_commentLength == 0) { 590 _commentLength = TrainManifestHeaderText.getStringHeader_Comment().length(); 591 String comment = ""; 592 Car carMax = null; 593 for (Car car : getList()) { 594 if (car.getComment().length() > _commentLength) { 595 _commentLength = car.getComment().length(); 596 comment = car.getComment(); 597 carMax = car; 598 } 599 } 600 if (carMax != null) { 601 log.info(Bundle.getMessage("InfoMaxComment", carMax.toString(), comment, _commentLength)); 602 } 603 } 604 return _commentLength; 605 } 606 607 public void load(Element root) { 608 if (root.getChild(Xml.CARS) != null) { 609 List<Element> eCars = root.getChild(Xml.CARS).getChildren(Xml.CAR); 610 log.debug("readFile sees {} cars", eCars.size()); 611 for (Element eCar : eCars) { 612 register(new Car(eCar)); 613 } 614 } 615 } 616 617 /** 618 * Create an XML element to represent this Entry. This member has to remain 619 * synchronized with the detailed DTD in operations-cars.dtd. 620 * 621 * @param root The common Element for operations-cars.dtd. 622 */ 623 public void store(Element root) { 624 // nothing to save under options 625 root.addContent(new Element(Xml.OPTIONS)); 626 627 Element values; 628 root.addContent(values = new Element(Xml.CARS)); 629 // add entries 630 List<Car> carList = getByIdList(); 631 for (Car rs : carList) { 632 Car car = rs; 633 values.addContent(car.store()); 634 } 635 } 636 637 protected void setDirtyAndFirePropertyChange(String p, Object old, Object n) { 638 // Set dirty 639 InstanceManager.getDefault(CarManagerXml.class).setDirty(true); 640 super.firePropertyChange(p, old, n); 641 } 642 643 @Override 644 public void propertyChange(PropertyChangeEvent evt) { 645 if (evt.getPropertyName().equals(Car.COMMENT_CHANGED_PROPERTY)) { 646 _commentLength = 0; 647 } 648 super.propertyChange(evt); 649 } 650 651 private final static Logger log = LoggerFactory.getLogger(CarManager.class); 652 653 @Override 654 public void initialize() { 655 InstanceManager.getDefault(OperationsSetupXml.class); // load setup 656 // create manager to load cars and their attributes 657 InstanceManager.getDefault(CarManagerXml.class); 658 } 659 660}