{"id":"libraries-and-tools-dao-ui","slug":"text-ui-over-a-dao","title":"A text UI over a DAO","text":"A DAO stores data; a user interface lets a person work with it. In module 25 a text UI read commands and called the program's logic. Here, the logic it calls is a DAO.\n\n### The UI gets its DAO\n\nThe UI class keeps the DAO in an instance variable whose type is the **interface**, and gets it, like the Scanner, through its constructor:\n\n```java\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        RecipeDao recipes = new InMemoryRecipeDao();\n        RecipeUi ui = new RecipeUi(recipes, new Scanner(System.in));\n        ui.start();\n    }\n}\n// ==== RecipeUi.java ====\nimport java.util.List;\nimport java.util.Scanner;\n\npublic class RecipeUi {\n    private RecipeDao recipes;\n    private Scanner scanner;\n\n    public RecipeUi(RecipeDao recipes, Scanner scanner) {\n        this.recipes = recipes;\n        this.scanner = scanner;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Bye\");\n                break;\n            }\n            if (command.equals(\"list\")) {\n                list();\n            } else if (command.equals(\"add\")) {\n                add();\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n\n    private void list() {\n        List<Recipe> all = this.recipes.list();\n        if (all.isEmpty()) {\n            System.out.println(\"No recipes yet\");\n        }\n        for (Recipe recipe : all) {\n            System.out.println(recipe);\n        }\n    }\n\n    private void add() {\n        String name = this.scanner.nextLine();\n        int minutes = Integer.valueOf(this.scanner.nextLine());\n        int id = this.recipes.add(name, minutes);\n        System.out.println(\"Saved as recipe \" + id);\n    }\n}\n// ==== RecipeDao.java ====\nimport java.util.List;\n\npublic interface RecipeDao {\n    List<Recipe> list();\n    int add(String name, int minutes);\n    Recipe findById(int id);\n}\n// ==== InMemoryRecipeDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRecipeDao implements RecipeDao {\n    private List<Recipe> recipes;\n    private int nextId;\n\n    public InMemoryRecipeDao() {\n        this.recipes = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<Recipe> list() {\n        return new ArrayList<>(this.recipes);\n    }\n\n    @Override\n    public int add(String name, int minutes) {\n        int id = this.nextId;\n        this.nextId++;\n        this.recipes.add(new Recipe(id, name, minutes));\n        return id;\n    }\n\n    @Override\n    public Recipe findById(int id) {\n        for (Recipe recipe : this.recipes) {\n            if (recipe.getId() == id) {\n                return recipe;\n            }\n        }\n        return null;\n    }\n}\n// ==== Recipe.java ====\npublic class Recipe {\n    private int id;\n    private String name;\n    private int minutes;\n\n    public Recipe(int id, String name, int minutes) {\n        this.id = id;\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getMinutes() {\n        return this.minutes;\n    }\n\n    @Override\n    public String toString() {\n        return \"#\" + this.id + \" \" + this.name + \", \" + this.minutes + \" min\";\n    }\n}\n```\n\n```input\nlist\nadd\nChickpea curry\n40\nadd\nHerb flatbread\n20\nlist\ncurry\nquit\n```\n\n```output\n> No recipes yet\n> Saved as recipe 1\n> Saved as recipe 2\n> #1 Chickpea curry, 40 min\n#2 Herb flatbread, 20 min\n> Unknown command: curry\n> Bye\n```\n\nAs in module 25, the program prints `> ` before reading each command, and the output doesn't show what was typed. A command that needs more, such as `add`, reads it from the next lines, without prompts of its own.\n\n### Who knows what\n\n- **The UI** reads commands and prints answers. It doesn't know whether the recipes are in a list, a file or a database: it only calls the methods of `RecipeDao`.\n- **The DAO** stores and finds recipes. It never reads input or prints anything.\n- **`main`** is the only place that names `InMemoryRecipeDao`. It picks the DAO and the Scanner and hands both to the UI.\n\nThat last point is what makes the split pay off. On your own computer, `main` could create a DAO that uses a database (step 4) and pass that one instead: `RecipeUi` wouldn't change a line. A test can do the opposite: fill a DAO in memory with exactly the recipes it needs, and give the UI a Scanner that reads a String (module 26):\n\n```java\nRecipeDao recipes = new InMemoryRecipeDao();\nrecipes.add(\"Chickpea curry\", 40);\nRecipeUi ui = new RecipeUi(recipes, new Scanner(\"list\\nquit\\n\"));\nui.start();\n```\n\nPassing an object the parts it needs, instead of letting it create them, is called **dependency injection**. Big frameworks do it automatically, but a constructor parameter is all it takes.\n","task":"Write the text UI of the bike repair queue in `QueueUi.java`. The DAO from step 2 is ready in the other files, and `main` creates both. In `start`, before reading each command, print `> ` with `print`. The commands:\n\n- `list` prints every job on a line of its own, or `The queue is empty` when there are none\n- `add` reads two more lines, the bike and the problem, adds the job and prints `Added job ` and its id\n- `quit` prints `Bye` and ends\n- anything else prints `Unknown command: ` and the command\n\n`QueueUi` uses only the DAO it's given. For the input shown, the program prints:\n\n```\n> The queue is empty\n> Added job 1\n> Added job 2\n> #1 red road bike: flat tire (waiting)\n#2 green cargo bike: squeaky brakes (waiting)\n> Unknown command: pump\n> Bye\n```\n","kind":"code","seed":"// ==== QueueUi.java ====\nimport java.util.Scanner;\n\npublic class QueueUi {\n    private RepairJobDao queue;\n    private Scanner scanner;\n\n    public QueueUi(RepairJobDao queue, Scanner scanner) {\n        this.queue = queue;\n        this.scanner = scanner;\n    }\n\n    public void start() {\n        // Write the command loop here.\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        QueueUi ui = new QueueUi(queue, new Scanner(System.in));\n        ui.start();\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n    boolean update(RepairJob job);\n    boolean remove(int id);\n}\n\n// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean update(RepairJob job) {\n        for (int i = 0; i < this.jobs.size(); i++) {\n            if (this.jobs.get(i).getId() == job.getId()) {\n                this.jobs.set(i, job);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean remove(int id) {\n        RepairJob job = findById(id);\n        if (job == null) {\n            return false;\n        }\n        this.jobs.remove(job);\n        return true;\n    }\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n","solution":"// ==== QueueUi.java ====\nimport java.util.List;\nimport java.util.Scanner;\n\npublic class QueueUi {\n    private RepairJobDao queue;\n    private Scanner scanner;\n\n    public QueueUi(RepairJobDao queue, Scanner scanner) {\n        this.queue = queue;\n        this.scanner = scanner;\n    }\n\n    public void start() {\n        // Write the command loop here.\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Bye\");\n                break;\n            }\n            if (command.equals(\"list\")) {\n                list();\n            } else if (command.equals(\"add\")) {\n                add();\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n\n    private void list() {\n        List<RepairJob> jobs = this.queue.list();\n        if (jobs.isEmpty()) {\n            System.out.println(\"The queue is empty\");\n        }\n        for (RepairJob job : jobs) {\n            System.out.println(job);\n        }\n    }\n\n    private void add() {\n        String bike = this.scanner.nextLine();\n        String problem = this.scanner.nextLine();\n        int id = this.queue.add(bike, problem);\n        System.out.println(\"Added job \" + id);\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        QueueUi ui = new QueueUi(queue, new Scanner(System.in));\n        ui.start();\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n    boolean update(RepairJob job);\n    boolean remove(int id);\n}\n\n// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean update(RepairJob job) {\n        for (int i = 0; i < this.jobs.size(); i++) {\n            if (this.jobs.get(i).getId() == job.getId()) {\n                this.jobs.set(i, job);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean remove(int id) {\n        RepairJob job = findById(id);\n        if (job == null) {\n            return false;\n        }\n        this.jobs.remove(job);\n        return true;\n    }\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n","hints":["Start from `RecipeUi`: `while (true)`, the prompt with `print`, one `nextLine()` for the command, `quit` with a `break`, and an `if` for each other command. A private method for each command keeps `start` short.","`list` asks `this.queue.list()` and checks `isEmpty()` first. `add` reads the bike and the problem with two more `nextLine()` calls and prints the id that `this.queue.add` returns."],"tests":[{"name":"Test 1","stdin":"list\nadd\nred road bike\nflat tire\nadd\ngreen cargo bike\nsqueaky brakes\nlist\npump\nquit\n","expect":"> The queue is empty\n> Added job 1\n> Added job 2\n> #1 red road bike: flat tire (waiting)\n#2 green cargo bike: squeaky brakes (waiting)\n> Unknown command: pump\n> Bye","hidden":false},{"name":"Test 2","stdin":"quit\n","expect":"> Bye","hidden":true},{"name":"Test 3","stdin":"add\nblue tandem\nloose chain\nList\nlist\nlist\nquit\n","expect":"> Added job 1\n> Unknown command: List\n> #1 blue tandem: loose chain (waiting)\n> #1 blue tandem: loose chain (waiting)\n> Bye","hidden":true},{"name":"Test 4","stdin":"","call":"RepairJobDao queue = new InMemoryRepairJobDao();\nqueue.add(\"silver e-bike\", \"dead light\");\nqueue.add(\"white racer\", \"bent fork\");\nqueue.remove(1);\nQueueUi ui = new QueueUi(queue, new Scanner(\"list\\nadd\\nblack fixie\\nworn saddle\\nlist\\nquit\\n\"));\nui.start();\n","expect":"> #2 white racer: bent fork (waiting)\n> Added job 3\n> #2 white racer: bent fork (waiting)\n#3 black fixie: worn saddle (waiting)\n> Bye","hidden":true}],"require":[{"pattern":"new\\s+InMemoryRepairJobDao","max":1,"message":"Only `main` creates the DAO. `QueueUi` uses the one it gets through its constructor, `this.queue`."}],"forbid":[],"more":[{"task":"When a bike is fixed, the mechanic marks its job as ready. Add the command `ready` to `QueueUi`: it reads one more line, a job's id. If there's no job with that id, it prints `No job ` and the id. Otherwise it stores the job again as ready, through the DAO's `update`, and prints `Job `, the id and ` is ready`.\n\nThe other commands stay as they are. For the input shown, the program prints:\n\n```\n> Added job 1\n> Added job 2\n> Job 2 is ready\n> No job 7\n> #1 red road bike: flat tire (waiting)\n#2 green cargo bike: squeaky brakes (ready)\n> Bye\n```\n","kind":"code","seed":"// ==== QueueUi.java ====\nimport java.util.List;\nimport java.util.Scanner;\n\npublic class QueueUi {\n    private RepairJobDao queue;\n    private Scanner scanner;\n\n    public QueueUi(RepairJobDao queue, Scanner scanner) {\n        this.queue = queue;\n        this.scanner = scanner;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Bye\");\n                break;\n            }\n            if (command.equals(\"list\")) {\n                list();\n            } else if (command.equals(\"add\")) {\n                add();\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n\n    private void list() {\n        List<RepairJob> jobs = this.queue.list();\n        if (jobs.isEmpty()) {\n            System.out.println(\"The queue is empty\");\n        }\n        for (RepairJob job : jobs) {\n            System.out.println(job);\n        }\n    }\n\n    private void add() {\n        String bike = this.scanner.nextLine();\n        String problem = this.scanner.nextLine();\n        int id = this.queue.add(bike, problem);\n        System.out.println(\"Added job \" + id);\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        QueueUi ui = new QueueUi(queue, new Scanner(System.in));\n        ui.start();\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n    boolean update(RepairJob job);\n    boolean remove(int id);\n}\n\n// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean update(RepairJob job) {\n        for (int i = 0; i < this.jobs.size(); i++) {\n            if (this.jobs.get(i).getId() == job.getId()) {\n                this.jobs.set(i, job);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean remove(int id) {\n        RepairJob job = findById(id);\n        if (job == null) {\n            return false;\n        }\n        this.jobs.remove(job);\n        return true;\n    }\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n","solution":"// ==== QueueUi.java ====\nimport java.util.List;\nimport java.util.Scanner;\n\npublic class QueueUi {\n    private RepairJobDao queue;\n    private Scanner scanner;\n\n    public QueueUi(RepairJobDao queue, Scanner scanner) {\n        this.queue = queue;\n        this.scanner = scanner;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Bye\");\n                break;\n            }\n            if (command.equals(\"list\")) {\n                list();\n            } else if (command.equals(\"add\")) {\n                add();\n            } else if (command.equals(\"ready\")) {\n                ready();\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n\n    private void list() {\n        List<RepairJob> jobs = this.queue.list();\n        if (jobs.isEmpty()) {\n            System.out.println(\"The queue is empty\");\n        }\n        for (RepairJob job : jobs) {\n            System.out.println(job);\n        }\n    }\n\n    private void add() {\n        String bike = this.scanner.nextLine();\n        String problem = this.scanner.nextLine();\n        int id = this.queue.add(bike, problem);\n        System.out.println(\"Added job \" + id);\n    }\n\n    private void ready() {\n        int id = Integer.valueOf(this.scanner.nextLine());\n        RepairJob job = this.queue.findById(id);\n        if (job == null) {\n            System.out.println(\"No job \" + id);\n            return;\n        }\n        this.queue.update(new RepairJob(id, job.getBike(), job.getProblem(), true));\n        System.out.println(\"Job \" + id + \" is ready\");\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        QueueUi ui = new QueueUi(queue, new Scanner(System.in));\n        ui.start();\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n    boolean update(RepairJob job);\n    boolean remove(int id);\n}\n\n// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean update(RepairJob job) {\n        for (int i = 0; i < this.jobs.size(); i++) {\n            if (this.jobs.get(i).getId() == job.getId()) {\n                this.jobs.set(i, job);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean remove(int id) {\n        RepairJob job = findById(id);\n        if (job == null) {\n            return false;\n        }\n        this.jobs.remove(job);\n        return true;\n    }\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n","hints":["Add an `else if` for `ready` that calls a new private method. It reads the id with `Integer.valueOf(this.scanner.nextLine())` and asks `this.queue.findById(id)`.","When the job is there, make `new RepairJob(id, job.getBike(), job.getProblem(), true)` and give it to `this.queue.update(...)`: the DAO's stored job changes only through the DAO."],"tests":[{"name":"Test 1","stdin":"add\nred road bike\nflat tire\nadd\ngreen cargo bike\nsqueaky brakes\nready\n2\nready\n7\nlist\nquit\n","expect":"> Added job 1\n> Added job 2\n> Job 2 is ready\n> No job 7\n> #1 red road bike: flat tire (waiting)\n#2 green cargo bike: squeaky brakes (ready)\n> Bye","hidden":false},{"name":"Test 2","stdin":"ready\n1\nlist\nquit\n","expect":"> No job 1\n> The queue is empty\n> Bye","hidden":true},{"name":"Test 3","stdin":"","call":"RepairJobDao queue = new InMemoryRepairJobDao();\nqueue.add(\"silver e-bike\", \"dead light\");\nqueue.add(\"white racer\", \"bent fork\");\nqueue.add(\"blue tandem\", \"loose chain\");\nQueueUi ui = new QueueUi(queue, new Scanner(\"ready\\n3\\nready\\n3\\nready\\n1\\nfix\\nquit\\n\"));\nui.start();\nSystem.out.println(queue.list());\n","expect":"> Job 3 is ready\n> Job 3 is ready\n> Job 1 is ready\n> Unknown command: fix\n> Bye\n[#1 silver e-bike: dead light (ready), #2 white racer: bent fork (waiting), #3 blue tandem: loose chain (ready)]","hidden":true}],"require":[],"forbid":[]},{"task":"Two more commands for `QueueUi`:\n\n- `remove` reads a job's id from the next line and removes that job through the DAO. It prints `Removed job ` and the id, or `No job ` and the id when there's none.\n- `next` prints `Next: ` and the first job in the list that isn't ready yet, or `Nothing is waiting` when every job is ready (or there are none).\n\nThe other commands, `ready` too, stay as they are. For the input shown, the program prints:\n\n```\n> Added job 1\n> Added job 2\n> Job 1 is ready\n> Next: #2 green cargo bike: squeaky brakes (waiting)\n> Removed job 2\n> No job 2\n> Nothing is waiting\n> Bye\n```\n","kind":"code","seed":"// ==== QueueUi.java ====\nimport java.util.List;\nimport java.util.Scanner;\n\npublic class QueueUi {\n    private RepairJobDao queue;\n    private Scanner scanner;\n\n    public QueueUi(RepairJobDao queue, Scanner scanner) {\n        this.queue = queue;\n        this.scanner = scanner;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Bye\");\n                break;\n            }\n            if (command.equals(\"list\")) {\n                list();\n            } else if (command.equals(\"add\")) {\n                add();\n            } else if (command.equals(\"ready\")) {\n                ready();\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n\n    private void list() {\n        List<RepairJob> jobs = this.queue.list();\n        if (jobs.isEmpty()) {\n            System.out.println(\"The queue is empty\");\n        }\n        for (RepairJob job : jobs) {\n            System.out.println(job);\n        }\n    }\n\n    private void add() {\n        String bike = this.scanner.nextLine();\n        String problem = this.scanner.nextLine();\n        int id = this.queue.add(bike, problem);\n        System.out.println(\"Added job \" + id);\n    }\n\n    private void ready() {\n        int id = Integer.valueOf(this.scanner.nextLine());\n        RepairJob job = this.queue.findById(id);\n        if (job == null) {\n            System.out.println(\"No job \" + id);\n            return;\n        }\n        this.queue.update(new RepairJob(id, job.getBike(), job.getProblem(), true));\n        System.out.println(\"Job \" + id + \" is ready\");\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        QueueUi ui = new QueueUi(queue, new Scanner(System.in));\n        ui.start();\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n    boolean update(RepairJob job);\n    boolean remove(int id);\n}\n\n// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean update(RepairJob job) {\n        for (int i = 0; i < this.jobs.size(); i++) {\n            if (this.jobs.get(i).getId() == job.getId()) {\n                this.jobs.set(i, job);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean remove(int id) {\n        RepairJob job = findById(id);\n        if (job == null) {\n            return false;\n        }\n        this.jobs.remove(job);\n        return true;\n    }\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n","solution":"// ==== QueueUi.java ====\nimport java.util.List;\nimport java.util.Scanner;\n\npublic class QueueUi {\n    private RepairJobDao queue;\n    private Scanner scanner;\n\n    public QueueUi(RepairJobDao queue, Scanner scanner) {\n        this.queue = queue;\n        this.scanner = scanner;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Bye\");\n                break;\n            }\n            if (command.equals(\"list\")) {\n                list();\n            } else if (command.equals(\"add\")) {\n                add();\n            } else if (command.equals(\"ready\")) {\n                ready();\n            } else if (command.equals(\"remove\")) {\n                remove();\n            } else if (command.equals(\"next\")) {\n                next();\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n\n    private void list() {\n        List<RepairJob> jobs = this.queue.list();\n        if (jobs.isEmpty()) {\n            System.out.println(\"The queue is empty\");\n        }\n        for (RepairJob job : jobs) {\n            System.out.println(job);\n        }\n    }\n\n    private void add() {\n        String bike = this.scanner.nextLine();\n        String problem = this.scanner.nextLine();\n        int id = this.queue.add(bike, problem);\n        System.out.println(\"Added job \" + id);\n    }\n\n    private void ready() {\n        int id = Integer.valueOf(this.scanner.nextLine());\n        RepairJob job = this.queue.findById(id);\n        if (job == null) {\n            System.out.println(\"No job \" + id);\n            return;\n        }\n        this.queue.update(new RepairJob(id, job.getBike(), job.getProblem(), true));\n        System.out.println(\"Job \" + id + \" is ready\");\n    }\n\n    private void remove() {\n        int id = Integer.valueOf(this.scanner.nextLine());\n        if (this.queue.remove(id)) {\n            System.out.println(\"Removed job \" + id);\n        } else {\n            System.out.println(\"No job \" + id);\n        }\n    }\n\n    private void next() {\n        for (RepairJob job : this.queue.list()) {\n            if (!job.isReady()) {\n                System.out.println(\"Next: \" + job);\n                return;\n            }\n        }\n        System.out.println(\"Nothing is waiting\");\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        QueueUi ui = new QueueUi(queue, new Scanner(System.in));\n        ui.start();\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n    boolean update(RepairJob job);\n    boolean remove(int id);\n}\n\n// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean update(RepairJob job) {\n        for (int i = 0; i < this.jobs.size(); i++) {\n            if (this.jobs.get(i).getId() == job.getId()) {\n                this.jobs.set(i, job);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean remove(int id) {\n        RepairJob job = findById(id);\n        if (job == null) {\n            return false;\n        }\n        this.jobs.remove(job);\n        return true;\n    }\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n","hints":["`remove` is like `ready`: read the id, then let the DAO do the work. Its `remove(id)` already returns whether the job was there.","For `next`, go through `this.queue.list()` with a for-each loop and print the first job whose `isReady()` is false, then `return`. After the loop, nothing was waiting."],"tests":[{"name":"Test 1","stdin":"add\nred road bike\nflat tire\nadd\ngreen cargo bike\nsqueaky brakes\nready\n1\nnext\nremove\n2\nremove\n2\nnext\nquit\n","expect":"> Added job 1\n> Added job 2\n> Job 1 is ready\n> Next: #2 green cargo bike: squeaky brakes (waiting)\n> Removed job 2\n> No job 2\n> Nothing is waiting\n> Bye","hidden":false},{"name":"Test 2","stdin":"next\nremove\n1\nquit\n","expect":"> Nothing is waiting\n> No job 1\n> Bye","hidden":true},{"name":"Test 3","stdin":"","call":"RepairJobDao queue = new InMemoryRepairJobDao();\nqueue.add(\"silver e-bike\", \"dead light\");\nqueue.add(\"white racer\", \"bent fork\");\nqueue.add(\"blue tandem\", \"loose chain\");\nqueue.update(new RepairJob(1, \"silver e-bike\", \"dead light\", true));\nQueueUi ui = new QueueUi(queue, new Scanner(\"next\\nremove\\n2\\nnext\\nlist\\nquit\\n\"));\nui.start();\n","expect":"> Next: #2 white racer: bent fork (waiting)\n> Removed job 2\n> Next: #3 blue tandem: loose chain (waiting)\n> #1 silver e-bike: dead light (ready)\n#3 blue tandem: loose chain (waiting)\n> Bye","hidden":true}],"require":[],"forbid":[]}]}