In this exercise you will:
Design the first version of a visual interactive XML pretty-printer | |
Produce a set of UML class and sequence diagrams to document your design | |
Experience design patterns in actual Java code | |
Use existing unit tests to test changes to existing code | |
Experiment with refactoring, assertions, and simple package design. | |
Use Swing to create a simple graphical user interface |
The deadline for this exercise is Thursday, April 14th, 2005.
In this exercise you need to write an interactive program - a window-based program that presents HTML conversions of an XML file, while waiting for the user to enter commands and responding to the ones it knows. The program will be based on the XML pretty-printer you wrote in exercise 1, and enable the creation of multiple HTML views of an input XML file, each displaying different parts of the document in different ways.
Write an executable program called 'xmli' (or a main class Xmli in Java), which takes exactly two command-line arguments - a file name of an XML file, and the number of HTML views to show. The program starts by displaying a visual form, with a frame for each view, a text box for entering commands, and a results label for command outputs. It then waits for commands from the user. The input file must be a valid XML document, under the requirements of the xmlp program you developed in exercise 1. Each command is a line of text; the program responds to each command and then returns to wait for the next one.
The program must recognize the following commands:
edit [output-name]
This
command sets the current view to the given view name, meaning that all
subsequent select commands will refer to that view, until another
'edit' command is entered. The names of the output views are the numbers
from 1 to maxviews, where maxviews
is xmli's second command line argument;
the initial view is 1.
This
command prints to the results label the line: "Now editing view
[view-number]
".
select [tag-name]
[count]
tags", where [count]
is the total number of selected tags in
this command, including parents of child nodes and children of composite tags that were selected. Each tag
(and particularly the root) should be counted once.upcase [tag-name]
This command changes all existing views to display all tags with the given name in upper case in the
HTML output. The tag name itself should be displayed in
uppercase in the output; if it is a text tag, then the text should be in
uppercase as well, but if it's a composite tag, then child tags should not be
modified. Attributes are not affected by this command.
This command only affects the views in the current
state: if a tag is selected in a view (using select) only after an
upcase command for that tag, then that tag should not be displayed in
uppercase. The upcase
command only affects tags that
are already displayed.
This command prints to the results label the
names of the views that were affected by it, in this format: "Modified views:
view1, view2, ...", where view1, view2 and so forth are the names of the views
that were modified by this command. It is required that the time required to
create this line will be proportional to the number of modified views, and not
to the number of all views.
locase
This command is
similar to upcase, but causes the output text to be displayed in lower-case
instead of upper-case letters. All other behavior and rules are exactly the
same.
undo
Results in
"undoing" the last command - all the above four commands are undoable. Undo
can be called repeatedly to undo a series of commands. If
nothing can be undone when undo is called, then "Nothing to undo" is printed to
the results label. Otherwise, undo prints a line depending on the reversed command:
When undoing edit
: "Now editing view [view-number]" (of the current view
after the undo).
When undoing select
: "Deselected [count] tags", where [count] is the number of
tags that the reversed command selected.
When undoing upcase
or locase
: "Modified views: view1, view2, ..." where
the view numbers are the ones affected by the undo. Note that locase
does not undo upcase
or vice
versa, since the original text may be mixed-case.
Exiting the program is by the using the X button at the upper-right corner of the window. Errors, such as requesting an unknown command or giving illegal parameters, should result in an informative error message on the results label, and a safe return to waiting for the next command.
There are no commands for printing the output - all views must show the selected tags, in HTML format and in mixed, lower or upper-case as requested, all the time. The XML parsing and conversion to HTML must be done using the code from xmlp; the simplest way to display the HTML on the screen is by using Swing's JEditorKit. The multiple views can be created by placing a JTable on the screen with one row and a column for each view; each cell in the JTable can contain a JEditorKit that displays that view.
In addition, there are two requirements regarding the performance of the
program. This is because of the fact that although xmli is now an interactive
program, in future versions is may be used as a server-side component, to which
other computers will send requests (as strings in the above formats) over the
network. The program may then have to handle thousands of views concurrently, and
propagate changes to large groups of them (through the upcase
and locase
commands). To support this, the following is
required:
Each view must consume the minimal necessary amount of memory. In particular, you are not allowed to copy the selected tags of each output into its own XML document object. That would be a waste of memory.
When displaying the names of modified views after executing or undoing an upcase or locase command, the time required to compute this list of views must be proportional to the number of affected views , and not to the total number of views. Looping over all views is too slow.
In this exercise, you do not start from scratch but instead rely on the existing code base of exercise 1. You are required to use that code for the XML parsing and HTML creation - future changes and features done by the xmlp developers must be easy to incorporate in the xmli program, so these two programs have to share common code. You may change the code of exercise 1 for this exercise if you have to, but under one condition: the unit tests of exercise 1 are maintained as well. You should submit a set of passing unit tests for xmlp together with this exercise. If you add functionality inside exercise 1 classes, you must add to its unit tests as well to test the additions.
As with the xmlp program, this is only the first version of xmli , and it is crucial to maintain an open mind with respect to possible future requirements. Your design must specifically prepare for these additions:
It may be required to support more modifications on selected tags than just turning text to uppercase or lowercase. For example, new commands can be added to translate tags to another language, sort the output based on tag names or text, hide attributes and so forth. Just like upcase and locase, these commands will be applied to a group of views, but should not affect views that will select these tags later.
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 three sentences long, which explains how it should be coded. An in exercise 1, three sentences are enough if your refer to known design patterns, which are easily supported by your design.
This exercise intends you to divide your time equally between actual coding and between design, writing UML diagrams, and answering the questions. Code in Java, and use the standard libraries to their full extent - including Swing, and excluding existing XML parsers as was in ex1.
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. You are required to use JUnit, and to submit unit tests for both xmlp and xmli code.
An ant build file must be submitted with this exercise in order to build it. Its default task must perform a full build: compile all files of both xmlp and xmli, and run all unit tests for both applications.
The code you submit must be built with no compiler warnings, and pass all unit tests.Coding & unit testing in this exercise include experimentation with three issues that were not considered in ex1: refactoring, assertions and package design. To explain how you used these issues in your code, answer the following three questions in your README file (these three questions together with the three design questions replace the six design questions from ex1). Each answer should be up to one paragraph long. Here are the questions, with some guidelines about how to deal with each issue:
Our course uses the department's regular submission system; submit a zip file as usual, with the following contents:
All program source code, ant build file and a small script to run the program. Include all the code of exercise 1 in addition to all new code. | |
All unit tests source code, for both xmlp and xmli. | |
UML class diagrams, describing all classes in the program, including exercise 1 classes. There can be one or several diagrams, as long as they are readable. | |
UML sequence diagrams of two non-trivial object interactions of your choice. | |
The README file, with the usual contents (IDs, logins and full names, descriptive list of files and features) and answers to the three design questions and three coding questions above. The README file should also describe parts of the design or design choices. |
The submitted structure of this exercise is as before.
How to Start
Read these general guidelines for Object-Oriented design (especially 'Design Guidelines') | |
Re-read about the Command, Observer and Strategy design patterns; some of the structural and creational patterns may also be useful here. | |
Design the program; start with the data structures, then the major operations, and finish with the "main" program. Create UML class and sequence diagrams (see also this tutorial) as you go. | |
During the design, add pre- and post-conditions to important methods, and state an invariant for each class and interface. | |
Read about unit testing and the JUnit framework before starting to code. | |
Code the program in the same three steps, writing unit tests in parallel with code. That is, write a test class for building the data structures, then a test class for the main operations, then a test class for the main program. | |
If during the coding and testing process you decide to change the design, maintain the UML diagrams to reflect the changes. | |
In every step of the way - design, code and test - regard the exercise 1 code as part of this exercise's code, which can be refactored as required. Consult the documented refactorings and see if they match any "bad smells" in your existing code. | |
Register to the course and then submit the exercise according to the above instructions. |
Good luck!