CS110 Lecture 17 Thursday, April 1, 2004 • Announcements – hw7 due tonight – pass/fail, withdraw deadline April 8 • Agenda – Questions – Juno – JFile system internals next week Lecture 17 1 Juno (Chapters 6, 7, ...) • We have a (J)File system • Now we provide it with a command line interface, like the one the emacs shell or a command prompt gives you to windows • Use that interface to – create TextFiles and Directories – navigate in the Directory tree Lecture 17 2 Command prompt interface to windows file system Lecture 17 3 Lecture 17 4 Juno (Chapters 6, 7, ...) • Simulates (models) that command line interface • “Juno” etymology: “Juno’s Unix not” (developed under Unix) • Juno UI: nested do forever loops – login: login as user, register, help, exit – mars:\users\eb> help, logout, mkdir, newfile, type ... cd, dir (various shell commands ) • Like Bank – banker command: customer, open, report, exit – transaction: deposit, withdraw, …, quit, Lecture 17 5 Sample Juno session Lecture 17 6 Juno classes Lecture 17 7 Juno.java (version 6) • fields (attributes of a Juno operating system) – Map for users (line 30) – Terminal for console (line 31) – Directories: slash, userHomes (lines 33, 34) – ShellCommandTable (line 36) • main() – parse command line arguments (175-186) – create a Juno object (190) Lecture 17 8 Juno constructor (45) • • • • new Terminal for console (line50) new Map for users (line 51) new table for ShellCommands (52) file system and system administrator – lines 56-59 – read them next week • create LoginInterpreter object to respond to user’s commands (64, 65) • send it a CLIlogin message (66) Lecture 17 9 LoginInterpreter • The object that listens for user responses to the login: prompt public void CLIlogin( ) { // (line 55) welcome(); boolean moreWork = true; while( moreWork ) { moreWork = interpret( console.readLine("Juno login: " )); } } read a line from the console, interpret it, loop until interpret returns false Lecture 17 10 interpret (line 69) • break command line into tokens (next slide) • put first token into String variable visitor (77) • use if - else if - else if … logic – – – – if “exit” return false! // leave loop in CLIlogin if “register” // create account for new user if “help” // give help else // input is a username • look up User object in map, with username as key • create a command shell for that User Lecture 17 11 StringTokenizer • Juno user might type Juno login: register bill Bill Campbell • We need to cut the blue String up into words • Like an Iterator StringTokenizer st = new StringTokenizer(“register bill B C”); while (st.hasMoreTokens()) System.out.println(“|”+st.nextToken()+“|”); produces |register| |bill| |B| |C| Lecture 17 12 StringTokenizer • Can change default (whitespace) delimiters StringTokenizer st = new S…T…(“x.b b*z”,“.*,”); while (st.hasMoreTokens()) System.out.println(st.nextToken()); produces x b b z • Can change delimiters dynamically - for no delimiters at all use st.nextToken(“”) Lecture 17 13 “register bill Bill Campbell” • LoginInterpreter lines 72, 73: create a StringTokenizer st for this String • Line 74 checks for no tokens (blank line) • Line 77 gets the first token for the value of the variable visitor - in this case “register” • Test on 81is true so line 82 sends this LoginInterpreter a register message, passing it the rest of the StringTokenizer Lecture 17 14 register (line 100) • Next token is userName bill • Get next token using no delimiters at all - so the rest of the line. Send that String a trim message to strip off white space at beginning and end • Create a new Directory with no owner • Create a new User • Arrange for him to own his home Directory Lecture 17 15 back to interpret • In most common case, response to Juno login prompt is a Juno username • Then that’s the first (and only) token on the line, hence the value of the variable visitor • Then interpret method – (88) looks up User object in map, with value of visitor String as key – (89) creates a command shell for that User Lecture 17 16 Shell object • Constructor sets some fields – the Juno system that created this Shell (37) (like issuing Bank in BankAccount) – the User and the console (38, 39) – the current Directory (the User’s home) (40) • Then invokes CLIShell (command line interface) which works just like LoginInterpreter – get an input line from the user (50) – invoke this Shell’s interpret method – done when interpret returns false for moreWork (user has typed “logout”) Lecture 17 17 Shell interpret method (60) • Create a StringTokenizer for the input line, after throwing away Juno comments (# …) • First token is the commandName (66) • If it’s “logout”, then done (return false) • Replace if else if … with dispatch table – (70,71) look up commandObject in command table (commandName String is key) – (76) send commandObject a doIt() message • Polymorphism! Lecture 17 18 abstract class ShellCommand • Documentation managed here – helpString and argstring fields (19, 20) – initialized by protected constructor (31, 32) • doIt() method (54): • abstract public void doIt ( StringTokenizer args, Shell sh ); • doIt is passed the rest of the text on the Juno command line, and the Shell it’s acting for • Each concrete ShellCommand implements its own doIt() - polymorphism Lecture 17 19 Creating a ShellCommand object • MkdirCommand extends ShellCommand (18) • Constructor (24) – super invokes ShellCommand constructor, telling it help string and argument string for mkdir • implement abstract method doIt (37) – next token on line is the name of the Directory to be made – tell Directory constructor the name, owner, parent – Directory constructor adds the new Directory to the parent public void doIt( StringTokenizer args, Shell sh ) { String filename = args.nextToken(); new Directory(filename, sh.getUser(), sh.getDot()); } Lecture 17 20 ShellCommandTable • Juno constructor creates a ShellCommandTable (Juno.java line 52) • ShellCommandTable.java – declare and initialize a TreeMap (line 23) – constructor (line 31) invokes fillTable (line 69) – fillTable creates one of each concrete ShellCommand objects, invokes install (line 61) to put it in the table – client (a Shell) invokes lookup (43), which wraps Map get method (and does the cast) Lecture 17 21 How the dispatch table works In CLIShell loop: – get first token on the line: commandName – lookup commandObject with commandName key – send doIt() message • Each particular ShellCommand extends the abstract ShellCommand class, implementing doIt() in its own way • Polymorphism at work Lecture 17 22 How LoginInterpreter interpret works • get first token on the line • use if - else if - else if … logic – – – – if “exit” return false! // leave loop in CLIlogin if “register” // create account for new user if “help” // give help else // input is a username Lecture 17 23 Dispatch table vs if-else if-else if • To add new commands just add a table entry • Command semantics separate from syntax • Lots of design overhead, hard to understand • Good for large command sets that will grow (Juno shell commands) • To add new commands must edit the main loop • Command semantics and syntax in same place • Quick and dirty, easy to understand and code • Good for small command sets that stay put (Juno login loop) Lecture 17 24