/* RoadNetwork.java * Program to process description of a road network * author Douglas W. Jones * version 2017-09-14 */ import java.util.LinkedList; import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; /** Error reporting package * provides standard prefix and behavior for messages */ class Errors { /** Report nonfatal errors, output a message and return * @arg message the message to output */ public static void warn( String message ) { System.err.println( "RoadNetwork: " + message ); } /** Report fatal errors, output a message and exit, never to return * @arg message the message to output */ public static void fatal( String message ) { warn( message ); System.exit( 1 ); } } /** Roads are joined by Intersections and driven over by Vehicles * @see Intersection */ class Road { float travelTime; // measured in seconds Intersection destination; // where this road goes Intersection source; // where this road comes from // name of a road is source-destination /** construct a new road by scanning its description from the source file */ Road( Scanner sc ) { // Bug: Can we prevent creation of a faulty road? String sourceName = sc.next(); String dstName = sc.next(); source = RoadNetwork.findIntersection( sourceName ); destination = RoadNetwork.findIntersection( dstName ); if (source == null) { Errors.warn( "No such source intersection: Road " + sourceName + dstName ); // Bug: Can we prevent creation of a faulty road? } if (destination == null) { Errors.warn( "No such destination intersection: Road " + sourceName + dstName ); // Bug: Can we prevent creation of a faulty road? } if (sc.hasNextFloat()) { travelTime = sc.nextFloat(); // Bug: Ought to complain about negative tavel times } else { Errors.warn( "Floating point argument expected: Road " + sourceName + " " + dstName ); // Bug: An obviously wrong value? travelTime = 99999.0F; } String skip = sc.nextLine(); } /** output the road in a form like that used for input */ public String toString() { // Bug: Can source be null for a badly constructed road? // Bug: Can destination be null for a badly constructed road? // Bug: Can the name fields be null for either intersection? return "road " + source.name + " " + destination.name + " " + travelTime; } } /** Intersections pass Vehicles between Roads * @see Road */ class Intersection { public String name; // textual name of intersection, never null! LinkedList outgoing; // set of all roads out of this intersection LinkedList incoming; // set of all roads in to this intersection // Bug: Is incoming really needed? // Bug: When are the above ever set to anything? Intersection( Scanner sc ) { name = sc.next(); // Bug: what if name = null because there was no next if (RoadNetwork.findIntersection( name ) != null) { Errors.warn( "Intersection redefined: " + name ); // Bug: Can we prevent creation of a faulty intersection? } // Bug: Finish scan of description of an intersection and create it } /** output the intersection in a form like that used for input */ public String toString() { // Bug: Can name be null because of a bad definition? return "intersection " + name; } } /** Vehicles drive over Roads between Intersections * @see Road * @see Intersection */ class Vehicle { // Bug: what are the attributes of a vehicle? // Bug: do vehicles need to know where they are? } public class RoadNetwork { /* the sets of all roads and all intersections */ private static LinkedList roads = new LinkedList (); private static LinkedList inters = new LinkedList (); /** Find an intersection by textual name in the set inters * @param s name of an intersection * @return the intersection named s or null if none */ public static Intersection findIntersection( String s ) { // quick and dirty implementation for (Intersection i: inters) { if (i.name.equals( s )) { return i; } } return null; } /** Initialize this road network by scanning its description */ private static void readNetwork( Scanner sc ) { while (sc.hasNext()) { String command = sc.next(); if ("intersection".equals( command )) { inters.add( new Intersection( sc ) ); } else if ("road".equals( command )) { roads.add( new Road( sc ) ); } else if ("--".equals( command )) { sc.nextLine(); } else { Errors.warn( "unknown command: " + command ); sc.nextLine(); } } } /** Print out the road network to system.out */ private static void printNetwork() { for (Intersection i: inters) { System.out.println( i.toString() ); } for (Road r: roads) { System.out.println( r.toString() ); } } /** Main program */ public static void main( String[] args ) { if (args.length < 1) { Errors.fatal( "Missing file name argument" ); } else if (args.length > 1) { Errors.fatal( "Too many arguments" ); } else try { readNetwork( new Scanner( new File( args[0] ) ) ); printNetwork(); } catch (FileNotFoundException e) { Errors.fatal( "Can't open the file" ); } } }