├── .idea ├── .name ├── .gitignore ├── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── vcs.xml ├── compiler.xml ├── misc.xml ├── gradle.xml ├── runConfigurations │ └── JunitTests.xml ├── jarRepositories.xml └── uiDesigner.xml ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── crcCards ├── Constants.txt ├── Find.txt ├── PathHandler.txt ├── Tree.txt ├── Exit.txt ├── History.txt ├── Man.txt ├── CommandExecutor.txt ├── GetURL.txt ├── JShellState.txt ├── Mv.txt ├── Redirection ├── cp.txt ├── CommandDecorator ├── CommandReader.txt ├── Ls.txt ├── Pwd.txt ├── JShell.txt ├── File.txt ├── Mkdir.txt ├── FileSystemObject.txt ├── Cat.txt ├── RecursiveDecorator.txt ├── Cd.txt ├── Pushd.txt ├── Directory.txt ├── Popd.txt ├── Echo.txt ├── Command.txt └── readMeForCrcCards.txt ├── src ├── main │ └── java │ │ ├── constants │ │ ├── CommandException.java │ │ ├── Exceptions.java │ │ └── Constants.java │ │ ├── commands │ │ ├── RecursiveInterface.java │ │ ├── Exit.java │ │ ├── Echo.java │ │ ├── Pwd.java │ │ ├── Tree.java │ │ ├── Mv.java │ │ ├── Cd.java │ │ ├── Cp.java │ │ ├── Pushd.java │ │ ├── Command.java │ │ ├── Popd.java │ │ ├── Man.java │ │ ├── Cat.java │ │ ├── Save.java │ │ ├── History.java │ │ ├── Get.java │ │ ├── Mkdir.java │ │ ├── Find.java │ │ ├── Load.java │ │ ├── CommandController.java │ │ ├── CommandReader.java │ │ └── Ls.java │ │ ├── command_decorators │ │ ├── CommandDecorator.java │ │ ├── RecursiveDecorator.java │ │ └── Redirection.java │ │ ├── helper_classes │ │ ├── CmdArgTuple.java │ │ ├── DirectoryFileNameTuple.java │ │ ├── StringHelper.java │ │ └── PathHandler.java │ │ ├── driver │ │ ├── IShellState.java │ │ ├── JShell.java │ │ └── JShellState.java │ │ └── file_system │ │ ├── File.java │ │ ├── FileSystemObject.java │ │ ├── VirtualFileSystem.java │ │ └── Directory.java └── test │ └── java │ └── commands │ └── MkdirTest.java ├── README.md ├── LICENSE ├── gradlew.bat └── gradlew /.idea/.name: -------------------------------------------------------------------------------- 1 | JavaShell -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'JavaShell' 2 | 3 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CSC207-UofT/Java-Shell/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /crcCards/Constants.txt: -------------------------------------------------------------------------------- 1 | Class name: Constants 2 | 3 | Responsibilities: 4 | * Holds program constants 5 | 6 | Collaborators: 7 | -------------------------------------------------------------------------------- /crcCards/Find.txt: -------------------------------------------------------------------------------- 1 | Class name: find 2 | 3 | Responsibilities: 4 | * Finds a specific file or directory 5 | 6 | Collaborators: 7 | * JShell 8 | -------------------------------------------------------------------------------- /crcCards/PathHandler.txt: -------------------------------------------------------------------------------- 1 | Class name: PathHandler 2 | 3 | Responsibilities: 4 | * Handles path input 5 | 6 | Collaborators: 7 | * FileSystemObject 8 | -------------------------------------------------------------------------------- /crcCards/Tree.txt: -------------------------------------------------------------------------------- 1 | Class name: tree 2 | 3 | Responsibilities: 4 | * Displays the entire filesystem as a tree 5 | 6 | Collaborators: 7 | * JShell 8 | -------------------------------------------------------------------------------- /crcCards/Exit.txt: -------------------------------------------------------------------------------- 1 | Class name: Exit 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Quit the program 6 | 7 | Collaborators: 8 | * JShellState 9 | -------------------------------------------------------------------------------- /crcCards/History.txt: -------------------------------------------------------------------------------- 1 | Class name: History 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Show recent commands 6 | 7 | Collaborators: 8 | * JShellState 9 | -------------------------------------------------------------------------------- /crcCards/Man.txt: -------------------------------------------------------------------------------- 1 | Class name: Man 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Display documentations of the command 6 | 7 | Collaborators: 8 | * Command 9 | -------------------------------------------------------------------------------- /crcCards/CommandExecutor.txt: -------------------------------------------------------------------------------- 1 | Class name: CommandExecutor 2 | 3 | Responsibilities: 4 | * Executes the command line 5 | 6 | Collaborators: 7 | * CommandReader 8 | * Command 9 | -------------------------------------------------------------------------------- /crcCards/GetURL.txt: -------------------------------------------------------------------------------- 1 | Class name: getURL 2 | 3 | Responsibilities: 4 | * Retrieve file from URL and add to the current working directory 5 | 6 | Collaborators: 7 | * JShell 8 | -------------------------------------------------------------------------------- /crcCards/JShellState.txt: -------------------------------------------------------------------------------- 1 | Class name: JShellState 2 | 3 | Responsibilities: 4 | * Hold state of JShell program 5 | 6 | Collaborators: 7 | * Directory 8 | * DirectoryStack 9 | -------------------------------------------------------------------------------- /crcCards/Mv.txt: -------------------------------------------------------------------------------- 1 | Class name: mv 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Move the contents from a old path to a new path 6 | 7 | Collaborators: 8 | * JShell 9 | * rec 10 | -------------------------------------------------------------------------------- /crcCards/Redirection: -------------------------------------------------------------------------------- 1 | Class name: Redirection 2 | Sub-classes: CommandDecorator 3 | 4 | Responsibilities: 5 | * Decorates command to redirect output into a file 6 | 7 | Collaborators: 8 | * Command -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /crcCards/cp.txt: -------------------------------------------------------------------------------- 1 | Class name: cp 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Copies all the items from old path to a new path 6 | 7 | Collaborators: 8 | * JShell 9 | * rec 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /crcCards/CommandDecorator: -------------------------------------------------------------------------------- 1 | Class name: CommandDecorator 2 | Sub-classes: Redirection, RecursiveDecorator 3 | 4 | Responsibilities: 5 | * Decorates command appropriately 6 | 7 | Collaborators: 8 | * Command -------------------------------------------------------------------------------- /crcCards/CommandReader.txt: -------------------------------------------------------------------------------- 1 | Class name: CommandReader 2 | 3 | Responsibilities: 4 | * Read input line, separate arguments 5 | * Raise exception if invalid arguments are provided 6 | 7 | Collaborators: 8 | -------------------------------------------------------------------------------- /crcCards/Ls.txt: -------------------------------------------------------------------------------- 1 | Class name: Ls 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Display all files and directories(in current directory) in the shell 6 | 7 | Collaborators: 8 | * FileSystemObject 9 | -------------------------------------------------------------------------------- /crcCards/Pwd.txt: -------------------------------------------------------------------------------- 1 | Class name: Pwd 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Display the path of the current working directory 6 | 7 | Collaborators: 8 | * JShellState 9 | * Directory 10 | -------------------------------------------------------------------------------- /src/main/java/constants/CommandException.java: -------------------------------------------------------------------------------- 1 | package constants; 2 | 3 | public class CommandException extends Exception { 4 | public CommandException(String msg) { 5 | super(msg); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /crcCards/JShell.txt: -------------------------------------------------------------------------------- 1 | Class name: JShell 2 | 3 | Responsibilities: 4 | * Run and terminate the program 5 | * Provide access to other classes 6 | 7 | Collaborators: 8 | * JShellState 9 | * CommandExecutor 10 | -------------------------------------------------------------------------------- /crcCards/File.txt: -------------------------------------------------------------------------------- 1 | Class name: File 2 | Parent class: FileSystemObject 3 | 4 | Responsibilities: 5 | * Contain data, information 6 | * Can be opened, read, edited, deleted 7 | 8 | Collaborators: 9 | * Directory 10 | -------------------------------------------------------------------------------- /crcCards/Mkdir.txt: -------------------------------------------------------------------------------- 1 | Class name: Mkdir 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Create a new directory relative to the current directory or its full path 6 | 7 | Collaborators: 8 | * Directory 9 | 10 | -------------------------------------------------------------------------------- /crcCards/FileSystemObject.txt: -------------------------------------------------------------------------------- 1 | Class name: FileSystemObject 2 | Subclasses: Directory, File 3 | 4 | Responsibilities: 5 | * Is a file system object such as directory or file 6 | * Can be renamed, moved 7 | 8 | Collaborators: 9 | -------------------------------------------------------------------------------- /crcCards/Cat.txt: -------------------------------------------------------------------------------- 1 | Class name: Cat 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Display the contents of a file and multiple files 6 | * Raise exception is file doesn't exist 7 | 8 | Collaborators: 9 | * File 10 | -------------------------------------------------------------------------------- /crcCards/RecursiveDecorator.txt: -------------------------------------------------------------------------------- 1 | Class name: RecursiveDecorator 2 | Sub-classes: CommandDecorator 3 | 4 | Responsibilities: 5 | * Decorates command to be able to execute recursive calls appropriately 6 | 7 | Collaborators: 8 | * Command -------------------------------------------------------------------------------- /crcCards/Cd.txt: -------------------------------------------------------------------------------- 1 | Class name: Cd 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Change current directory of the JShell 6 | * Raise exception if directory doesn't exist 7 | 8 | Collaborators: 9 | * JShellState 10 | * Directory 11 | -------------------------------------------------------------------------------- /crcCards/Pushd.txt: -------------------------------------------------------------------------------- 1 | Class name: Pushd 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Save the current directory by pushing it into the directory stack 6 | 7 | Collaborators: 8 | * JShellState 9 | * DirectoryStack 10 | * Directory 11 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /crcCards/Directory.txt: -------------------------------------------------------------------------------- 1 | Class name: Directory 2 | Parent class: FileSystemObject 3 | 4 | Responsibilities: 5 | * Store file system objects 6 | * Show path to itself 7 | * Show file system object inside itself 8 | 9 | Collaborators: 10 | * FileSystemObject 11 | -------------------------------------------------------------------------------- /crcCards/Popd.txt: -------------------------------------------------------------------------------- 1 | Class name: Popd 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Change the current directory in the program to the directory at the top of the directory stack 6 | 7 | Collaborators: 8 | * JShellState 9 | * DirectoryStack 10 | * Directory 11 | -------------------------------------------------------------------------------- /crcCards/Echo.txt: -------------------------------------------------------------------------------- 1 | Class name: Echo 2 | Parent class: Command 3 | 4 | Responsibilities: 5 | * Replace the content of a given file (contains only string) with string 6 | * Create a new file that contains the string 7 | * Append a string to a file 8 | 9 | Collaborators: 10 | *File 11 | -------------------------------------------------------------------------------- /crcCards/Command.txt: -------------------------------------------------------------------------------- 1 | Class name: Command 2 | Parent class: None 3 | Subclasses: Cat, Cd, Cp, Echo, Exit, GetURL, Ls, Mkdir, Mv, Pwd 4 | 5 | Responsibilities: 6 | * Execute a valid command 7 | * Raise exception if command is invalid 8 | 9 | Collaborators: 10 | * Shell 11 | * Exception 12 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/main/java/commands/RecursiveInterface.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | 7 | /** 8 | * Interface for commands that can be executed recursively (have -R as an 9 | * optional parameter) 10 | */ 11 | public interface RecursiveInterface { 12 | String executeRecursively 13 | (IShellState shellState, List arguments); 14 | } 15 | -------------------------------------------------------------------------------- /crcCards/readMeForCrcCards.txt: -------------------------------------------------------------------------------- 1 | --All your crc cards will reside in here. 2 | 3 | --Your code structure MUST always reflect the design outlined in CRC Cards. 4 | 5 | --If at any point you change or modify your design: 6 | ----a) Change your CRC Cards to reflect the new design. 7 | ----b) Change your code sturcture so that it reflects the new design. 8 | 9 | --Follow the same format as in Assignment1 for crc cards. 10 | -------------------------------------------------------------------------------- /src/main/java/command_decorators/CommandDecorator.java: -------------------------------------------------------------------------------- 1 | package command_decorators; 2 | 3 | import commands.Command; 4 | 5 | 6 | // This is a builder! 7 | /** 8 | * This is an abstract class that is a base for all decorators of the command 9 | */ 10 | public abstract class CommandDecorator extends Command { 11 | final Command command; 12 | 13 | public CommandDecorator(Command command) { 14 | super(command.getMaxArg(), command.getMinArg()); 15 | this.command = command; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/runConfigurations/JunitTests.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | -------------------------------------------------------------------------------- /src/main/java/commands/Exit.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | 7 | /** 8 | * This class is responsible for letting user to exit the program 9 | */ 10 | public class Exit extends Command { 11 | 12 | public Exit() { 13 | super(0, 0); 14 | } 15 | 16 | /** 17 | * Stop the JShell program by changing its state 18 | * @param shellState is the object that holds JShell's state 19 | * @throws Exception if number of arguments provided is incorrect 20 | */ 21 | public String executeCommand 22 | (IShellState shellState, List arguments) throws Exception{ 23 | checkArgumentsNum(arguments); 24 | shellState.stopRunning(); 25 | return ""; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/commands/Echo.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | 7 | /** 8 | * This class reads the provided STRING argument 9 | */ 10 | public class Echo extends Command { 11 | 12 | public Echo() { 13 | super(1, 1); 14 | } 15 | 16 | /** 17 | * Returns provided STRING argument. 18 | * @param shellState is the state of the program 19 | * @param arguments is list of arguments that were passed along with command 20 | * @throws Exception number of arguments provided is incorrect 21 | */ 22 | public String executeCommand(IShellState shellState, List arguments) 23 | throws Exception { 24 | checkArgumentsNum(arguments); 25 | return arguments.get(0); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/helper_classes/CmdArgTuple.java: -------------------------------------------------------------------------------- 1 | package helper_classes; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * This is a class that mimics a tuple in python 7 | */ 8 | public class CmdArgTuple { 9 | private final String command; 10 | private final List arguments; 11 | 12 | /** 13 | * Constructor for the tuple 14 | */ 15 | public CmdArgTuple(String command, List arguments) { 16 | this.command = command; 17 | this.arguments = arguments; 18 | } 19 | 20 | /** 21 | * Return first object 22 | */ 23 | public String getCommand() { 24 | return this.command; 25 | } 26 | 27 | /** 28 | * Return second object 29 | */ 30 | public List getArguments() { 31 | return this.arguments; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/commands/Pwd.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | 7 | /** 8 | * Display path of current directory in the program 9 | */ 10 | public class Pwd extends Command { 11 | 12 | public Pwd() { 13 | super(0, 0); 14 | } 15 | 16 | /** 17 | * Print the current working directory (including the whole path). 18 | * @param shellState is the state of JShell program 19 | * @param arguments is list of arguments that were passed along with command 20 | * (includes the path of directory to be switched to) 21 | */ 22 | public String executeCommand 23 | (IShellState shellState, List arguments) throws Exception{ 24 | checkArgumentsNum(arguments); 25 | return shellState.getCurrentDir().getPath(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/driver/IShellState.java: -------------------------------------------------------------------------------- 1 | package driver; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | import java.util.Stack; 6 | 7 | import file_system.Directory; 8 | import file_system.VirtualFileSystem; 9 | 10 | public interface IShellState extends Serializable { 11 | boolean isRunning(); 12 | 13 | void stopRunning(); 14 | 15 | VirtualFileSystem getFileSystem(); 16 | 17 | Directory getRootDir(); 18 | 19 | Directory getCurrentDir(); 20 | 21 | void setCurrentDir(Directory newCurrentDir); 22 | 23 | void addHistory(String inputLine); 24 | 25 | void removeHistory(int index); 26 | 27 | List getHistory(); 28 | 29 | void addCorrectHistory(String inputLine); 30 | 31 | List getCorrectHistory(); 32 | 33 | Stack getDirectoryStack(); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/helper_classes/DirectoryFileNameTuple.java: -------------------------------------------------------------------------------- 1 | package helper_classes; 2 | 3 | import file_system.Directory; 4 | 5 | /** 6 | * This is a class that mimics a tuple in python 7 | */ 8 | public class DirectoryFileNameTuple { 9 | private final Directory directory; 10 | private final String fileName; 11 | 12 | /** 13 | * Constructor for a tuple 14 | */ 15 | public DirectoryFileNameTuple(Directory directory, String fileName) { 16 | this.directory = directory; 17 | this.fileName = fileName; 18 | } 19 | 20 | /** 21 | * Return first object 22 | */ 23 | public Directory getDirectory() { 24 | return this.directory; 25 | } 26 | 27 | /** 28 | * Return second object 29 | */ 30 | public String getFileName() { 31 | return this.fileName; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /src/main/java/commands/Tree.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | import file_system.VirtualFileSystem; 7 | 8 | /** 9 | * Display the entire file system as a tree 10 | */ 11 | public class Tree extends Command { 12 | 13 | public Tree() { 14 | super(0, 0); 15 | } 16 | 17 | /** 18 | * Displays the entire file system as a tree 19 | * @param shellState the state of JShell program 20 | * @param arguments list of arguments that were passed along with command 21 | * @return Representation of the entire file system as a tree 22 | */ 23 | @Override 24 | public String executeCommand(IShellState shellState, List arguments) 25 | throws Exception { 26 | checkArgumentsNum(arguments); 27 | VirtualFileSystem fs = shellState.getFileSystem(); 28 | return fs.getTreeRepresentation(); 29 | } 30 | 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java-Shell 2 | 3 | ## System Requirements 4 | Java (1.7 or later) 5 | 6 | ## Using the program 7 | 8 | ### Compiling 9 | * Open a terminal. (It's in the row of tabs at the bottom of this window.) 10 | * Copy and paste these two commands: 11 | ``` 12 | cd src/main/java # This opens the src/main/java folder 13 | javac driver/*.java # This compiles the whole program. 14 | ``` 15 | 16 | ### Starting the Program 17 | * Run the program: 18 | ``` 19 | $ java driver/JShell 20 | ``` 21 | 22 | ## Commands 23 | List of commands available 24 | * ! 25 | * cat 26 | * cd 27 | * cp 28 | * echo 29 | * exit 30 | * find 31 | * get 32 | * history 33 | * load 34 | * ls 35 | * man 36 | * mkdir 37 | * mv 38 | * popd 39 | * pushd 40 | * pwd 41 | 42 | ## Example using the commands 43 | 44 | To read the documentation of a specific command 45 | ``` 46 | $ man [command] 47 | #example: 48 | $ man ls 49 | ``` 50 | 51 | To write to a file using echo: 52 | ``` 53 | $ echo "hello world" > file1 54 | ``` 55 | 56 | To append to a existing file: 57 | To write to a file using echo: 58 | ``` 59 | $ echo "good bye" >> file1 60 | ``` 61 | -------------------------------------------------------------------------------- /src/main/java/commands/Mv.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | import file_system.VirtualFileSystem; 7 | 8 | /** 9 | * Moves a file or directory from one path to another 10 | */ 11 | public class Mv extends Command { 12 | 13 | public Mv() { 14 | super(2, 2); 15 | } 16 | 17 | /** 18 | * Moves a file or directory at one path to another path, possibly 19 | * overwritting a file or directory. 20 | * @param shellState is the state of the program 21 | * @param arguments is list of provided arguments 22 | * @throws Exception if given paths are invalid 23 | */ 24 | @Override 25 | public String executeCommand(IShellState shellState, List arguments) 26 | throws Exception { 27 | checkArgumentsNum(arguments); 28 | VirtualFileSystem fs = shellState.getFileSystem(); 29 | String oldPath = arguments.get(0); 30 | String newPath = arguments.get(1); 31 | fs.moveFsObject(shellState.getCurrentDir(), oldPath, newPath); 32 | return ""; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/commands/Cd.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | import file_system.Directory; 7 | import helper_classes.PathHandler; 8 | 9 | /** 10 | * This class allows user to move between directories 11 | */ 12 | public class Cd extends Command { 13 | 14 | public Cd() { 15 | super(1, 1); 16 | } 17 | 18 | /** 19 | * Switches the current directory that JShell program is in to the one 20 | * defined by given path 21 | * 22 | * @param shellState is the state of JShell program 23 | * @param arguments is list of arguments that were passed along with command 24 | * (includes the path of directory to be switched to) 25 | */ 26 | public String executeCommand(IShellState shellState, List arguments) 27 | throws Exception { 28 | checkArgumentsNum(arguments); 29 | String path = arguments.get(0); 30 | Directory target = PathHandler.getDirectoryByPath(shellState, path); 31 | shellState.setCurrentDir(target); 32 | return ""; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/commands/Cp.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | import file_system.VirtualFileSystem; 7 | 8 | /** 9 | * This class copies a file or directory from one place to another 10 | */ 11 | public class Cp extends Command { 12 | 13 | public Cp() { 14 | super(2, 2); 15 | } 16 | 17 | /** 18 | * Copies a file or directory at one path to another path, possibly 19 | * overwritting a file or directory. 20 | * @param shellState is the state of the program 21 | * @param arguments is list of provided arguments 22 | * @throws Exception if given paths are invalid 23 | */ 24 | @Override 25 | public String executeCommand(IShellState shellState, List arguments) 26 | throws Exception { 27 | checkArgumentsNum(arguments); 28 | VirtualFileSystem fs = shellState.getFileSystem(); 29 | String oldPath = arguments.get(0); 30 | String newPath = arguments.get(1); 31 | fs.copyFsObject(shellState.getCurrentDir(), oldPath, newPath); 32 | return ""; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Minh Hoang Nguyen and Nhi Nguyen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/commands/Pushd.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | import file_system.Directory; 7 | 8 | public class Pushd extends Command { 9 | 10 | /** 11 | * Pushd class save the current working directory 12 | * to directory stack and switch to given dir 13 | * 14 | */ 15 | public Pushd() { 16 | super(1, 1); 17 | } 18 | 19 | /** 20 | * Saves the current working directory to directory stack 21 | * and then changes the new current working directory to given directory 22 | * @param shellState is the state of JShell program 23 | * @param arguments is list of arguments that were passed along with command 24 | * (includes the path of directory to be switched to) 25 | */ 26 | public String executeCommand(IShellState shellState, List arguments) 27 | throws Exception { 28 | checkArgumentsNum(arguments); 29 | Directory currentDir = shellState.getCurrentDir(); 30 | Cd cd = new Cd(); 31 | cd.executeCommand(shellState, arguments); 32 | shellState.getDirectoryStack().push(currentDir); 33 | return ""; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/main/java/driver/JShell.java: -------------------------------------------------------------------------------- 1 | package driver; 2 | 3 | import java.util.Scanner; 4 | 5 | import commands.CommandController; 6 | 7 | /** 8 | * This is the Shell that prompts user for input and prints the output 9 | * according to specified input 10 | */ 11 | public class JShell { 12 | 13 | public static void main(String[] args) { 14 | JShellState shellState = new JShellState(); 15 | CommandController commandExecutor = new CommandController(); 16 | Scanner in = new Scanner(System.in); 17 | // keep reading the command and executing it until user exits the program 18 | while (shellState.isRunning()) { 19 | System.out.print("$ "); 20 | // read next input line parse it and check if it is valid 21 | String commandLine = in.nextLine(); 22 | try { 23 | String output = commandExecutor.executeCommand(shellState, commandLine); 24 | if (!output.equals("")) { 25 | System.out.println(output); 26 | } 27 | } 28 | catch (Exception e) { 29 | // TODO: change to CommandException everywhere. 30 | System.out.println(e.getMessage()); 31 | } 32 | } 33 | in.close(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/command_decorators/RecursiveDecorator.java: -------------------------------------------------------------------------------- 1 | package command_decorators; 2 | 3 | import java.util.List; 4 | 5 | import commands.Command; 6 | import commands.RecursiveInterface; 7 | import constants.Exceptions; 8 | import driver.IShellState; 9 | 10 | /** 11 | * This class is a decorator for command that can be executed recursively 12 | * (can take -R as an optional parameter) 13 | */ 14 | public class RecursiveDecorator extends CommandDecorator { 15 | 16 | public RecursiveDecorator(Command command) { 17 | super(command); 18 | } 19 | 20 | /** 21 | * Checks if given command takes -R as an optional parameter. Then execute 22 | * accordingly 23 | * @param shellState is state of program 24 | * @param arguments are base arguments provided 25 | * @throws Exception if command doesn't take -R 26 | */ 27 | @Override 28 | public String executeCommand(IShellState shellState, List arguments) 29 | throws Exception { 30 | // if command does not support -R as optional parameter 31 | if (!(command instanceof RecursiveInterface)) { 32 | throw new Exception(Exceptions.INVALID_OPTIONAL_PARAM); 33 | } 34 | return ((RecursiveInterface) command). 35 | executeRecursively(shellState, arguments); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/commands/Command.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import constants.CommandException; 6 | import driver.IShellState; 7 | 8 | /** 9 | * This is a base class for any commands that might be needed in the program 10 | */ 11 | public abstract class Command { 12 | protected final int maxArguments; 13 | protected final int minArguments; 14 | 15 | public Command(int maxArguments, int minArguments) { 16 | this.maxArguments = maxArguments; 17 | this.minArguments = minArguments; 18 | } 19 | 20 | public int getMaxArg() { 21 | return maxArguments; 22 | } 23 | 24 | public int getMinArg() { 25 | return minArguments; 26 | } 27 | 28 | abstract public String executeCommand 29 | (IShellState shellState, List arguments) throws Exception; 30 | 31 | // TODO: write Javadoc 32 | protected void checkArgumentsNum(List arguments) throws Exception { 33 | if (arguments.size() > maxArguments) { 34 | // TODO: add this message to class constants.Exceptions 35 | throw new CommandException("too many arguments provided"); 36 | } 37 | if (arguments.size() < minArguments) { 38 | throw new CommandException("too little arguments provided"); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/commands/Popd.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | import java.util.Stack; 5 | 6 | import constants.Exceptions; 7 | import driver.IShellState; 8 | import file_system.Directory; 9 | 10 | /** 11 | * Pop class Remove the top entry from 12 | * the directory stack, and cd into it 13 | * 14 | */ 15 | public class Popd extends Command { 16 | public Popd() { 17 | super(0, 0); 18 | } 19 | 20 | /** 21 | * Remove the top entry from the directory stack, and cd into it 22 | * @param shellState is the state of JShell program 23 | * @param arguments is list of arguments that were passed along with command 24 | * (includes the path of directory to be switched to) 25 | * @throws Exception if pop from empty directory stack 26 | */ 27 | public String executeCommand(IShellState shellState, List arguments) 28 | throws Exception { 29 | checkArgumentsNum(arguments); 30 | Stack dirStack = shellState.getDirectoryStack(); 31 | int stackLen = dirStack.size(); 32 | if (stackLen == 0) { 33 | throw new Exception(Exceptions.POP_EMPTY_STACK); 34 | } 35 | // switch to last directory in the directoryStack(removing it from stack) 36 | shellState.setCurrentDir(dirStack.pop()); 37 | return ""; 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/helper_classes/StringHelper.java: -------------------------------------------------------------------------------- 1 | package helper_classes; 2 | 3 | /** 4 | * This class contains methods that help make operations with strings 5 | */ 6 | public class StringHelper { 7 | 8 | /** 9 | * Method checks if a string contains any of the characters in the array 10 | * @param str is the string 11 | * @param charArray is an array of characters 12 | * @return boolean 13 | */ 14 | public static boolean containsAny(String str, char[] charArray) { 15 | boolean result = false; 16 | for (int i = 0; i < str.length(); i++) { 17 | char currentChar = str.charAt(i); 18 | for (char c : charArray) { 19 | if (c == currentChar) { 20 | result = true; 21 | break; 22 | } 23 | } 24 | } 25 | return result; 26 | } 27 | 28 | /** 29 | * This method multiplies concatenates given string given number of times 30 | * @param str any string 31 | * @param numRepeat number of repetition 32 | * @return repeated string 33 | */ 34 | public static String repeat(String str, int numRepeat) { 35 | StringBuilder output = new StringBuilder(); 36 | for (int i = 0; i < numRepeat; i++) { 37 | output.append(str); 38 | i++; 39 | } 40 | return output.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/commands/Man.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | import constants.Constants; 5 | import driver.IShellState; 6 | /** 7 | * This class will get the documentation for a given command 8 | */ 9 | public class Man extends Command { 10 | 11 | public Man() { 12 | super(1, 1); 13 | } 14 | 15 | /** 16 | * Prints the documentation for the given command 17 | * @param shellState is the current state of JShell program 18 | * @param arguments is the command that indicates what should be printed 19 | * @return the current FileSystemObject the path indicates 20 | * @throws Exception if command is invalid 21 | */ 22 | @Override 23 | public String executeCommand(IShellState shellState, List arguments) 24 | throws Exception{ 25 | checkArgumentsNum(arguments); 26 | String commandToPrint = arguments.get(0); 27 | if (!CommandReader.isValidCommand(commandToPrint)) { 28 | throw new Exception("command to print documentation not found"); 29 | } 30 | return getDocumentation(commandToPrint); 31 | } 32 | 33 | /** 34 | * Gets the documentation for the given command 35 | * @param command is the command that indicates what documentation to get 36 | * @return the documentation of the given command 37 | */ 38 | private String getDocumentation(String command) { 39 | return Constants.COMMAND_DOCUMENTATION.get(command); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/commands/MkdirTest.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import driver.JShellState; 4 | import file_system.Directory; 5 | import file_system.VirtualFileSystem; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import java.util.List; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | public class MkdirTest { 15 | JShellState shellState; 16 | CommandController commandExecutor; 17 | 18 | @Before 19 | public void setUp() throws Exception { 20 | VirtualFileSystem.resetFileSystemInstance(); 21 | shellState = new JShellState(); 22 | commandExecutor = new CommandController(); 23 | } 24 | 25 | @After 26 | public void tearDown() throws Exception { 27 | } 28 | 29 | @Test 30 | public void testExecuteCommandHistory() { 31 | try { 32 | String output = commandExecutor.executeCommand(shellState, "mkdir test"); 33 | List history = shellState.getHistory(); 34 | assertEquals("mkdir test", history.get(0)); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | 40 | 41 | @Test 42 | public void testExecuteCommandNewDir() { 43 | try { 44 | String output = commandExecutor.executeCommand(shellState, "mkdir test"); 45 | VirtualFileSystem fileSystem = shellState.getFileSystem(); 46 | Directory newDir = fileSystem.getDirectoryByPath(fileSystem.getRoot(), "test"); 47 | } catch (Exception e) { 48 | fail("Could not retrieve new directory using getDirectoryByPath"); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/java/commands/Cat.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | import file_system.File; 7 | import helper_classes.PathHandler; 8 | 9 | /** 10 | * Cat class Returns content of the file(s) at path(s) that are provided 11 | */ 12 | public class Cat extends Command { 13 | 14 | public Cat() { 15 | super(100, 1); 16 | } 17 | 18 | /** 19 | * Returns content of the file(s) at path(s) that are provided 20 | * @param shellState is the state of the program 21 | * @param arguments is list of arguments that were passed along with command 22 | * @throws Exception if path is invalid 23 | */ 24 | public String executeCommand(IShellState shellState, List arguments) 25 | throws Exception { 26 | /* 27 | * loop through each path in the argument list 28 | * and get the directory of the requirement file and its name 29 | */ 30 | checkArgumentsNum(arguments); 31 | StringBuilder output = new StringBuilder(); 32 | for (String path: arguments) { 33 | try { 34 | File filetoCat = PathHandler.getFileByPath(shellState, path); 35 | /* 36 | * if this is the first file get cat, do not include line break 37 | * else concatenate the current file after the previous 38 | * file with 3 lines break 39 | */ 40 | output.append((output.toString().equals("")) ? 41 | filetoCat.getContent() : ("\n\n" + filetoCat.getContent())); 42 | } 43 | catch (Exception e) { 44 | String errorString = "cannot view file " + path + ": " + e.getMessage(); 45 | output.append((output.toString().equals("")) ? 46 | errorString : "\n\n" + errorString); 47 | } 48 | } 49 | return output.toString(); 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/constants/Exceptions.java: -------------------------------------------------------------------------------- 1 | package constants; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.ArrayList; 5 | 6 | /** 7 | * This class holds all the exception messages in the program 8 | */ 9 | public class Exceptions { 10 | public static final String WRONG_PATH_INPUT_MSG = "No such file or directory"; 11 | public static final String INVALID_STRING_MSG = "Invalid string input"; 12 | public static final String POP_EMPTY_STACK = 13 | "cannot execute: use pushd to push a directory into the stack first "; 14 | public static final String FILE_EXISTS = "File/directory exists"; 15 | public static final String COMMAND_NOT_FOUND = "command not found"; 16 | public static final String OPTIONAL_PARAM_ERROR = "invalid option"; 17 | public static final String INVALID_ARGUMENT = "invalid argument"; 18 | public static final String MOVE_INTO_SUBCHILD_ERROR = 19 | "Can't move or copy into sub child"; 20 | public static final String INVALID_OPTIONAL_PARAM = 21 | "this command doesn't support this optional parameter"; 22 | 23 | public static final String NOT_A_FILE_ERROR = "Not a file"; 24 | public static final String NOT_A_DIRECTORY_ERROR = "Not a file"; 25 | public static final String INVALID_NAME = 26 | "name cannot contain some of the given characters"; 27 | public static final String MOVE_DIRECTORY_INTO_FILE_ERROR = 28 | "Cannot move a directory into a file"; 29 | 30 | // Returns a list of all exceptions 31 | public static ArrayList getErrors() { 32 | ArrayList errorMessages = new ArrayList(); 33 | Field[] fields = Exceptions.class.getFields(); 34 | for (Field field : fields) { 35 | try { 36 | String errorMessage = (String) field.get(Exceptions.class); 37 | errorMessages.add(errorMessage); 38 | } catch (Exception e) { 39 | // TODO Auto-generated catch block 40 | e.printStackTrace(); 41 | } 42 | } 43 | return errorMessages; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/commands/Save.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.io.*; 4 | import java.util.List; 5 | import constants.Exceptions; 6 | import driver.IShellState; 7 | /** 8 | * This class is responsible for saving the current JShell session into a file 9 | */ 10 | public class Save extends Command { 11 | 12 | public Save() { 13 | super(1, 1); 14 | } 15 | 16 | /** 17 | * This method will save the current JShell session into a file which will 18 | * created/ overwritten at the given path 19 | * @param shellState is the current state of JShell program 20 | * @param arguments list of arguments that were passed along with command 21 | * @throws Exception if any of the paths is invalid 22 | */ 23 | public String executeCommand(IShellState shellState, List arguments) 24 | throws Exception { 25 | try { 26 | checkArgumentsNum(arguments); 27 | String path = arguments.get(0); 28 | if (!path.contains("/")) { 29 | throw new Exception(Exceptions.WRONG_PATH_INPUT_MSG); 30 | } 31 | 32 | saveToFile2(shellState, path); 33 | return ""; 34 | } catch (IOException e) { 35 | throw new Exception(Exceptions.WRONG_PATH_INPUT_MSG); 36 | } 37 | } 38 | 39 | private void saveToFile2(IShellState shellState, String path) throws IOException { 40 | 41 | FileOutputStream fileOut = 42 | new FileOutputStream(path); 43 | ObjectOutputStream out = new ObjectOutputStream(fileOut); 44 | out.writeObject(shellState); 45 | out.close(); 46 | fileOut.close(); 47 | } 48 | 49 | private void saveToFile1(IShellState shellState, String path) throws IOException { 50 | FileWriter fileWriter = new FileWriter(path); 51 | BufferedWriter bw = new BufferedWriter(fileWriter); 52 | //add history 53 | for (String commandLine : shellState.getHistory()) { 54 | bw.write(commandLine); 55 | bw.newLine(); 56 | } 57 | bw.write("*****"); 58 | bw.newLine(); 59 | // add content to file 60 | for (String commandLine : shellState.getCorrectHistory()) { 61 | bw.write(commandLine); 62 | bw.newLine(); 63 | } 64 | bw.close(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/file_system/File.java: -------------------------------------------------------------------------------- 1 | package file_system; 2 | 3 | import constants.Exceptions; 4 | 5 | /** 6 | * This class represents a virtual file that has content and is a child of a 7 | * directory 8 | */ 9 | public class File extends FileSystemObject { 10 | private String content; 11 | 12 | 13 | /** 14 | * Constructs a file with given name and parent 15 | * @param name given name 16 | * @param parent given parent 17 | * @throws Exception if object with given name exists in given parent 18 | */ 19 | public File(String name, Directory parent) throws Exception { 20 | this(name, parent, ""); 21 | } 22 | 23 | /** 24 | * Constructs a file with given name and parent and content 25 | * @param name given name 26 | * @param parent given parent 27 | * @param content given content 28 | * @throws Exception if object with given name exists in given parent 29 | */ 30 | public File(String name, Directory parent, String content) throws Exception { 31 | super(name, parent); 32 | parent.addChild(this); 33 | this.content = content; 34 | } 35 | 36 | /** 37 | * Return content of file 38 | */ 39 | public String getContent() { 40 | return this.content; 41 | } 42 | 43 | /** 44 | * Set content of file 45 | * @param content is given content 46 | */ 47 | public void setContent(String content) { 48 | this.content = content; 49 | } 50 | 51 | /** 52 | * Append content to the file 53 | * @param contentToAppend is content to append to the file 54 | */ 55 | public void appendContent(String contentToAppend) { 56 | this.content += "\n" + contentToAppend; 57 | } 58 | 59 | @Override 60 | public void moveFsObjectIn(FileSystemObject fsObject) throws Exception { 61 | if (!(fsObject instanceof File)) { 62 | throw new Exception(Exceptions.MOVE_DIRECTORY_INTO_FILE_ERROR); 63 | } 64 | setContent(fsObject.getContent()); 65 | } 66 | 67 | /** 68 | * Constructor for cloning purpose 69 | */ 70 | private File(String name, String content) { 71 | this.name = name; 72 | this.content = content; 73 | this.parent = null; 74 | } 75 | 76 | @Override 77 | public FileSystemObject cloneObject() { 78 | return new File(name, content); 79 | } 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/driver/JShellState.java: -------------------------------------------------------------------------------- 1 | package driver; 2 | 3 | import file_system.Directory; 4 | import file_system.VirtualFileSystem; 5 | 6 | import java.io.Serializable; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.Stack; 10 | 11 | /** 12 | * This class holds all the states of the Shell Program 13 | */ 14 | public class JShellState implements IShellState, Serializable { 15 | private final VirtualFileSystem fs; 16 | private Directory currentDir; 17 | private boolean running; 18 | private final Stack directoryStack; 19 | private final List commandsHistory; 20 | private final List correctCommandsHistory; 21 | 22 | /** 23 | * Constructs an object that holds JShell's important states including 24 | * the root directory, current directory, directory stack and a boolean that 25 | * indicates JShell is running 26 | */ 27 | public JShellState() { 28 | this.running = true; 29 | this.fs = VirtualFileSystem.createFileSystemInstance(); 30 | this.currentDir = fs.getRoot(); 31 | this.commandsHistory = new ArrayList<>(); 32 | this.correctCommandsHistory = new ArrayList<>(); 33 | this.directoryStack = new Stack<>(); 34 | } 35 | 36 | public boolean isRunning() { 37 | return running; 38 | } 39 | 40 | public void stopRunning() { 41 | running = false; 42 | } 43 | 44 | public VirtualFileSystem getFileSystem() { 45 | return fs; 46 | } 47 | 48 | public Directory getRootDir() { 49 | return fs.getRoot(); 50 | } 51 | 52 | public Directory getCurrentDir() { 53 | return currentDir; 54 | } 55 | 56 | public void setCurrentDir(Directory newCurrentDir) { 57 | currentDir = newCurrentDir; 58 | } 59 | 60 | public void addHistory(String inputLine) { 61 | commandsHistory.add(inputLine); 62 | } 63 | 64 | public void removeHistory(int index) { 65 | commandsHistory.remove(index); 66 | } 67 | 68 | public List getHistory() { 69 | return commandsHistory; 70 | } 71 | 72 | public void addCorrectHistory(String inputLine) { 73 | correctCommandsHistory.add(inputLine); 74 | } 75 | 76 | public List getCorrectHistory() { 77 | return correctCommandsHistory; 78 | } 79 | 80 | public Stack getDirectoryStack(){ 81 | return directoryStack; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/commands/History.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import constants.Exceptions; 7 | import driver.IShellState; 8 | 9 | public class History extends Command { 10 | 11 | public History() { 12 | super(1, 0); 13 | } 14 | 15 | /** 16 | * print out recent commands, one command per line 17 | * @param shellState is the state of JShell program 18 | * @param arguments is list of arguments that were passed along with command 19 | * (includes the path of directory to be switched to) 20 | */ 21 | public String executeCommand(IShellState shellState, List arguments) 22 | throws Exception { 23 | int numberOfCommand; 24 | checkArgumentsNum(arguments); 25 | /* if no argument is passed, 26 | * set numberOfCommand to print the all history 27 | */ 28 | if (arguments.size() == 0) { 29 | numberOfCommand =shellState.getHistory().size(); 30 | } else { 31 | numberOfCommand = Integer.parseInt(arguments.get(0)); 32 | } 33 | return getHistory(shellState, numberOfCommand); 34 | } 35 | 36 | /** 37 | * print out recent commands, one command per line 38 | * @param shellState is the state of JShell program 39 | * @param numberOfCommand is the number of command in the history 40 | * the user want to see 41 | * @throws Exception if numberOfCommand < 0 42 | */ 43 | private String getHistory(IShellState shellState, int numberOfCommand) 44 | throws Exception { 45 | List history = shellState.getHistory(); 46 | int i = history.size() - 1 ; 47 | StringBuilder output = new StringBuilder(); 48 | /* 49 | * if numberOfCommand exceed the number of history, 50 | * set it to print up to all history 51 | */ 52 | if (numberOfCommand > history.size()) { 53 | numberOfCommand = history.size(); 54 | } else if (numberOfCommand < 0) { 55 | throw new Exception(Exceptions.INVALID_ARGUMENT); 56 | } 57 | /* 58 | * loop and print the number of commands required 59 | * or until all history commands have been printed 60 | */ 61 | while (numberOfCommand > 0 && i <= history.size()) { 62 | output.insert(0, i + 1 + ". " + history.get(i) + "\n"); 63 | i--; 64 | numberOfCommand--; 65 | } 66 | return output.toString(); 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/java/commands/Get.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | import file_system.Directory; 7 | 8 | import java.net.*; 9 | import java.io.*; 10 | 11 | /** 12 | * This class create a new file with content from given url 13 | */ 14 | public class Get extends Command{ 15 | public Get() { 16 | super(1, 1); 17 | } 18 | 19 | /** 20 | * Retrieve file at given URL and add it to the current working directory 21 | * @param shellState is the current state of JShell program 22 | * @param arguments is the list of paths that indicate where new directories 23 | * should be created 24 | * @throws Exception if any of the paths is invalid 25 | */ 26 | public String executeCommand(IShellState shellState, List arguments) 27 | throws Exception { 28 | checkArgumentsNum(arguments); 29 | Directory currentDir = shellState.getCurrentDir(); 30 | 31 | //read through each line of the file and append to content 32 | StringBuilder content = new StringBuilder(); 33 | URL url = new URL(arguments.get(0)); 34 | BufferedReader in = new BufferedReader( 35 | new InputStreamReader(url.openStream())); 36 | String inputLine; 37 | while ((inputLine = in.readLine()) != null) 38 | content.append(inputLine).append("\n"); 39 | in.close(); 40 | 41 | //get the url to find the file name 42 | String urlLink = arguments.get(0); 43 | 44 | String fileName = extractName(urlLink); 45 | /* 46 | * create a file in current directory with founded file name 47 | * and content 48 | */ 49 | new file_system.File(fileName, currentDir, content.toString()); 50 | 51 | return ""; 52 | } 53 | 54 | /** 55 | * Get the file name from a url 56 | * @param urlLink is a url link 57 | */ 58 | public String extractName(String urlLink) { 59 | int start=0; 60 | int end=urlLink.length(); 61 | 62 | boolean foundName = false; 63 | // loop from the end until find the first "/" 64 | int i = urlLink.length() - 1; 65 | while ( i >= 0 && !foundName) { 66 | char c = urlLink.charAt(i); 67 | // exclude the file type 68 | if (c == '.') { 69 | end = i; 70 | } else if (c == '/') { 71 | start = i+1; 72 | foundName = true; 73 | } 74 | i--; 75 | } 76 | return urlLink.substring(start, end); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/commands/Mkdir.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | import file_system.Directory; 7 | import helper_classes.DirectoryFileNameTuple; 8 | import helper_classes.PathHandler; 9 | 10 | /** 11 | * Creates directories in the file system 12 | */ 13 | public class Mkdir extends Command { 14 | private static final String startingErrorMsg = "cannot create directory"; 15 | 16 | public Mkdir() { 17 | super(100, 1); 18 | } 19 | 20 | /** 21 | * Creates many directories according to each path 22 | * @param shellState is the current state of JShell program 23 | * @param arguments is the list of paths that indicate where new directories 24 | * should be created 25 | * @throws Exception if any of the paths is invalid 26 | */ 27 | public String executeCommand 28 | (IShellState shellState, List arguments) throws Exception { 29 | checkArgumentsNum(arguments); 30 | StringBuilder allErrorMsg = new StringBuilder(); 31 | for (String path: arguments) { 32 | try { 33 | createDir(shellState, path); 34 | } 35 | catch (Exception e) { 36 | String fullErrorMsg = constructFullErrorMsg(path, e.getMessage()); 37 | allErrorMsg.append((allErrorMsg.toString().equals("")) ? 38 | fullErrorMsg : ("\n" + fullErrorMsg)); 39 | } 40 | } 41 | if (!allErrorMsg.toString().equals("")) { 42 | throw new Exception(allErrorMsg.toString()); 43 | } 44 | return ""; 45 | } 46 | 47 | /** 48 | * Creates a single new directory according to the given path 49 | * @param shellState is the current state of JShell program 50 | * @param path indicates where the new directory should be created 51 | * @throws Exception if given path is invalid 52 | */ 53 | private void createDir(IShellState shellState, String path) 54 | throws Exception { 55 | /* 56 | * get the directory from which new directory should be added from and 57 | * name of the new directory 58 | */ 59 | DirectoryFileNameTuple wantedDirAndFileName = 60 | PathHandler.getDirectoryAndFileName(shellState, path); 61 | new Directory(wantedDirAndFileName.getFileName(), 62 | wantedDirAndFileName.getDirectory()); 63 | } 64 | 65 | /** 66 | * Constructs a complete detailed error message for this command subclass 67 | * @param path is the path from which directory could not be created 68 | * @param detailedErrorMsg is the error message that was returned when 69 | * creating directory failed 70 | * @return string that represents the complete detailed error message 71 | */ 72 | private String constructFullErrorMsg(String path, String detailedErrorMsg) { 73 | return startingErrorMsg + " '" + path + "': " + detailedErrorMsg; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/main/java/commands/Find.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import constants.Exceptions; 6 | import driver.IShellState; 7 | import file_system.Directory; 8 | import file_system.File; 9 | import file_system.FileSystemObject; 10 | import helper_classes.PathHandler; 11 | 12 | 13 | /** 14 | * This class searches for the file or directory in a given path 15 | * 16 | */ 17 | 18 | public class Find extends Command{ 19 | 20 | public Find() { 21 | super(100, 5); 22 | } 23 | 24 | /** 25 | * Searches for the file or directory in a given path 26 | * @param shellState is the current state of JShell program 27 | * @param arguments includes all of: [file_path], --type [f/d], --name [file_name] 28 | * @throws Exception if path, type or name is invalid 29 | * 30 | */ 31 | public String executeCommand(IShellState shellState, 32 | List arguments) throws Exception { 33 | 34 | checkArgumentsNum(arguments); 35 | String output = ""; 36 | String name = arguments.get(arguments.size()-1); 37 | String type = arguments.get(arguments.size()-3); 38 | 39 | if ((!arguments.get(arguments.size()-2).equals("-name"))|| 40 | !arguments.get(arguments.size()-4).equals("-type")){ 41 | throw new Exception(Exceptions.INVALID_ARGUMENT); 42 | } 43 | if (!type.equals("d") && !type.equals("f")){ 44 | throw new Exception("Invalid type"); 45 | } 46 | 47 | 48 | try { 49 | // get arguments excluding the type and expression 50 | List baseArgs = arguments.subList(0, arguments. 51 | size() - 4); 52 | // Search the given paths for the file/directory 53 | for (String paths:baseArgs) { 54 | FileSystemObject fsObject = PathHandler 55 | .getFileSystemObject(shellState, paths); 56 | // if path is a file, check if it matches type 57 | // and name 58 | if (fsObject.isEqualByClassAndName(File.class,name)){ 59 | output = name + "found in " + paths; 60 | } 61 | // if path is a directory, check its contents to find 62 | // the file or the directory 63 | if (fsObject instanceof Directory) { 64 | // if it has a child that is of type directory 65 | if (((Directory) fsObject). 66 | hasChildWithTypeAndName(Directory.class,name)){ 67 | output = "directory found in " + paths;} 68 | // if it has a child that is of type file 69 | else if (((Directory) fsObject). 70 | hasChildWithTypeAndName(File.class, name)){ 71 | output = name + "found in " + paths; 72 | } 73 | else { 74 | output = "File or Directory not found"; 75 | } 76 | }}} 77 | catch (Exception e) { 78 | output = "File/Directory not found"; 79 | } 80 | return output; 81 | }} 82 | 83 | -------------------------------------------------------------------------------- /src/main/java/helper_classes/PathHandler.java: -------------------------------------------------------------------------------- 1 | package helper_classes; 2 | 3 | import driver.IShellState; 4 | import file_system.Directory; 5 | import file_system.File; 6 | import file_system.VirtualFileSystem; 7 | import file_system.FileSystemObject; 8 | 9 | /** 10 | * This is class finds files and directories related to the shell given path 11 | */ 12 | public class PathHandler { 13 | 14 | /** 15 | * This method is used when trying to create or access some file or directory 16 | * with the path. Gets the directory from which the file/directory is 17 | * attempted to be created/accessed from and its name 18 | * @param shellState holds state of the program including root directory and 19 | * current directory 20 | * @param path is the specified path that indicates which file/directory is 21 | * attempted to be created/accessed 22 | * @return a tuple that holds directory from which the file/directory is 23 | * attempted to be created/accessed from and its name 24 | * @throws Exception if the given path is invalid 25 | */ 26 | public static DirectoryFileNameTuple getDirectoryAndFileName 27 | (IShellState shellState, String path) throws Exception { 28 | VirtualFileSystem fs = shellState.getFileSystem(); 29 | return fs.getDirectoryAndFileName(shellState.getCurrentDir(), path); 30 | } 31 | 32 | /** 33 | * This method is used when trying to access some file system object such as 34 | * file or directory with the path. 35 | * @param shellState holds state of the program including root directory and 36 | * current directory 37 | * @param path is the specified path that indicates which file/directory is 38 | * attempted to be accessed 39 | * @return the file system object indicated by path 40 | * @throws Exception if the object does not exist at given path 41 | */ 42 | public static FileSystemObject getFileSystemObject 43 | (IShellState shellState, String path) throws Exception { 44 | VirtualFileSystem fs = shellState.getFileSystem(); 45 | return fs.getFileSystemObject(shellState.getCurrentDir(), path); 46 | } 47 | 48 | /** 49 | * Get the file specified by path 50 | * @param shellState holds state of the program including root directory and 51 | * current directory 52 | * @param path is the specified path(complete or relative) 53 | * @return path described by path 54 | * @throws Exception if the path specified object at this path is not a file 55 | */ 56 | public static File getFileByPath 57 | (IShellState shellState, String path) throws Exception { 58 | VirtualFileSystem fs = shellState.getFileSystem(); 59 | return fs.getFileByPath(shellState.getCurrentDir(), path); 60 | } 61 | 62 | /** 63 | * Get the directory specified by path 64 | * @param shellState holds state of the program including root directory and 65 | * current directory 66 | * @param path is the specified path(complete or relative) 67 | * @return directory described by path 68 | * @throws Exception if the path specified object at this path is not a 69 | * directory 70 | */ 71 | public static Directory getDirectoryByPath 72 | (IShellState shellState, String path) throws Exception { 73 | VirtualFileSystem fs = shellState.getFileSystem(); 74 | return fs.getDirectoryByPath(shellState.getCurrentDir(), path); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/commands/Load.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.io.*; 4 | import java.util.List; 5 | 6 | import constants.Exceptions; 7 | import driver.IShellState; 8 | 9 | /** 10 | * This class is responsible for loading up the previously saved JShell session 11 | */ 12 | public class Load extends Command { 13 | 14 | public Load() { 15 | super(1, 1); 16 | } 17 | 18 | /** 19 | * This method will load the previous JShell session that was saved on the 20 | * file from the given path 21 | * 22 | * @param shellState is the current state of JShell program 23 | * @param arguments list of arguments that were passed along with command 24 | * @throws Exception if any of the paths is invalid 25 | */ 26 | public String executeCommand(IShellState shellState, List arguments) 27 | throws Exception { 28 | 29 | try { 30 | checkArgumentsNum(arguments); 31 | // check if load was the first to be called in new session 32 | List his = shellState.getHistory(); 33 | if (his.size() != 1) { 34 | throw new Exception("Load can only be called at the start of a session"); 35 | } 36 | String path = arguments.get(0); 37 | if (!path.contains("/")) { 38 | throw new Exception(Exceptions.WRONG_PATH_INPUT_MSG); 39 | } 40 | 41 | loadShellState1(shellState, path); 42 | return ""; 43 | } catch (IOException e) { 44 | throw new Exception(Exceptions.WRONG_PATH_INPUT_MSG); 45 | } 46 | 47 | } 48 | 49 | private void loadShellState2(IShellState shellState, String path) throws Exception { 50 | FileInputStream fileIn = new FileInputStream(path); 51 | ObjectInputStream in = new ObjectInputStream(fileIn); 52 | IShellState loadShellState = (IShellState) in.readObject(); 53 | // what do we do with it now? We want to replace the ShellState 54 | // object in method main, but we don't have a way for this use 55 | // case to reach into that method. A design problem! 56 | System.out.println(shellState.getCorrectHistory()); 57 | in.close(); 58 | fileIn.close(); 59 | } 60 | 61 | private void loadShellState1(IShellState shellState, String path) throws Exception { 62 | String line; 63 | FileReader fileReader = new FileReader(path); 64 | BufferedReader bufferedReader = new BufferedReader(fileReader); 65 | 66 | CommandController commandExecutor = new CommandController(); 67 | boolean nextPart = false; 68 | int count = 0; 69 | String currentHistory = shellState.getHistory().get(0); 70 | shellState.removeHistory(0); 71 | 72 | // load the file system 73 | while ((line = bufferedReader.readLine()) != null) { 74 | if (line.equals("*****")) { 75 | nextPart = true; 76 | } else if (!nextPart) { 77 | shellState.addHistory(line); 78 | 79 | } else { 80 | // executeCommand correct command 81 | count++; 82 | commandExecutor.executeCommand(shellState, line); 83 | } 84 | 85 | } 86 | 87 | bufferedReader.close(); 88 | // remove double history 89 | for (int i = 0; i < count; i++) { 90 | int currentSize = shellState.getHistory().size(); 91 | shellState.removeHistory(currentSize - 1); 92 | } 93 | shellState.addHistory("exit"); 94 | shellState.addHistory(currentHistory); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/commands/CommandController.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import command_decorators.Redirection; 8 | import constants.CommandException; 9 | import constants.Constants; 10 | import constants.Exceptions; 11 | import driver.IShellState; 12 | import helper_classes.CmdArgTuple; 13 | 14 | /** 15 | * Decorates and executes command appropriately based on arguments provided 16 | */ 17 | public class CommandController { 18 | 19 | /** 20 | * Executes the provided command line 21 | * @param shellState is the state of the program 22 | * @param commandLine is the given command line and arguments 23 | * @return string that is given back as command is executed 24 | * @throws Exception if any of the provided arguments is invalid 25 | */ 26 | public String executeCommand(IShellState shellState, String commandLine) 27 | throws Exception { 28 | // TODO: clean this up. 29 | shellState.addHistory(commandLine); 30 | if (commandLine.equals("")) { 31 | return ""; 32 | } 33 | // use command reader to separate command with arguments 34 | CmdArgTuple cmdArgTuple = CommandReader.parseCommandLine(commandLine); 35 | Command command = getCommand(cmdArgTuple); 36 | List arguments = cmdArgTuple.getArguments(); 37 | List optParams = getOptionalParamsAndRemoveFrom(arguments); 38 | 39 | // decorate command appropriately 40 | command = decorateCommand(command, arguments, optParams); 41 | String result = command.executeCommand(shellState, arguments); 42 | // if command doesn't result in an error add it to STD OUPOUT history 43 | shellState.addCorrectHistory(commandLine); 44 | return result; 45 | } 46 | 47 | private List getOptionalParamsAndRemoveFrom(List arguments) { 48 | // remove optional parameters, make a new list 49 | List optParams = new ArrayList<>(); 50 | for (String arg : arguments) { 51 | if (Constants.OPTIONAL_PARAM_DIC.containsKey(arg)) { 52 | optParams.add(arg); 53 | } 54 | } 55 | for (String optParam : optParams) { 56 | arguments.remove(optParam); 57 | } 58 | return optParams; 59 | } 60 | 61 | private Command getCommand(CmdArgTuple cmdArgTuple) throws CommandException { 62 | String command = cmdArgTuple.getCommand(); 63 | if (!CommandReader.isValidCommand(command)) { 64 | throw new CommandException(Exceptions.COMMAND_NOT_FOUND); 65 | } 66 | return Constants.COMMAND_DIC.get(command); 67 | } 68 | 69 | /** 70 | * Decorates the command with optional parameter(if present) and 71 | * redirection (if present) 72 | * @param command is the command to decorate 73 | * @param arguments are base arguments provided 74 | * @param optParam is a list of optional parameters provided 75 | * @return command that is decorated 76 | * @throws Exception if there is more than one optional parameter 77 | */ 78 | private Command decorateCommand 79 | (Command command, List arguments, List optParam) 80 | throws Exception { 81 | Command decoratedCommand = command; 82 | if (optParam.size() > 1) { 83 | throw new Exception("commands can only take 1 optional parameter"); 84 | } 85 | // decorate with optional parameter if necessary 86 | if (optParam.size() == 1) { 87 | String aprropDecoratorName = 88 | Constants.OPTIONAL_PARAM_DIC.get(optParam.get(0)); 89 | Class appropDecoratorClass = 90 | Class.forName("commandDecorators." + aprropDecoratorName); 91 | Constructor decConstructor = 92 | appropDecoratorClass.getConstructor(Command.class); 93 | decoratedCommand = (Command) decConstructor.newInstance(command); 94 | } 95 | // decorate with redirection if necessary 96 | int argLen = arguments.size(); 97 | if (argLen >= 2) { 98 | if (arguments.get(argLen - 2).equals(Constants.REDIRECTION_APPEND) || 99 | arguments.get(argLen - 2).equals(Constants.REDIRECTION_OVERWRITE)) { 100 | decoratedCommand = new Redirection(decoratedCommand); 101 | } 102 | } 103 | return decoratedCommand; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/command_decorators/Redirection.java: -------------------------------------------------------------------------------- 1 | package command_decorators; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import commands.Command; 7 | import constants.Constants; 8 | import constants.Exceptions; 9 | import driver.IShellState; 10 | import file_system.Directory; 11 | import file_system.File; 12 | import helper_classes.DirectoryFileNameTuple; 13 | import helper_classes.PathHandler; 14 | 15 | /** 16 | * This is a decorator that redirects output to a provided outfile 17 | */ 18 | public class Redirection extends CommandDecorator { 19 | 20 | public Redirection(Command command) { 21 | super(command); 22 | } 23 | 24 | /** 25 | * Redirect result from the command to a file provided in the arguments 26 | * @param shellState is the state of the program 27 | * @param arguments are provided arguments, including redirection type and 28 | * path of file to execute redirection on (length >= 2) 29 | * @throws Exception if path of redirection file is invalid 30 | */ 31 | @Override 32 | public String executeCommand(IShellState shellState, List arguments) 33 | throws Exception { 34 | // get arguments excluding the redirection part 35 | List baseArgs = arguments.subList(0, arguments.size() - 2); 36 | // get the output that the command executes with base arguments 37 | String contentToRedirect = command.executeCommand(shellState, baseArgs); 38 | contentToRedirect = removeErrors(contentToRedirect); 39 | // get the redirection type and path of file to redirect output to 40 | String redirectionType = arguments.get(arguments.size() - 2); 41 | String path = arguments.get(arguments.size() - 1); 42 | // get fileName and directory from which the outfile should be in 43 | DirectoryFileNameTuple wantedDirAndFileName = 44 | PathHandler.getDirectoryAndFileName(shellState, path); 45 | Directory dirToCreateFileFrom = wantedDirAndFileName.getDirectory(); 46 | String fileName = wantedDirAndFileName.getFileName(); 47 | // if file doesn't yet exist 48 | if (!dirToCreateFileFrom.hasChildWithTypeAndName(File.class, fileName)) { 49 | // create new file with String argument as its content 50 | new File(fileName, dirToCreateFileFrom, contentToRedirect); 51 | } 52 | else { 53 | // get the existing file 54 | File existingFile = 55 | Directory.findChildFile(dirToCreateFileFrom, fileName); 56 | // append or overwrite accordingly 57 | if (redirectionType.equals(Constants.REDIRECTION_OVERWRITE)) { 58 | existingFile.setContent(contentToRedirect); 59 | } else { 60 | existingFile.appendContent(contentToRedirect); 61 | } 62 | } 63 | return ""; 64 | } 65 | 66 | /** 67 | * Removes the error messages from the given string 68 | * @param result is the given string 69 | * @return the given string without error messages 70 | */ 71 | private String removeErrors(String result) { 72 | // get all the error messages 73 | ArrayList errorMessages = Exceptions.getErrors(); 74 | // remove all the error messages 75 | for (String errorMessage : errorMessages) { 76 | result = removeError(result, errorMessage); 77 | } 78 | return result; 79 | } 80 | 81 | /** 82 | * Remove the specified error message from the given string 83 | * @param result is the given string 84 | * @param error is the specified error message 85 | * @return given string without specified error message 86 | */ 87 | private String removeError(String result, String error) { 88 | // remove the error message until are none left 89 | while (result.contains(error)) { 90 | int firstIndex = result.indexOf(error); 91 | int startIndex = 0; 92 | for (int i = firstIndex; i >= 0; i--) { 93 | startIndex = i; 94 | if (result.charAt(i) == '\n') { 95 | break; 96 | } 97 | } 98 | int lastIndex = firstIndex + error.length(); 99 | if (lastIndex < result.length()) { 100 | lastIndex ++; 101 | } 102 | result = result.substring(0, startIndex) 103 | + result.substring(lastIndex); 104 | } 105 | return result; 106 | 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/file_system/FileSystemObject.java: -------------------------------------------------------------------------------- 1 | package file_system; 2 | 3 | import constants.Constants; 4 | import constants.Exceptions; 5 | import helper_classes.StringHelper; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * This class represents an object in a file system (can be a directory of file) 11 | */ 12 | public abstract class FileSystemObject implements Serializable { 13 | // this is object's name 14 | protected String name; 15 | // this is object's parent object 16 | protected Directory parent; 17 | 18 | /** Constructs an object that will be considered as root */ 19 | public FileSystemObject() { 20 | // set name and create empty list of children 21 | this.name = Constants.SYSTEM_FILE_ROOT_NAME; 22 | this.parent = null; 23 | } 24 | 25 | /** 26 | * Constructs an object that has a name, and a parent object 27 | * @param name is a name of the object 28 | * @param parent is the parent object of the object 29 | * @throws Exception if name has invalid characters in it 30 | */ 31 | public FileSystemObject 32 | (String name, Directory parent) throws Exception { 33 | // check if name is valid, throw error if not 34 | if (StringHelper.containsAny(name, Constants.INVALID_NAMING_CHAR)) { 35 | throw new Exception(this.getClass().getSimpleName() + " " + 36 | Exceptions.INVALID_NAME); 37 | } 38 | // set name and create empty list of children 39 | this.name = name; 40 | this.parent = parent; 41 | } 42 | 43 | /** Return name of this FileSystemObject */ 44 | public String getName() { 45 | return name; 46 | } 47 | 48 | 49 | /** Set name of this FileSystemObject 50 | * @throws Exception if name contains invalid characters */ 51 | public void setName(String name) throws Exception { 52 | // check if name is valid, throw error if not 53 | if (StringHelper.containsAny(name, Constants.INVALID_NAMING_CHAR)) { 54 | throw new Exception(this.getClass().getSimpleName() + " " + 55 | Exceptions.INVALID_NAME); 56 | } 57 | this.name = name; 58 | } 59 | 60 | /** Return parent of this FileSystemObject */ 61 | public FileSystemObject getParent() { 62 | return parent; 63 | } 64 | 65 | /** 66 | * Set new parent to this object 67 | * @param newParent is the new parent (directory) 68 | * @throws Exception if newParent already has child with this object's name 69 | */ 70 | public void setParent(Directory newParent) throws Exception { 71 | if (parent != null) { 72 | parent.removeChild(this); 73 | } 74 | newParent.addChild(this); 75 | parent = newParent; 76 | } 77 | 78 | /** Return the path of this FileSystemObject */ 79 | public String getPath() { 80 | // initialize result path 81 | String result; 82 | // recursively get the result path 83 | if (parent == null) { 84 | result = name; 85 | } else if (parent.getParent() == null) { 86 | result = parent.getPath() + name; 87 | } else { 88 | result = parent.getPath() + Constants.SYSTEM_FILE_PATH_SEPERATOR + name; 89 | } 90 | // return the result path 91 | return result; 92 | } 93 | 94 | /** 95 | * Check if this fileSystemObject instance is of given type and name 96 | * @param classToComp given type 97 | * @param name given name 98 | * @return boolean 99 | */ 100 | public boolean isEqualByClassAndName(Class classToComp, String name) { 101 | return (classToComp.equals(this.getClass()) && 102 | this.name.equals(name)); 103 | } 104 | 105 | abstract public String getContent(); 106 | 107 | /** 108 | * Check if current object has given fsObject as an ancestor 109 | * @param fsObject is given file system object 110 | * @return boolean 111 | */ 112 | public boolean hasAncestor(FileSystemObject fsObject) { 113 | // if fsObject is a directory and this object isn't the fsObject directory 114 | if (fsObject instanceof Directory) { 115 | if (this.equals(fsObject)) { 116 | return true; 117 | } 118 | // get current object 119 | FileSystemObject currentObject = this; 120 | // loop until meet the root or until we find fsObject as ancestor 121 | while (currentObject.getParent() != null) { 122 | FileSystemObject curParent = currentObject.getParent(); 123 | if (curParent.equals(fsObject)) { 124 | return true; 125 | } 126 | currentObject = currentObject.getParent(); 127 | } 128 | } 129 | // return false if no ancestor found 130 | return false; 131 | } 132 | 133 | abstract public void moveFsObjectIn 134 | (FileSystemObject fsObject) throws Exception; 135 | 136 | abstract public FileSystemObject cloneObject(); 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/commands/CommandReader.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import constants.Constants; 7 | import constants.Exceptions; 8 | import helper_classes.CmdArgTuple; 9 | 10 | /** 11 | * Parses command line input, recognizes a string surrounded by quotes as one 12 | * argument 13 | */ 14 | public class CommandReader { 15 | 16 | /** 17 | * Parses the input into a tuple that holds command as String and arguments 18 | * as List of Strings 19 | * 20 | * @param commandLine the input command line 21 | * @return CmdArgTuple the tuple that holds command and its arguments 22 | */ 23 | public static CmdArgTuple parseCommandLine(String commandLine) 24 | throws Exception { 25 | // split up the command line by the spaces 26 | List splited = manuallySplit(commandLine); 27 | if (splited.size() == 0) { 28 | throw new Exception(Exceptions.COMMAND_NOT_FOUND); 29 | } 30 | String command = splited.get(0); 31 | List arguments = splited.subList(1, splited.size()); 32 | return new CmdArgTuple(command, arguments); 33 | } 34 | 35 | /** 36 | * Split a string into 'arguments' where 'arguments' words surrounded by 37 | * white spaces. Anything surrounded by double quotes is considered as one 38 | * argument 39 | * 40 | * @param commandLine is the 41 | * @return the list of arguments 42 | * @throws Exception if STRING input is invalid (i.e STRING input has 43 | * quotation mark inside it" 44 | */ 45 | private static List manuallySplit(String commandLine) 46 | throws Exception { 47 | // initialize list of split arguments and current index 48 | List splittedCommandLine = new ArrayList<>(); 49 | int currI = 0; 50 | while (currI < commandLine.length()) { 51 | char currChar = commandLine.charAt(currI); 52 | if (currChar == ' ') { 53 | currI += 1; 54 | } else { 55 | /* 56 | * else, current character is the start of an argument that is needed 57 | * to be split. Get the end index of the argument and split it. 58 | */ 59 | // int endSplitI = (currChar == '"') ? 60 | // getEndStringIndex(commandLine, currI) : 61 | // getEndNonStrIndex(commandLine, currI); 62 | 63 | int endSplitI; 64 | if (currChar == '"') { 65 | endSplitI = getEndStringIndex(commandLine, currI); 66 | } else { 67 | endSplitI = getEndNonStrIndex(commandLine, currI); 68 | } 69 | 70 | String splittedArgument = commandLine.substring(currI, endSplitI); 71 | // remove the quotes if the argument is the STRING argument 72 | if (currChar == '"') { 73 | splittedArgument = 74 | splittedArgument.substring(1, splittedArgument.length() - 1); 75 | } 76 | // add the argument to the list, move on 77 | splittedCommandLine.add(splittedArgument); 78 | currI = endSplitI; 79 | } 80 | } 81 | return splittedCommandLine; 82 | } 83 | 84 | /** 85 | * Get end of a STRING input inside given string that starts at given index 86 | * 87 | * @param str given string 88 | * @param startI given start index 89 | * @return index of the last character of the STRING input 90 | * @throws Exception if STRING input is invalid 91 | */ 92 | private static int getEndStringIndex(String str, int startI) 93 | throws Exception { 94 | boolean foundEndI = false; 95 | int endI = 0; 96 | int currI = startI + 1; 97 | // make the current index the wanted end index of the string argument 98 | while (!foundEndI && currI < str.length()) { 99 | if (str.charAt(currI) == '"') { 100 | if (currI + 1 != str.length() && str.charAt(currI + 1) != ' ') { 101 | throw new Exception(Exceptions.INVALID_STRING_MSG); 102 | } 103 | endI = currI + 1; 104 | foundEndI = true; 105 | } 106 | currI++; 107 | } 108 | // throw error if no other quotation mark was found 109 | if (endI == 0) { 110 | throw new Exception(Exceptions.INVALID_STRING_MSG); 111 | } 112 | return endI; 113 | } 114 | 115 | /** 116 | * Get end of an input surrounded by spaces 117 | * 118 | * @param str given string 119 | * @param startI given start index 120 | * @return index of the last character of the input surrounded by spaces 121 | */ 122 | private static int getEndNonStrIndex(String str, int startI) { 123 | boolean foundEndI = false; 124 | int endI = startI + 1; 125 | while (!foundEndI && endI < str.length()) { 126 | if (str.charAt(endI) == ' ') { 127 | foundEndI = true; 128 | } else { 129 | endI += 1; 130 | } 131 | } 132 | return endI; 133 | } 134 | 135 | /** 136 | * This method checks if the given command is valid 137 | * 138 | * @param command the input command 139 | * @return boolean that indicates if command is valid 140 | */ 141 | public static boolean isValidCommand(String command) { 142 | return Constants.COMMAND_DIC.containsKey(command); 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/commands/Ls.java: -------------------------------------------------------------------------------- 1 | package commands; 2 | 3 | import java.util.List; 4 | 5 | import driver.IShellState; 6 | import file_system.Directory; 7 | import file_system.FileSystemObject; 8 | import helper_classes.PathHandler; 9 | 10 | /** 11 | * This class finds the content of some directory (recursively if specified) 12 | */ 13 | public class Ls extends Command implements RecursiveInterface { 14 | 15 | public Ls() { 16 | super(100, 0); 17 | } 18 | 19 | /** 20 | * Returns the content of the current Directory if path not given 21 | * If path p specifies a file, print p 22 | * if path p specifies a directory, print the content of the directory 23 | * @param shellState is the current state of JShell program 24 | * @param arguments is the paths that indicates what should be printed 25 | * @throws Exception if path is invalid 26 | */ 27 | public String executeCommand(IShellState shellState, List arguments) 28 | throws Exception { 29 | checkArgumentsNum(arguments); 30 | StringBuilder output = new StringBuilder(); 31 | // if no path is given, get content of the current directory 32 | if (arguments.size() == 0) { 33 | output.append(shellState.getCurrentDir().getContent()); 34 | } 35 | // go through all the paths and print content accordingly 36 | else { 37 | for (String path : arguments) { 38 | output.append(path).append(getContentOfObject(shellState, path)).append("\n"); 39 | } 40 | } 41 | return output.toString().endsWith("\n") 42 | ? output.substring(0, output.length() - 1) : output.toString(); 43 | } 44 | 45 | /** 46 | * Given the path of a FileSystem object, if path specifies a file, 47 | * return the path, else if path p specifies a directory, return the content 48 | * of the directory 49 | * @param shellState that holds root directory of file system 50 | * @param path is the given path 51 | * @return string as specified in the description 52 | */ 53 | public String getContentOfObject 54 | (IShellState shellState, String path) { 55 | String output = ""; 56 | try { 57 | FileSystemObject fsObject = PathHandler.getFileSystemObject(shellState, path); 58 | // if object is directory print out the path with the content 59 | if (fsObject instanceof Directory) { 60 | String objContent = fsObject.getContent(); 61 | output += objContent.equals("") 62 | ? ": \n" : ": \n" + fsObject.getContent() + "\n"; 63 | } 64 | } 65 | catch (Exception e) { 66 | output += ": " + e.getMessage() + "\n"; 67 | } 68 | return output; 69 | } 70 | 71 | /** 72 | * Get content (recursively) of file or directory at specified path 73 | * @param state is the state of the program 74 | * @param path is the given path 75 | * @return content 76 | */ 77 | public String getRecursiveContent (IShellState state, String path){ 78 | String output = ""; 79 | try { 80 | FileSystemObject fsObject = PathHandler.getFileSystemObject(state, path); 81 | // if object is directory print out the path with the content 82 | if (fsObject instanceof Directory) { 83 | output += recrusiveListing((Directory) fsObject, path); 84 | } else { 85 | output += path + "\n"; 86 | } 87 | } 88 | catch (Exception e) { 89 | output += path + ": " + e.getMessage() + "\n\n"; 90 | } 91 | return output; 92 | } 93 | 94 | /** 95 | * Lists content of current directory, and subdirectories 96 | * @param dir given directory 97 | * @param path path of parent directory 98 | * @return content of current directory, and subdirectories 99 | */ 100 | public String recrusiveListing(Directory dir, String path) { 101 | // get current directories content 102 | String content = dir.getContent(); 103 | StringBuilder output = new StringBuilder(path.equals("") ? content : path + ": \n" + content); 104 | output.append(content.equals("") ? "\n" : "\n\n"); 105 | // get content of subdirectories recursively 106 | for (FileSystemObject child: dir) { 107 | if (child instanceof Directory) { 108 | String childPath = path + "/" + child.getName(); 109 | output.append(recrusiveListing((Directory) child, childPath)); 110 | } 111 | } 112 | return output.toString(); 113 | } 114 | 115 | /** 116 | * Get content (recursively) of file or directory at specified paths 117 | * @param shellState is the state of the program 118 | * @param arguments is the list of given path 119 | * @return needed content 120 | */ 121 | @Override 122 | public String executeRecursively 123 | (IShellState shellState, List arguments) { 124 | StringBuilder output = new StringBuilder(); 125 | if (arguments.size() == 0) { 126 | output.append(recrusiveListing(shellState.getCurrentDir(), "")); 127 | } else { 128 | // for each path, recursively return content of that path 129 | for (String path: arguments) { 130 | output.append(getRecursiveContent(shellState, path)); 131 | } 132 | } 133 | // return output (remove last line break if present 134 | return output.toString().endsWith("\n") 135 | ? output.substring(0, output.length() - 1) : output.toString(); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/main/java/constants/Constants.java: -------------------------------------------------------------------------------- 1 | package constants; 2 | 3 | import java.util.Hashtable; 4 | 5 | import commands.Cat; 6 | import commands.Cd; 7 | import commands.Command; 8 | import commands.Cp; 9 | import commands.Echo; 10 | import commands.Exit; 11 | import commands.Find; 12 | import commands.Get; 13 | import commands.History; 14 | import commands.Load; 15 | import commands.Ls; 16 | import commands.Man; 17 | import commands.Mkdir; 18 | import commands.Mv; 19 | import commands.Popd; 20 | import commands.Pushd; 21 | import commands.Pwd; 22 | import commands.Save; 23 | import commands.Tree; 24 | 25 | /** 26 | * This class holds the constants variables in the program 27 | */ 28 | public class Constants { 29 | // path related constants 30 | public static final String SYSTEM_FILE_PATH_SEPERATOR = "/"; 31 | public static final String SYSTEM_FILE_ROOT_NAME = "/"; 32 | public static final String PARENT_OF_SYSTEM_FILE_INDICATOR = ".."; 33 | public static final String CURRENT_SYSTEM_FILE_INDICATOR = "."; 34 | // invalid file naming characters 35 | public static final char[] INVALID_NAMING_CHAR = {'/','.', '!', '@', '#', 36 | '$', '%', '^', '&', '*', '(', ')', '{', '}', '~', '|', '<', '>', '?'}; 37 | public static final String REDIRECTION_OVERWRITE = ">"; 38 | public static final String REDIRECTION_APPEND = ">>"; 39 | // command dictionary 40 | public static final Hashtable COMMAND_DIC = 41 | new Hashtable(); 42 | 43 | static { 44 | COMMAND_DIC.put("get", new Get()); 45 | COMMAND_DIC.put("exit", new Exit()); 46 | COMMAND_DIC.put("mkdir", new Mkdir()); 47 | COMMAND_DIC.put("cd", new Cd()); 48 | COMMAND_DIC.put("ls", new Ls()); 49 | COMMAND_DIC.put("pwd", new Pwd()); 50 | COMMAND_DIC.put("pushd", new Pushd()); 51 | COMMAND_DIC.put("popd", new Popd()); 52 | COMMAND_DIC.put("history", new History()); 53 | COMMAND_DIC.put("cat", new Cat()); 54 | COMMAND_DIC.put("echo", new Echo()); 55 | COMMAND_DIC.put("man", new Man()); 56 | COMMAND_DIC.put("mv", new Mv()); 57 | COMMAND_DIC.put("cp", new Cp()); 58 | COMMAND_DIC.put("tree", new Tree()); 59 | COMMAND_DIC.put("save", new Save()); 60 | COMMAND_DIC.put("load", new Load()); 61 | COMMAND_DIC.put("find", new Find()); 62 | 63 | } 64 | 65 | //optional parameters dictionary maps optional parameter to its decorator 66 | public static final Hashtable OPTIONAL_PARAM_DIC = 67 | new Hashtable(); 68 | 69 | static { 70 | OPTIONAL_PARAM_DIC.put("-R", "RecursiveDecorator"); 71 | } 72 | 73 | public static final Hashtable COMMAND_DOCUMENTATION = 74 | new Hashtable(); 75 | 76 | static { 77 | COMMAND_DOCUMENTATION.put("exit","Quit the program"); 78 | COMMAND_DOCUMENTATION.put("mkdir", "Create directories, each of which may" 79 | + " be relative to the current directory \n or may be a full path."); 80 | COMMAND_DOCUMENTATION.put("cd", "Change directory to DIR, which may be" 81 | + " relative to the current directory or \n may be a full path. As" 82 | + " with Unix, .. means a parent directory and a .means the current" 83 | + " directory."); 84 | COMMAND_DOCUMENTATION.put("ls", "If no paths are given, print the" 85 | + " contents (file or directory) of the current \n directory, with a" 86 | + " new line following each of the content (file or directory). \n" 87 | + " Otherwise, for each path p, the order listed: \n" 88 | + " •If p specifies a file, print p \n" 89 | + " •If p specifies a directory, print p, a colon, then" 90 | + " the contents of that directory, then an extra new line. \n" 91 | + " •If p does not exist, print a suitable message. "); 92 | COMMAND_DOCUMENTATION.put("pwd", "Print the current working directory" 93 | + " (including the whole path). "); 94 | COMMAND_DOCUMENTATION.put("cp"," Move item OLDPATH to NEWPATH, but don’t" 95 | + " remove OLDPATH. \n If OLDPATHis a directory, recursively copy the" 96 | + " contents."); 97 | COMMAND_DOCUMENTATION.put("mv"," Move item OLDPATH to NEWPATH. Both " 98 | + "OLDPATH and NEWPATH \n may be relative to the current directory" 99 | + "or may be full paths. If NEWPATH is a directory, move the item" 100 | + "into the directory."); 101 | COMMAND_DOCUMENTATION.put("pushd","Saves the current working directory by" 102 | + " pushing onto directory stack and \n then changes the new current" 103 | + " working directory to DIR. The push must be\nconsistent as per" 104 | + " the LIFO behavior of a stack. The pushd command \n saves the" 105 | + " old current working directory in directory stack so that it can" 106 | + " be \n returned to at any time (via the popd command). The size of" 107 | + " the directory \n stack is dynamic and dependent on the pushd and" 108 | + " the popd commands. "); 109 | COMMAND_DOCUMENTATION.put("popd", "Remove the top entry from the" 110 | + " directory stack, and cd into it. The removal \n must be" 111 | + " consistent as per the LIFO behavior of a stack. The popd \n" 112 | + "command removes the top most directory from the directory stack" 113 | + " and \n makes it the current working directory. If there is no" 114 | + " directory onto the \n stack, then give appropriate error message." 115 | + " "); 116 | COMMAND_DOCUMENTATION.put("history","This command will print out recent" 117 | + " commands, one command per line. \nHistory will also include" 118 | + "any syntactical errors typed by the user "); 119 | COMMAND_DOCUMENTATION.put("cat", "Display the contents of FILE1 and other" 120 | + " files (i.e. File2 ....) concatenated in the shell."); 121 | COMMAND_DOCUMENTATION.put("echo","•echo STRING: prints the provided " + 122 | "STRING argument.\nSTRING argument must be surrounded by double quotes" 123 | + "unless it consists of only one word"); 124 | COMMAND_DOCUMENTATION.put("man", "Print documentation for command"); 125 | COMMAND_DOCUMENTATION.put("get", "Retrieve the file at given URL and add" + 126 | " it to the current working directory"); 127 | COMMAND_DOCUMENTATION.put("save", "Saves the session of the JShell" 128 | + " onto a file in the given path"); 129 | COMMAND_DOCUMENTATION.put("load", "Loads the session of the JShell" 130 | + " from the file of the given path. Load must be called at the start" 131 | + "of the new session"); 132 | COMMAND_DOCUMENTATION.put("find", "The syntax of thefindcommand is as" 133 | + "follows:find path ... -type [f|d] -name expression. \n So here are" 134 | + " some examples of how thefindcommand may be used:" 135 | + "\n •find /users/Desktop -type f -name \"xyz\". This command will" 136 | + " search the directoryDesktopand find all files (indicated by type" 137 | + " f) that have the name exactlyxyz. \n" 138 | + " •find /users/Desktop -type d -name \"abc\". This command will" 139 | + " search the directoryDesktopand find all directories (indicated by" 140 | + " type d) that have the name exactlyabc. \n" 141 | + " •find /users/Desktop. This command will result in an error" 142 | + " because it has missing arguments. \n" 143 | + " •find /users/Desktop /users/Desktop1 -type d -name \"abc\". " 144 | + " This command will searchthe directoryDesktopandDesktop1 and" 145 | + " find all directories (indicated bytype d) that have the name" 146 | + " exactly abc. \n " 147 | + "•find /users/Desktop /users/Desktop1 -type f -name \"abc\". " 148 | + " This command will searchthe directory Desktop and Desktop1 and" 149 | + " find all directories (indicated bytype f) that have the name" 150 | + " exactly abc.\n" 151 | + " •If at any point one of the path in this command is invalid," 152 | + " shell will print out an error for that path,however, you must" 153 | + " continue searching for any other files or directories that may" 154 | + " exist in other valid paths. \n" 155 | + " •Thefindcommand must accept the path as relative or in absolute" 156 | + " path."); 157 | COMMAND_DOCUMENTATION.put("tree", "Tree will display the entire" 158 | + " filesystem as a tree starting from the root directory"); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/file_system/VirtualFileSystem.java: -------------------------------------------------------------------------------- 1 | package file_system; 2 | 3 | import java.io.Serializable; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import constants.Constants; 8 | import constants.Exceptions; 9 | import helper_classes.DirectoryFileNameTuple; 10 | import helper_classes.StringHelper; 11 | 12 | /** 13 | * This class is a virtual file system that stores directories and files. 14 | */ 15 | public class VirtualFileSystem implements Serializable { 16 | // this is a single reference to a File System 17 | private static VirtualFileSystem singleReference = null; 18 | // this is the root directory of file system 19 | private final Directory root; 20 | 21 | /** 22 | * This is a private constructor that creates a new file system 23 | */ 24 | private VirtualFileSystem() { 25 | root = new Directory(); 26 | } 27 | 28 | /** 29 | * If file system hasn't been created before, create a new file system; else 30 | * return the reference to the file system 31 | * @return the reference to a single file system 32 | */ 33 | public static VirtualFileSystem createFileSystemInstance() { 34 | if (singleReference == null) { 35 | singleReference = new VirtualFileSystem(); 36 | } 37 | return singleReference; 38 | } 39 | 40 | /** 41 | * This is a hack. Because sinceReference is static, we can't reset the 42 | * system when running unit tests. 43 | * This method was added to work around that. 44 | * TODO: need a better option, like make the file system non-static. 45 | */ 46 | public static void resetFileSystemInstance() { 47 | singleReference = new VirtualFileSystem(); 48 | } 49 | 50 | /** 51 | * Return root directory of the file system 52 | */ 53 | public Directory getRoot() { 54 | return root; 55 | } 56 | 57 | /** 58 | * Get the directory from which the path starts (root directory if path is 59 | * full and current directory if path is relative) 60 | * @param path is the given path 61 | * @return directory from which the path starts 62 | */ 63 | private Directory getStartingDirectoryToGoFrom 64 | (Directory curDir, String path) { 65 | return (path.startsWith(Constants.SYSTEM_FILE_ROOT_NAME) ? 66 | root : curDir); 67 | } 68 | 69 | /** 70 | * This method parses given path into a list of string names 71 | * (never including root) 72 | * @param path is a given string path 73 | * @return list of SystemFile names 74 | */ 75 | private List parsePath(String path) { 76 | // split the path by system file separator (by default: /) 77 | return Arrays.asList(path.split(Constants.SYSTEM_FILE_PATH_SEPERATOR)); 78 | } 79 | 80 | /** 81 | * This method is used when trying to create or access some file or directory 82 | * with the path. Gets the directory from which the file/directory is 83 | * attempted to be created/accessed from and its name 84 | * current directory 85 | * @param path is the specified path that indicates which file/directory is 86 | * attempted to be created/accessed 87 | * @return a tuple that holds directory from which the file/directory is 88 | * attempted to be created/accessed from and its name 89 | * @throws Exception if the given path is invalid 90 | */ 91 | public DirectoryFileNameTuple getDirectoryAndFileName 92 | (Directory curDir, String path) throws Exception { 93 | List pathAsList = parsePath(path); 94 | List pathToDirToBeAddedFrom = 95 | pathAsList.subList(0, pathAsList.size() - 1); 96 | String nameOfFileToBeCreated = pathAsList.get(pathAsList.size() - 1); 97 | Directory startingDir = getStartingDirectoryToGoFrom(curDir, path); 98 | Directory dirToBeAddedFrom = 99 | Directory.findDirectory(startingDir, pathToDirToBeAddedFrom); 100 | return new DirectoryFileNameTuple(dirToBeAddedFrom, nameOfFileToBeCreated); 101 | } 102 | 103 | /** 104 | * This method is used when trying to access some file system object such as 105 | * file or directory with the path. 106 | * current directory 107 | * @param path is the specified path that indicates which file/directory is 108 | * attempted to be accessed 109 | * @return the file system object indicated by path 110 | * @throws Exception if the object does not exist at given path 111 | */ 112 | public FileSystemObject getFileSystemObject 113 | (Directory curDir, String path) throws Exception { 114 | if (path.equals(Constants.SYSTEM_FILE_ROOT_NAME)) { 115 | return root; 116 | } 117 | DirectoryFileNameTuple dirAndFileName = 118 | getDirectoryAndFileName(curDir, path); 119 | return Directory.findChild 120 | (dirAndFileName.getDirectory(), dirAndFileName.getFileName()); 121 | } 122 | 123 | /** 124 | * Get the file specified by path 125 | * current directory 126 | * @param path is the specified path(complete or relative) 127 | * @return path described by path 128 | * @throws Exception if the path specified object at this path is not a file 129 | */ 130 | public File getFileByPath 131 | (Directory curDir, String path) throws Exception { 132 | FileSystemObject fsObject = getFileSystemObject(curDir, path); 133 | if (!(fsObject instanceof File)) { 134 | throw new Exception(Exceptions.NOT_A_FILE_ERROR); 135 | } 136 | return (File) fsObject; 137 | } 138 | 139 | /** 140 | * Get the directory specified by path 141 | * current directory 142 | * @param path is the specified path(complete or relative) 143 | * @return directory described by path 144 | * @throws Exception if the path specified object at this path is not a 145 | * directory 146 | */ 147 | public Directory getDirectoryByPath 148 | (Directory curDir, String path) throws Exception { 149 | FileSystemObject fsObject = getFileSystemObject(curDir, path); 150 | if (!(fsObject instanceof Directory)) { 151 | throw new Exception(Exceptions.NOT_A_DIRECTORY_ERROR); 152 | } 153 | return (Directory) fsObject; 154 | } 155 | 156 | /** 157 | * Return tree representation of current file system 158 | */ 159 | public String getTreeRepresentation() { 160 | return getTreeRepresentationHelper(root, 0); 161 | } 162 | 163 | /** 164 | * Make tree representation of file system rooted at given root; root is 165 | * indented by given number of spaces 166 | * @param root is given the root directory 167 | * @param numIndent is the number of spaces to indent root 168 | * @return tree representation 169 | */ 170 | private String getTreeRepresentationHelper(Directory root, int numIndent) { 171 | // initialize output with root's name 172 | StringBuilder output = new StringBuilder(StringHelper.repeat(" ", numIndent) + 173 | root.getName() + "\n"); 174 | for (FileSystemObject child: root) { 175 | if (child instanceof File) { 176 | output.append(StringHelper.repeat(" ", numIndent + 1)).append(child.getName()).append("\n"); 177 | } else { 178 | output.append(getTreeRepresentationHelper((Directory) child, numIndent + 2)); 179 | } 180 | } 181 | return output.toString(); 182 | } 183 | 184 | /** 185 | * Move an object from one path to another (path can be absolute or relative 186 | * to given directory) 187 | * @param curDir given directory 188 | * @param oldPath is the path of object to be moved 189 | * @param newPath is the path of object to be moved into 190 | * @throws Exception if either of the paths are invalid or if trying to move 191 | * a directory inside one of its sub-directories 192 | */ 193 | public void moveFsObject 194 | (Directory curDir, String oldPath, String newPath) throws Exception { 195 | FileSystemObject oldFsObject = getFileSystemObject(curDir, oldPath); 196 | DirectoryFileNameTuple newPathDirFileName = 197 | getDirectoryAndFileName(curDir, newPath); 198 | Directory dirWithNewObject = newPathDirFileName.getDirectory(); 199 | String newFileName = newPathDirFileName.getFileName(); 200 | // check if object at newPath is a subChild of object at oldPath 201 | if (dirWithNewObject.hasAncestor(oldFsObject)) { 202 | throw new Exception(Exceptions.MOVE_INTO_SUBCHILD_ERROR); 203 | } 204 | // if there is already an object at newPath, overwrite it 205 | try { 206 | FileSystemObject newFsObject = 207 | Directory.findChild(dirWithNewObject, newFileName); 208 | // if object at newPath and oldPath are the same do nothing 209 | if (!newFsObject.equals(oldFsObject)) { 210 | // else move accordingly 211 | newFsObject.moveFsObjectIn(oldFsObject); 212 | } 213 | } 214 | // else move oldFsObject into the directory with new object with new name 215 | catch (Exception e) { 216 | oldFsObject.setName(newFileName); 217 | oldFsObject.setParent(dirWithNewObject); 218 | } 219 | } 220 | 221 | /** 222 | * Copy an object from one path to another (path can be absolute or relative 223 | * to given directory) 224 | * @param curDir given directory 225 | * @param oldPath is the path of object to be moved 226 | * @param newPath is the path of object to be moved into 227 | * @throws Exception if either of the paths are invalid or if trying to move 228 | * a directory inside one of its sub-directories 229 | */ 230 | public void copyFsObject 231 | (Directory curDir, String oldPath, String newPath) throws Exception { 232 | FileSystemObject oldFsObject = getFileSystemObject(curDir, oldPath); 233 | FileSystemObject parentOfOld = oldFsObject.getParent(); 234 | FileSystemObject clonedOldFsObject = oldFsObject.cloneObject(); 235 | moveFsObject(curDir, oldPath, newPath); 236 | clonedOldFsObject.setParent((Directory) parentOfOld); 237 | } 238 | 239 | } 240 | -------------------------------------------------------------------------------- /src/main/java/file_system/Directory.java: -------------------------------------------------------------------------------- 1 | package file_system; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | import constants.Constants; 8 | import constants.Exceptions; 9 | 10 | /** 11 | * This class represents a virtual directory that can hold other FileSystem 12 | * objects such as file or directory 13 | */ 14 | public class Directory extends FileSystemObject 15 | implements Iterable { 16 | // this is a list that holds this directory's children 17 | private final ArrayList children; 18 | 19 | /** 20 | * This is an Directory Iterator 21 | */ 22 | public class DirectoryIterator implements Iterator { 23 | // this is array of objects to loop through 24 | private final ArrayList childrenArr; 25 | // this is a counter 26 | int counter; 27 | 28 | /** 29 | * Create directory iterator with an array of objects to loop through 30 | * @param children array of children that can be a file or a directory 31 | */ 32 | public DirectoryIterator(ArrayList children) { 33 | this.childrenArr = children; 34 | counter = 0; 35 | } 36 | 37 | @Override 38 | public boolean hasNext() { 39 | return counter < childrenArr.size() && childrenArr.get(counter) != null; 40 | } 41 | 42 | @Override 43 | public FileSystemObject next() { 44 | FileSystemObject fsObject = children.get(counter); 45 | counter ++; 46 | return fsObject; 47 | } 48 | 49 | } 50 | 51 | /** Constructs a directory without a parent (root directory) */ 52 | public Directory() { 53 | // set name and create empty list of children 54 | super(); 55 | children = new ArrayList<>(); 56 | } 57 | 58 | /** 59 | * Constructs a Directory that has a name, and a parent directory 60 | * @param name is a name of the directory 61 | * @param parent is the parent directory of the directory 62 | * @throws Exception if name has invalid characters in it 63 | */ 64 | public Directory(String name, Directory parent) throws Exception { 65 | // assign name, and parent directory, create list of children 66 | super(name, parent); 67 | children = new ArrayList<>(); 68 | // add this directory as a child of parent directory 69 | if (parent != null) { 70 | parent.addChild(this); 71 | } 72 | 73 | } 74 | 75 | /** Return children of this directory */ 76 | public ArrayList getChildren() { 77 | return children; 78 | } 79 | 80 | /** Add a child to this directory 81 | * @throws Exception if child with that type and name already exists 82 | */ 83 | public void addChild(FileSystemObject child) throws Exception { 84 | if (this.hasChildWithName(child.name)) { 85 | throw new Exception(Exceptions.FILE_EXISTS); 86 | } 87 | children.add(child); 88 | } 89 | 90 | @Override 91 | public String getContent() { 92 | StringBuilder content = new StringBuilder(); 93 | for (FileSystemObject child : this) { 94 | content.append(child.getName()).append("\n"); 95 | } 96 | if (!content.toString().equals("")) { 97 | content = new StringBuilder(content.substring(0, content.length() - 1)); 98 | } 99 | return content.toString(); 100 | } 101 | 102 | /** 103 | * Checks if this directory has a child with given name and type 104 | * @param childClass is the type of the child 105 | * @param name is the given name of the child 106 | * @return boolean that indicates if directory has child with that name 107 | */ 108 | public boolean hasChildWithTypeAndName(Class childClass, String name) { 109 | boolean result = false; 110 | for (FileSystemObject currentChild : this.children) { 111 | if (currentChild.isEqualByClassAndName(childClass, name)) { 112 | result = true; 113 | } 114 | } 115 | return result; 116 | } 117 | 118 | /** 119 | * Checks if this directory has a child with given name 120 | * @param name is the given name of the child 121 | * @return boolean that indicates if directory has child with that name 122 | */ 123 | public boolean hasChildWithName(String name) { 124 | boolean result = false; 125 | for (FileSystemObject currentChild : this.children) { 126 | if (name.equals(currentChild.getName())) { 127 | result = true; 128 | break; 129 | } 130 | } 131 | return result; 132 | } 133 | 134 | /** 135 | * Check if given directory has a child with given type and name 136 | * @param currentDir is given directory 137 | * @param classType is the given child type 138 | * @param name is the given child name 139 | * @return child with matching name and type 140 | * @throws Exception if currentDir directory has no such child 141 | */ 142 | public static FileSystemObject findChild 143 | (Directory currentDir, Class classType, String name) throws Exception { 144 | List curDirChildren = currentDir.getChildren(); 145 | /* 146 | * loop through children to find and return child directory that 147 | * matches by name 148 | */ 149 | for (FileSystemObject currentChild : curDirChildren) { 150 | if (currentChild.isEqualByClassAndName(classType, name)) { 151 | return currentChild; 152 | } 153 | } 154 | // throw exception because if method hasn't returned yet, no child matched 155 | throw new Exception(Exceptions.WRONG_PATH_INPUT_MSG); 156 | } 157 | 158 | /** 159 | * Check if given directory has a child with given name; if name is '.' refer 160 | * to current directory, if name is '..' refer to parent directory 161 | * @param currentDir is given directory 162 | * @param childName is the given fileSystemObject name 163 | * @return child with matching name 164 | * @throws Exception if this directory has no such child 165 | */ 166 | public static FileSystemObject findChild 167 | (Directory currentDir, String childName) throws Exception { 168 | List curDirChildren = currentDir.getChildren(); 169 | /* 170 | * if name is '.' refer 171 | * to current directory, if name is '..' refer to parent directory 172 | */ 173 | if (childName.equals(Constants.PARENT_OF_SYSTEM_FILE_INDICATOR)) { 174 | return (currentDir.getParent() != null) 175 | ? currentDir.getParent() : currentDir; 176 | } else if (childName.equals(Constants.CURRENT_SYSTEM_FILE_INDICATOR)) { 177 | return currentDir; 178 | } 179 | /* 180 | * else loop through children to find and return child directory 181 | * that matches by name 182 | */ 183 | for (FileSystemObject currentChild : curDirChildren) { 184 | if (currentChild.getName().equals(childName)) { 185 | return currentChild; 186 | } 187 | } 188 | // throw exception because if method hasn't returned yet, no child matched 189 | throw new Exception(Exceptions.WRONG_PATH_INPUT_MSG); 190 | } 191 | 192 | /** 193 | * Removes directory's child with current name(if present) 194 | * @param fsObject reference child file object 195 | */ 196 | public void removeChild(FileSystemObject fsObject) { 197 | children.remove(fsObject); 198 | } 199 | 200 | /** 201 | * Removes directory's child with current name(if present) 202 | * @param fsObjectName given child name 203 | */ 204 | public void removeChildByName(String fsObjectName) { 205 | try { 206 | removeChild(findChild(this, fsObjectName)); 207 | } catch (Exception e) { 208 | System.out.println(e.getMessage()); 209 | } 210 | } 211 | 212 | /** 213 | * Check if given directory has a directory child with given name 214 | * @param currentDir is given directory 215 | * @param dirName is the given directory name 216 | * @return child with matching name 217 | * @throws Exception currentDir directory has no such child 218 | */ 219 | public static Directory findChildDirectory 220 | (Directory currentDir, String dirName) throws Exception { 221 | return (Directory) findChild(currentDir, Directory.class, dirName); 222 | } 223 | 224 | /** 225 | * Check if given directory has a file child with given name 226 | * @param currentDir is given directory 227 | * @param fileName is the given directory name 228 | * @return file child with matching name 229 | * @throws Exception currentDir directory has no such child 230 | */ 231 | public static File findChildFile 232 | (Directory currentDir, String fileName) throws Exception { 233 | return (File) findChild(currentDir, File.class, fileName); 234 | } 235 | 236 | /** 237 | * Find next directory by moving either backwards (to parent) or forward 238 | * (some child directory) from given directory according to the given string 239 | * @param currentDir is the given directory 240 | * @param nextDirectory is string that indicates which directory to move to 241 | * @return directory that matches nextDirectory 242 | * @throws Exception if cannot move from this directory to directory that 243 | * matches nextDirectory 244 | */ 245 | public static Directory findDirectory 246 | (Directory currentDir, String nextDirectory) throws Exception{ 247 | Directory wantedDirectory = currentDir; 248 | if (nextDirectory.equals(Constants.PARENT_OF_SYSTEM_FILE_INDICATOR)) { 249 | /* 250 | * if nextDirectory is the 'go to parent directory' indicator, 251 | * move to current directory parent; remain in the current directory if 252 | * it doesn't have a parent or if nextDirectory is an empty String 253 | */ 254 | if (currentDir.getParent() != null) { 255 | wantedDirectory = (Directory) currentDir.getParent(); 256 | } 257 | } else if (!nextDirectory.equals(Constants.CURRENT_SYSTEM_FILE_INDICATOR) 258 | && !nextDirectory.equals("")) { 259 | /* 260 | * else if nextDirectory isn't the 'current directory' indicator (do 261 | * nothing if it is), check to see any child directory of current one 262 | * matches the next directory name in the list by name 263 | */ 264 | wantedDirectory = findChildDirectory(currentDir, nextDirectory); 265 | } 266 | return wantedDirectory; 267 | } 268 | 269 | /** 270 | * Find the directory starting from given directory, moving either backwards 271 | * (to its parent) or forward (to one of its children) according to the 272 | * given list of directory names 273 | * @param currentDir is the starting directory 274 | * @param listOfDirNames is list of directory names to move through 275 | * @return directory that is there after moved through the entire list 276 | * @throws Exception if at some point, next item on the list cannot be moved 277 | * to from current directory 278 | */ 279 | public static Directory findDirectory 280 | (Directory currentDir, List listOfDirNames) throws Exception { 281 | // move in order through each directory in the list 282 | for (String nextDirectory: listOfDirNames) { 283 | currentDir = findDirectory(currentDir, nextDirectory); 284 | } 285 | return currentDir; 286 | } 287 | 288 | /** 289 | * Moves given file system object into the current directory, overwriting 290 | * existing file in current directory (if they have the same name) 291 | * @param fsObject the file object to be moved in this directory 292 | */ 293 | public void moveFsObjectIn(FileSystemObject fsObject) { 294 | removeChildByName(fsObject.getName()); 295 | try { 296 | fsObject.setParent(this); 297 | } catch (Exception e) { 298 | System.out.println(e.getMessage()); 299 | } 300 | } 301 | 302 | @Override 303 | public Iterator iterator() { 304 | return new DirectoryIterator(children); 305 | } 306 | 307 | /** 308 | * Constructor for cloning purposes 309 | */ 310 | @Override 311 | public FileSystemObject cloneObject(){ 312 | Directory clonedDirectory = new Directory(); 313 | try { 314 | clonedDirectory = new Directory(name, null); 315 | for (FileSystemObject child : this) { 316 | FileSystemObject childClone = child.cloneObject(); 317 | childClone.setParent(clonedDirectory); 318 | } 319 | } catch (Exception e) {System.out.println(e.getMessage());} 320 | return clonedDirectory; 321 | } 322 | } 323 | --------------------------------------------------------------------------------