/** * Copyright (c) 2015 Camil Staps * See the LICENSE file for copying permission. */ package com.camilstaps.shop; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Set; import java.util.regex.Pattern; /** * Executing commands and providing output, using a UserInteraction and acting * on a Database. * @author Camil Staps, s4498062 */ public class Shell { /** * The Database to work with */ private final Database database; /** * The UserInteraction to use */ private final UserInteraction ui; /** * The current User, if logged in */ private User user; public Shell(UserInteraction userInteraction) { this.database = Database.getInstance(); this.ui = userInteraction; } /** * Request commands, execute them, and show the results */ public void run() { while (true) { Command command = ui.getCommand(); try { Method method = getClass().getMethod("exec" + command.getCommand().substring(0,1).toUpperCase() + command.getCommand().substring(1)); method.invoke(this); if (command.getCommand().equalsIgnoreCase("exit")) { return; } } catch (NoSuchMethodException ex) { ui.putStringLn("Failure: no such command"); } catch (InvocationTargetException ex) { ui.putStringLn("Failure: " + ex.getCause().toString()); } catch (SecurityException | IllegalAccessException | IllegalArgumentException ex) { ui.putStringLn("Failure: unknown error"); } } } /** * Require that the visitor logs in * @throws com.camilstaps.shop.Shell.LoginRequiredException if the visitor fails to login * @throws ItemNotFoundException if the visitor tries to login with a non-existing User number */ public void requireLogin() throws LoginRequiredException, ItemNotFoundException { if (user == null) { ui.putStringLn("You must login first."); try { execLogin(); } catch (InputRequiredException ex) { } if (user == null) { throw new LoginRequiredException(); } } } /** * Require that an administrator is logged in * @throws com.camilstaps.shop.Shell.AdminRequiredException if the visitor fails to login, or is not an administrator * @throws ItemNotFoundException if the visitor tries to login with a non-existing User number */ public void requireAdmin() throws AdminRequiredException, ItemNotFoundException { if (user == null || !user.isAdmin()) { ui.putStringLn("You must login as an administrator first."); try { execLogin(); } catch (InputRequiredException ex) { } if (user == null || !user.isAdmin()) { throw new AdminRequiredException(); } } } /** * Command: add an article * @throws DuplicateEntryException * @throws InputRequiredException * @throws com.camilstaps.shop.Shell.LoginRequiredException * @throws ItemNotFoundException */ public void execAddArticle() throws DuplicateEntryException, InputRequiredException, LoginRequiredException, ItemNotFoundException { requireLogin(); String name = ui.getRequiredString("Name: "); Category category = ui.getCategory(); float price = ui.getFloat("Price: "); Article a = new Article(user, name, category, price); database.addItem(a); } /** * Command: set the article description * @throws com.camilstaps.shop.Shell.LoginRequiredException * @throws ItemNotFoundException * @throws InputRequiredException */ public void execSetArticleDescription() throws LoginRequiredException, ItemNotFoundException, InputRequiredException { requireLogin(); Article a; if (user.isAdmin()) { a = ui.getArticle(); } else { a = ui.getArticle(user); } a.setDescription(ui.getRequiredString("Description: ")); } /** * Command: set the multimedia linked to an article * @throws com.camilstaps.shop.Shell.LoginRequiredException * @throws ItemNotFoundException * @throws InputRequiredException */ public void execSetArticleMultimedia() throws LoginRequiredException, ItemNotFoundException, InputRequiredException { requireLogin(); Article a; if (user.isAdmin()) { a = ui.getArticle(); } else { a = ui.getArticle(user); } a.setMultimedia(new File(ui.getRequiredString("Multimedia: "))); } /** * Command: remove an article * @throws com.camilstaps.shop.Shell.LoginRequiredException * @throws ItemNotFoundException * @throws InputRequiredException */ public void execRemoveArticle() throws LoginRequiredException, ItemNotFoundException, InputRequiredException { requireLogin(); Article a; if (user.isAdmin()) { a = ui.getArticle(); } else { a = ui.getArticle(user); } database.removeItem(a); } /** * Command: show a list of articles */ public void execListArticles() { for (Article a : database.getArticles()) { ui.putStringLn(a.toString()); } } /** * Command: search for an article */ public void execSearchArticle() { String regex = ui.getString("Keywords: "); for (Article a : database.searchArticle(Pattern.compile(regex))) { ui.putStringLn(a.toString()); } } /** * Command: show detailed data about an article * @throws InputRequiredException * @throws ItemNotFoundException */ public void execShowArticle() throws InputRequiredException, ItemNotFoundException { Article a = ui.getArticle(); ui.putStringLn(a.toString()); if (a.getDescription() != null) { ui.putStringLn(a.getDescription()); } File multimedia = a.getMultimedia(); if (multimedia != null) { ui.putStringLn("Multimedia: " + multimedia.getPath()); } if (user != null && user.isAdmin()) { ui.putStringLn("User: " + a.getUser().toString(true)); } } /** * Command: add a category * @throws DuplicateEntryException * @throws InputRequiredException * @throws com.camilstaps.shop.Shell.AdminRequiredException * @throws ItemNotFoundException */ public void execAddCategory() throws DuplicateEntryException, InputRequiredException, AdminRequiredException, ItemNotFoundException { requireAdmin(); String name = ui.getRequiredString("Name: "); database.addItem(new Category(name)); } /** * Command: list categories */ public void execListCategories() { for (String c : database.getCategoryNames()) { ui.putStringLn(c); } } /** * Command: list users * Administrators see a more detailed list */ public void execListUsers() { for (User u : database.getUsers()) { ui.putStringLn(u.toString(user != null && user.isAdmin())); } } /** * Command: register a new user * @throws DuplicateEntryException * @throws InputRequiredException */ public void execRegister() throws DuplicateEntryException, InputRequiredException { boolean addAsAdmin = false; if (database.getUsers().isEmpty()) { addAsAdmin = true; ui.putStringLn("This is the first user and will therefore be added as administrator."); } else if (user != null && user.isAdmin()) { addAsAdmin = ui.getBoolean("Add user as administrator"); } String nr = ui.getRequiredString("Number: "); String email = ui.getRequiredString("Email: "); User u = new User(nr, email, addAsAdmin); String password = u.setRandomPassword(); ui.putStringLn("Password: " + password); database.addItem(u); } /** * Command: login * @throws InputRequiredException * @throws ItemNotFoundException */ public void execLogin() throws InputRequiredException, ItemNotFoundException { if (user != null) { ui.putStringLn("You are already logged in."); return; } User u = ui.getUser(); String pw = ui.getRequiredString("Password: "); if (!u.verify(pw)) { ui.putStringLn("Failed to login."); return; } if (u.isBlocked()) { ui.putStringLn("You are blocked."); return; } user = u; } /** * Command: logout */ public void execLogout() { user = null; } /** * Command: add an article to the cart * @throws com.camilstaps.shop.Shell.LoginRequiredException * @throws ItemNotFoundException * @throws InputRequiredException */ public void execAddToCart() throws LoginRequiredException, ItemNotFoundException, InputRequiredException { requireLogin(); user.getCart().add(ui.getArticle()); } /** * Command: remove an article from the cart * @throws com.camilstaps.shop.Shell.LoginRequiredException * @throws ItemNotFoundException */ public void execRemoveFromCart() throws LoginRequiredException, ItemNotFoundException { requireLogin(); user.getCart().remove(ui.getArticle(user.getCart().getArticles())); } /** * Command: list articles in the cart * @throws com.camilstaps.shop.Shell.LoginRequiredException * @throws ItemNotFoundException */ public void execListCart() throws LoginRequiredException, ItemNotFoundException { requireLogin(); for (Article a : user.getCart().getArticles()) { ui.putStringLn(a.toString()); } ui.putStringLn("Total value: " + user.getCart().getTotalAmount()); } /** * Command: remove all articles from the cart * @throws com.camilstaps.shop.Shell.LoginRequiredException * @throws ItemNotFoundException */ public void execClearCart() throws LoginRequiredException, ItemNotFoundException { requireLogin(); if (ui.getBoolean("Are you sure?")) user.getCart().reset(); } /** * Command: checkout (create an Order using the current Cart) * @throws ItemNotFoundException * @throws com.camilstaps.shop.Shell.LoginRequiredException * @throws DuplicateEntryException */ public void execCheckout() throws ItemNotFoundException, LoginRequiredException, DuplicateEntryException { requireLogin(); if (user.getCart().getArticles().isEmpty()) { throw new ItemNotFoundException(); } ui.putStringLn("By checking out, you agree to pay the total amount."); if (!ui.getBoolean("Do you agree?")) return; Order order = new Order(user); database.addItem(order); ui.putStringLn("Your order has been added as " + order.toString()); } /** * Command: list orders * @throws ItemNotFoundException * @throws com.camilstaps.shop.Shell.LoginRequiredException */ public void execListOrders() throws ItemNotFoundException, LoginRequiredException { requireLogin(); Set orders; if (user.isAdmin()) { orders = database.getOrders(); } else { orders = user.getOrders(); } for (Order o : orders) { ui.putStringLn(o.toString()); } } /** * Command: show detailed information about an order * @throws com.camilstaps.shop.Shell.LoginRequiredException * @throws ItemNotFoundException * @throws InputRequiredException */ public void execShowOrder() throws LoginRequiredException, ItemNotFoundException, InputRequiredException { requireLogin(); Order o; if (user.isAdmin()) { o = ui.getOrder(); } else { o = ui.getOrder(user); } ui.putStringLn(o.toString()); for (Article a : o.getArticles()) { ui.putStringLn(" " + a.toString()); } ui.putStringLn("Total amount: " + o.getTotalAmount()); ui.putStringLn("Paid: " + (o.isPaid() ? "yes" : "no")); } /** * Command: set the paid status of an Order to true * @throws com.camilstaps.shop.Shell.AdminRequiredException * @throws ItemNotFoundException * @throws InputRequiredException */ public void execSetOrderPaid() throws AdminRequiredException, ItemNotFoundException, InputRequiredException { requireAdmin(); ui.getOrder().setPaid(true); } /** * Command: block a user * @throws InputRequiredException * @throws ItemNotFoundException * @throws com.camilstaps.shop.Shell.AdminRequiredException */ public void execBlockUser() throws InputRequiredException, ItemNotFoundException, AdminRequiredException { requireAdmin(); ui.getUser().setBlocked(true); } /** * Command: unblock a user * @throws InputRequiredException * @throws ItemNotFoundException * @throws com.camilstaps.shop.Shell.AdminRequiredException */ public void execUnblockUser() throws InputRequiredException, ItemNotFoundException, AdminRequiredException { requireAdmin(); ui.getUser().setBlocked(false); } /** * Command: save the database */ public void execExit() { database.write(); } /** * This Exception is thrown when the visitor is required to login, but fails */ private class LoginRequiredException extends Exception { } /** * This Exception is thrown when the visitor is required to login as an administrator, but fails */ private class AdminRequiredException extends Exception { } }