Description |
In this exercise you will:
- Design and build a file system manager - Kraken
- Produce a set of UML class and sequence diagrams to document your design
- Experience design patterns in actual C++ or Java code
- Write a covering set of unit tests
Requirements
In this exercise you will develop kraken - a simple shell for manipulating files.
kraken command line is: kraken <root directory>
The shell will start in the given root directory. Its prompt is:
kraken:DIR> where DIR is the same with unix - / for the root, /a/b/c for
directory c under directory b under directory a under the root directory, and so on.
The file system (and its types) are the same used in exercise 1. One change
from exercise 1 is that you have to support all the mime types specified in the
given list. If the file extension is missing from the list (or if it has
no extension) then write "unknown" as MIME type.
Commands
- Display:
cd <path> - sets the current directory to path .
cd .. sets the current directory to the parent directory, except when
the current directory is the root directory (same as unix cd command works).
The / character specifies the root directory, as given when starting kraken.
list [-n] [-d] [-r] - prints the structure of the current directory in xml format.
The format and behaviour are the same as in exercise 1. The -n and -d parameters are the same as
nameonly an dironly (respectively), and -r means the list should be recursive - descend into
directories (as was the default in exercise 1).
- File Manipulation:
copy [-r] <file|dir> <destination> - copies the file to the destination
location (same as the unix cp command works). The -r parameter means recursive
copy - if the copied file is actually a directory, then all the files and directories that it contains
(recursively) will be copied as well.
move <file|dir> <destination> - moves the file/directory to the destination
location. Just like the unix mv command works, this command can also be used to either
move a file, rename it or do both things at once.
delete <file|dir> - deletes the file. Only an empty directory can be deleted.
- Action Manipulation:
commit - performs the copies/moves/deletes done since the last commit or rollback to
the actual file system. Commited actions cannot be undone (using undo ). The commit
action is the only one that causes changes to the real file system. All other actions happen only in
memory, and execute in batch mode if and when commit is called. The cd is not
executed on the real file system.
rollback - undoes all the actions done from the last commit or rollback. This is equal to
calling undo for all the actions done since the last commit/rollback.
undo - undoes the last action done. If no such action exists, does nothing. All commands can
be undone except list , commit and rollback . It is possible to call
undo an unlimited number of times, to undo all actions done since the last commit or rollback.
redo - redoes the last undo'ed action. If no such action exists or if the last action wasn't
undo , does nothing. It is possible to call redo an unlimited number of times, to redo
all undone actions.
- Mirrorring:
mirror <dirA> <dirB> - mirrors dirA and dirB. This
means the following:
- Any copy, move or delete operation done on dirA should be done on dirB, and vice versa
(the mirroring is symmetric).
- No mirror can be established between a directory and one of its ancestors.
- If dirA and dirB are mirrored, then copying or moving dirA into dirB (or vice versa) is not allowed.
Deleting either DirA or DirB is not allowed as well.
-
If dirA (or dirB) is moved or renamed, the mirror is kept with the directory in its new location/name.
If dirA (or dirB) is copied, then dirB is mirrored with both the original dirA (or dirB) and its new copy.
- If a copy, move or delete is done on a file or directory that exists only in one of the mirrored directories,
then nothing is done in the other mirrored directory.
- Mirroring is transitive - if dirA mirrors dirB, and dirB mirrors dirC, then any action done on any of the
three directories, is done in all three of them.
unmirror <dirA> <dirB> - "breaks" the mirror between dirA and dirB.
General:
Here is a small example of the shell:
kraken:/> cd docs
kraken:/docs>cd images
kraken:/docs/images>copy a.gif ../newimages
kraken:/docs/images>cd ..
kraken:/docs/mirror images1 images2
Here is an algorithm for handling the mirror:
- Translate command to full paths
- Loop over all mirrors, and replace strings where they match
(bi-linear)
- Build list of strings to execute. Don't add duplicate strings, stop
checking for matches when the list stops changing.
- Execute the final list of commands. The order is undefined, except
the fact that the original command must be executed first.
- That same list in the same order is executed upon commit. Undo does
the list in the exact same order.
- If any command fails (or illegal) - ignore it.
- Move is not a mirrored command. After executing an 'mv' command,
don't check for mirrors at all.
For example:
assume we have the following:
/
+A
|+B
| +C
| +a.txt
+D
|+B
| +C
| +a.txt
There are two mirrors : /A-/D, /A/B/C-/D/B/C. Here is the command:
kraken:/A/B/C>copy a.txt b.txt
First, we normalize the command:
copy /A/B/C/a.txt /A/B/C/b.txt
Then, we add the commands from the mirror /A-/D:
copy /A/B/C/a.txt /D/B/C/b.txt
copy /D/B/C/a.txt /A/B/C/b.txt
copy /D/B/C/a.txt /D/B/C/b.txt
Then, we add the commands from the mirror /A/B/C-/D/B/C:
nothing new is added
So we execute the following:
copy /A/B/C/a.txt /A/B/C/b.txt (original command, executed first)
copy /A/B/C/a.txt /D/B/C/b.txt
copy /D/B/C/a.txt /A/B/C/b.txt
copy /D/B/C/a.txt /D/B/C/b.txt
Also notice that there are overwrite of files in the copy command, so please address it.
Future requirements
Consider the following possibilities, and address them in your README.html:
- Presume we have another command,
backup <name> , which saves the system's status.
The command restore <name> restores the entire system to the named backed-up version.
How would you implement this command? How would you implement the restore?
- How would you add symbolic links to system? All the operations should work on the linked file
except delete, which should delete the link itself. Explain how you would implement
cd
and mirror when the link points to a directory.
- Suppose we have the following command:
define <mime-type> <viewer> which
sets the viewer of files with that mime-type (for example, a browser fro html files). The viewer will
be launched, in a separate process, when the file name is written in the shell.
- Suppose we have a
refesh command which synchronizes the memory file system with the
actual file system. This is useful when the actual file system is manipulated while kraken is running
and there are un-commited actions. Refresh should notify the user on all the un-commited actions that
are no longer valid. refesh cannot be undone.
- Consider actions are immediately flushed to the file system (as Windows Explorer
and Konqueror are working). How would you change your application? In your answer adress all
the commands listed above. (You can elaborate here...)
You must design your program so that it is easy to add code that implements the
above requirements. For each of the above requirements write an explanation in your README file,
not more than five sentences long, which explains how it should be coded. Use the patterns vocabulary,
as well as references to the classes in your design.
Code & Unit Test
This exercise intends you to divide your time equally between actual coding and between design,
writing UML diagrams, and answering the above design questions. You must base your implemetation
on the submitted code from exercise 1. Refactor it if necessary - document these refactorings in the
README.html file.
It is also required that you submit unit tests to test your work. Organize your unit tests into
classes by subject, and write a method for each small test. Each test should be self-validating -
that is, know by itself whether it has passed or failed. Writing unit tests should be an integral
part of coding, and is essential when code must be changed in newer versions.
The code you submit must be built with no compiler warnings, and pass all unit tests.
One metric for measuring the usefulness of a set of unit tests is called coverage, which means
the percentage of your code that the unit tests actually run. Coverage of 90% or above is
considered good, and you should aim to that goal.
This is an advanced course, so there is no intention to take points for coding style or
naming conventions - the emphasis is on proper design. However, you are as always expected
to write clear code with a consistent style.
README.html - In order to simplify the usage of UML, you are required to export your
UML diagrams to image files (jpg or gif) and display them in an HTML file called README.html.
This file will replace the README file. It is recommended that you will take advantage of HTML's
capabilities (headlines, tables, lists, etc.) but it is not required. No fancy JavaScript/CSS is required
as well. You are required to add a meta tag to the header with your logins like this: <meta name="students" content="bart, lisa">
Example README.html can be found here.
|