Exercise 3 - Zip Synchronizer
Design, Code and Unit-Test Using Design Patterns
Deadline April 5th, 2006 at Ross closing time
Description In this exercise you will:
  • Design and build a utility to synchronize a set of directories and/or zip files
  • Produce a set of UML package, class and sequence diagrams to document your design
  • Experience design patterns in actual Java code
  • Write a covering set of unit tests
  • Experience maintenance of code, design, unit tests and build file
  • Experience working with and testing a Swing application

Overview

Create a Java Swing application named ixzip which is able to print and extract the contents of ZIP files and directories, and synchronize them. The program's usage from the command line is ixzip [views], where views is an optional number between 2 and 9, with a default value of 3. The program opens a window which contains one text box for entering user commands, one "Ok" button for executing the entered command, one label to display messages about the last action performed, and a set of views (whose number is determined by the views command-line argument), which can contain multiple lines of text.

Viewing Directories and ZIP Files

The views are numbered 1 to 9 from left to right. The following commands are used to open and display views:

  • open N as [directory or zip file] - This command opens the given zip file or directory, and prints its contents inside view number N. Printing is done exactly as done in xzip from exercise 1. A directory and its files are printed exactly as if they were a zip file with the same name containing the same files.
    On success, the text "opened [directory/zip file name] in view N" should appear in the message bar.

  • close N - This command closes view number N, clearing its display, and canceling any previous copy or sync commands in which it is mentioned (these two commands will be explained below). When the program starts, all views are closed.
    On success, the text "closed view N" should appear in the message bar.
    Calling close on a view that is already closed is legal. Calling open on an already open view is legal, and is equivalent to closing that view and then reopening it. For example, the following two sequences of commands are equivalent:
         open 1 as c:\web  ;  close 1  ;  open 1 as d:\my.zip
         open 1 as c:\web  ;  open 1 as d:\my.zip

  • display <short/long> - This command toggles whether views are displayed in short or long format, as defined for the -s and -l command-line arguments of xzip respectively. Executing this command changes the display of all open views to reflect the new setting immidiately. When the program start, short display is active.
    On success, the text "[short/long] display is active" should appear in the message bar.

In case of error, the message bar should contained an informative message describing it. Quitting the program is done by pressing the X button on its window's upper right corner, and this naturally closes all views.

Copying and Synchronizing Views

The main function of ixzip is not to display zip files and directories, but rather to make copies and synchronize them. Selecting what will be copied where is done using the copy command:

  • copy X to Y - Select all the files and directories (recursively) in view number X to be copied into view number Y. If the same file name already exists in view Y, it will be overwritten. The display of view Y should be immediately modified to reflect how it will appear after the copy operation. Each file or directory that will be copied from a different view should prefix its name with that view number in parentheses.
    On success, the text Marked view X to be copied to view Y should appear in the message bar.

For example, assume that the following views have been opened:

1

2

3

one.txt
two.txt
others
   three.txt

one.txt
four.txt

one.txt
four.txt
others
   five.txt

Then after executing the command copy 1 to 2, the display will be as follows:

1

2

3

one.txt
two.txt
others
   three.txt

(1) one.txt
four.txt
(1) two.txt
(1) others
   (1) three.txt

one.txt
four.txt
others
   five.txt

The order of printed files in each view may be different in your program, since the printing order of files within a directory is undefined. Note that the copy command only marks files to be copied - actually making the copy is only done via the commit command, as the next section will explain. There are two special rules regarding the copy command:

  • Rule of transitivity - The command copy X to Y marks for copying not only the actual files of view X, but also any other files or directories that are already marked to be copied into it. Other views that are copied from view Y need to be updated according to this rule as well.

For example, after executing the command copy 2 to 3 in the previous example, the display will show:

1

2

3

one.txt
two.txt
others
   three.txt

(1) one.txt
four.txt
(1) two.txt
(1) others
   (1) three.txt

(1) one.txt
(2) four.txt
(1) two.txt
others
   five.txt
   (1) three.txt

The second part of the rule of transitivity means that the order of copy commands doesn't matter: Executing copy A to B and then copy B to C has the same effect as executing copy B to C and then copy A to B. In the above example, the display would look the same if we executed copy 2 to 3 first and copy 1 to 2 afterwards.

  • Rule of cycles - Whenever a copy X to Y command causes a cycle to be created between two or more views, then for every file that exists in more than one of these views, the most up-to-date file (as dictated by its last modification time) should be copied to all these views. If two versions have the exact same last modification time, then the version from the smallest view number should be copied to all these views.

For example, assume that the most up-to-date version of one.txt is in the directory or zip file displayed in view 1, that the most recent version of four.txt is in view 2, and that the most recent version of others is in view 3. Then, after executing the command copy 3 to 1 on the above table, the display will show the following:

1

2

3

one.txt
(2) four.txt
two.txt
(3) others
   (3) five.txt
   three.txt

(1) one.txt
four.txt
(1) two.txt
(3) others
   (3) five.txt
   (1) three.txt

(1) one.txt
(2) four.txt
(1) two.txt
others
   five.txt
   (1) three.txt

The rule of cycles preserves the property that the order of copy commands executed on a set of views doesn't matter, even when cycles are created. Calling copy X to Y after X is already copied to Y through some cycle (for example, calling copy 1 to 3 on the above table) is legal, and similarly calling copy X to Y twice is legal. Note that whenever a cycle occurs, the list of files and directories as well as the source view for each file will be the same in all views participating in the cycle. This has the effect of synchronizing all the views in the cycle, and to make this common operation easier for users, the following command is defined:

  • sync X and Y - This command is equivalent to the two commands copy X to Y and then copy Y to X.
    On success, the text Marked views X and Y to be synchronized should appear in the message bar.

Whenever a view is closed, all copy and sync operations involving it are discarded. For example, the following sequence of commands:
     open 1 as c:\web
     open 2 as d:\web.zip
     open 3 as e:\backups\web
     copy 1 to 2
     copy 2 to 3
     copy 3 to 1
     close 2
Is equivalent to this series of commands:
     open 1 as c:\web
     open 3 as e:\backups\web
     copy 3 to 1

Commit and Rollback

While copy and sync enable a user to mark files and directories for copying and view the results, actual changes to the file system are only caused by this command:

  • commit - This command performs all the marked copies in the actual file system. This can involve directory to directory, directory to zip file, zip file to directory or zip file to zip file transfers. After this operation all views should be refreshed, and all the previous copy/sync commands are discarded.
    On success, the text Copy operations were committed should appear in the message bar.

For example, after executing commit on the display from the end of the previous section, files will be copied and then the display will show:

1

2

3

one.txt
four.txt
two.txt
others
   five.txt
   three.txt

one.txt
four.txt
two.txt
others
   five.txt
   three.txt

one.txt
four.txt
two.txt
others
   five.txt
   three.txt

The user can also decide not to perform actual copying of the marked files, using this command:

  • rollback - This command discards all previous copy/sync commands, and refreshes all views. This is equivalent to closing and reopening all views in a single command.
    On success, the text Copy operations were rolled back should appear in the message bar.

For example, after executing rollback on the display from the end of the previous section, no files will be copied and the display will show:

1

2

3

one.txt
two.txt
others
   three.txt

one.txt
four.txt

one.txt
four.txt
others
   five.txt

Undo and Redo

The last two commands that ixzip should support are the following:

  • undo - Undo the last command. The open, close, copy, sync and display commands can be undone, and the result of undoing them should restore the program to its exact state before the command was executed. On success, the text Command [command name] was undone should appear in the message bar. The commit and rollback commands cannot be undone, and trying to undo them should result in an informative error message. The user can undo an unlimited number of commands - that is, the entire history of commands since program startup or the last commit or rollback command should be kept.

  • redo - Redo the last command that was undone; or in other words, undo the last undo operation. This command can only be called if command preceding it was undo; if undo was called multiple times, then redo can be called multiple times as well to redo all these undo commands. On success, the message bar should contain the text of the relevant command that was redone.

As an example, the following table demonstrates a list of commands, and the text that should appear in the message bar after each command:

Command: Message bar after the command:

open 1 as c:\projects

Opened c:\projects in view 1

open 2 as d:\projects

Opened d:\projects in view 2

undo

Command open was undone

open 2 as d:\backup\projects.zip

Opened d:\backup\projects.zip in view 2

redo

Error: Cannot redo since last command was not undo

sync 1 and 2

Marked views 1 and 2 to be synchronized
undo Command sync was undone
redo Marked views 1 and 2 to be synchronized

commit

Copy operations were committed

undo

Error: No commands to undo

Performance and Testing Considerations

Although ixzip is an interactive program supporting at most nine views, in its next version the same code is planned to be used as a synchronization server, and will be required to handle up to thousands of concurrent synchronizing client directories and zip files. This has two implications. First, you should design this program as a performance-critical application:

  • The time required to handle a copy/sync command must be proportional to the number of involved views, and not to the number of all views. Iterating over all views is unacceptable.
  • The time required to handle a commit command must be proportional to the number of files and directories being copied, and not to the total number of files and directories in the open views.
  • Saving on memory is important as well: Zip files should be extracted to memory only when it is necessary to do so, and not immediately when a zip file is opened into a view.

Second, you should make it easy to reuse as much of the program's code as possible in a different executable that will not have a Swing user interface:

  • Maintain a very clear separation between the Swing user interface class(es) and all other program code. The Swing layer should be as thin as possible, and should be encapsulated in a separate Java package.

Such a separation is important in every application that contains a graphical user interface for another reason: unit testing. Note that it is impossible to directly unit-test a GUI, since you have no way to replace the human using the keyboard and mouse. Unit tests only work on objects, and so you must maintain the amount of code that you don't unit test (and only test manually, in this exercise) to an absolute minimum.

Design

Answer the following questions about your design, in one or two paragraphs at most:

  1. Explain how your code is divided into packages, and what is the dependencies graph between packages. Explain the rationale behind this division.
  2. Explain how your design handles a copy/sync command in a time that is proportional to the number of involved views, and not to the number of all views.
  3. Explain how your design handles a commit command in a time that is proportional to the number of files and directories being copied, and not to the total number of files and directories in the open views.

Then, for each of the following possible future requirements from ixzip, explain in 2-3 sentences how your design can be easily extended to implement them.

  1. It may be required to add a recursion <of/off> command, which toggles whether copy and sync commands operate recursively on directories or not. Note that the default, which you must code and test in this exercise, is to copy directories recursively.
  2. It may be required to support copy/sync of a subset of files from one view to another. For example, a command such as copy *.java from 1 to 2 would mean that only *.java files should be copied from view 1 to view 2.
  3. It may be required to support other commands on files displayed in views, for example to rename a file or directory, delete a file or directory, move a file from one view to another and so on. Undo and redo functionality may be required for such commands as well.

Code & Unit Test

All the code & unit test guidelines from Exercise 1 apply to this exercise as well. In addition, you are required to use the code base and tests you developed for xzip, and you must submit it as well. The submitted code, unit tests, UML diagrams and Ant build file should include both xzip and ixzip in full. You are allowed to make any changes in your xzip code to make it more easily reusable for ixzip, but note that you will have to make sure that xzip still works after these changes, and to maintain its unit tests as well.

The time and effort required to complete this exercise highly depend on the quality of your design. The recommended order in which to think about your design is to design the required data structures first, the classes and operations that use these data structures second, and the Swing UI and main program flow last. Also, think in advance about how to partition your code into packages, and provide separate test classes for each package.

Submission Submit a zip file which contains the following:
  • All program source code, for both xzip and ixzip.

  • All unit tests source code, for both xzip and ixzip.

  • An Ant build.xml file, whose default target compiles and runs all unit tests for both xzip and ixzip.

  • UML diagrams, which should include a package diagram describing the dependencies between all your packages, class diagrams that cover all classes (from both xzip and ixzip), and at least four sequence diagrams (two from xzip and two new ones about important interactions in ixzip).

  • A README file, with the usual contents (IDs, logins and full names, descriptive list of files and features) and answers to the six possible extensions in the design section above. The README file should also describe parts of the design or design choices that are not evident from reading the UML diagrams.

  • The Eclipse project file, to enable opening your project and reading all of the above files from within Eclipse.

Resources