// RoadNetwork.java /** Road network simulator (or it will become one once it's done) * @author Douglas W. Jones * @version Feb. 17, 2021 */ import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; import java.util.Collection; import java.util.LinkedList; /** Centralized error reporting tools * error reports are output to System.err (standard error, aka stderr) */ class Error { /** Fatal error * @param msg -- the warning message * this never returns, the application is terminated abnormally */ public static void fatal( String msg ) { System.err.println( "Error: " + msg ); System.exit( 1 ); // report failure to the OS (or to the shell) } /** Non-fatal warning * @param msg -- the warning message */ public static void warn( String msg ) { System.err.println( "Warning: " + msg ); } } class Road { Intersection source; // road from here Intersection destination; // road to there double travelTime; // time in seconds public Road( Scanner in ) { String srcname; // name of source intersection String dstname; // name of destination intersection if (in.hasNext()) { srcname = in.next(); } else { Error.warn( "road: source missing" ); srcname = "???"; } if (in.hasNext()) { dstname = in.next(); } else { Error.warn( "road " + srcname + ": destination missing" ); dstname = "???"; } if (in.hasNextFloat()) { travelTime = in.nextFloat(); } else { Error.warn( "road " + srcname + " " + dstname + ": travel time missing" ); travelTime = 99999.9F; } // BUG: What about time units? if (in.hasNext( ";" )) { in.next( ";" ); } else { Error.warn( "road " + srcname + " " + dstname + " " + travelTime + ": semicolon missing" ); } if (travelTime <= 0.0F) { Error.warn( "road " + srcname + " " + dstname + " " + travelTime + ": negative travel time?" ); travelTime = 99999.9F; } // look up the source and destination intersections source = Intersection.lookup( srcname ); if (source == null) { Error.warn( "road " + srcname + " " + dstname + " " + travelTime + ": undefined source intersection?" ); } destination = Intersection.lookup( dstname ); if (destination == null) { Error.warn( "road " + srcname + " " + dstname + " " + travelTime + ": undefined destination intersection?" ); } } // BUG: need to add behavior for roads } class Intersection { // instance variables of each intersection // BUG: is collection the right class? Should I pick a subclass? Collection incoming; // the roads leading here Collection outgoing; // the roads that come from here double traversalTime; // time in seconds String name; // the name of the intersection // static data about all the intersections private static LinkedList allInts = new LinkedList<>(); public Intersection( Scanner in ) { if (in.hasNext()) { name = in.next(); } else { Error.warn( "intersection: name missing" ); name = "???"; } if (in.hasNextFloat()) { traversalTime = in.nextFloat(); } else { Error.warn( "intersection" + name + ": traversal time missing" ); traversalTime = 99999.9F; } // BUG: What about time units? if (in.hasNext( ";" )) { in.next( ";" ); } else { Error.warn( "intersection " + name + " " + traversalTime + ": semicolon missing" ); } if (lookup( name ) != null) { Error.warn( "intersection " + name + " " + traversalTime + ": name redefined?" ); // BUG: anything else to do in this case? } allInts.add( this ); } // BUG: need to add behavior for intersections /** look up an interseciton by name * @param name -- the textual name of the intersetion * @return the Intersection object or null if there is none */ public static Intersection lookup( String name ) { for (Intersection i: allInts) if (i.name.equals( name )) return i; return null; } } public class RoadNetwork { /** build a road network model by scanning an input file * @param in -- the scanner used to read the file * Input file contains keywords road and intersection, * details beyond that are handled by the appropriate classes */ private static void buildModel( Scanner in ) { while (in.hasNext()) { String keyword = in.next(); if ("intersection".equals( keyword )) { new Intersection( in ); } else if ("road".equals( keyword )) { new Road( in ); } else { Error.warn( "not a keyword in the input: " + keyword ); } } } /** main method mostly concerned with command line arguments * @param args -- the command line arguments * Want just one argument, the file name for model description */ public static void main( String[] args ) { // arg[0] should be the name of a file describing a road network if (args.length < 1) { Error.fatal( "missing command line argument, a file name" ); } if (args.length > 1) { Error.warn( "extra command line argument: " + args[1] ); } try { buildModel( new Scanner( new File( args[0] ) ) ); // BUG: simulate the network that was built } catch ( FileNotFoundException e ) { Error.fatal( "could not open file: " + args[0] ); } } }