Chapter 5 continued. Web Site Manager - Design and Implementation
In the previous chapter, we developed a use-case
analysis of the Web Site Manager. In this chapter, we’ll use that analysis to
guide a design and implementation.
Our approach:
·
Flesh out the design model
·
Implement the graph and tool models, then their
user interfaces
·
Add in the tree system, and its user interface
·
Discuss how we’ve used an old framework,
and defined a new framework.
We’ll develop the model before the user
interface, because the user interface is almost always “most likely to change.”
(Should it be a GUI? Should it use Swing or AWT? Should the current node be on
top? Is green the right color for this?) The object model is more stable: the
system will still be a web site manager if it doesn’t use Swing, but not if it
no longer deals with web sites.
Design Model
The screen design reflects three parts of the
program:

We have three models to merge:
·
Analysis object model
·
Selection model
·
Graph framework
We’ll begin by adopting the object model from
analysis, and see how it looks.

The Tool needs to know its Site. Also, we’d like
to know the Tool’s name. We didn’t identify this as a property before. (So,
we’ll add a method “String getName()”
to Tool.)
Design Model -
Selection
“A page is selected, and tools operate on it.”
The page is important, and so is the tool, but realizing that a selection
relates the two together is key.
[KEY] The analysis model didn’t emphasize the
idea of a “current page”, but it is crucial to the design. The current page
represents the focus of all three screen areas.
One approach to defining how selection might
work would be to define a PageSelectionModel, a PageSelectionListener, and a
PageSelectionEvent, suitable for use with JavaBeans. It might not be a bad
approach. But, even while designing one framework, we keep our eyes out for
other frameworks.
Selection is generally useful, so we’ll
introduce a “micro framework” for selection:
SelectionModel:
tracks a selected object.
SelectionListener:
listens for changes in selection.
SelectionEvent:
notification of change in selection. [TBD needed?]
DefaultSelectionModel:
an implementation
These objects will connect like this:

When an object is selected, the model notifies
the listeners of the change.
This object, focused on generic selection, may
not be as type-safe as a version focused on pages, but it enables generic
components to hook together with fewer adapters and fewer types overall.
Once we have these objects, we are following the
JavaBeans version of the Observer pattern.
How did we know to use this pattern? By sweat
work: trying a number of configurations, until it became obvious that all three
screen areas were viewing the same thing. This is a classic arrangement that
can make use of the Observer pattern.
Design Model -
Graph
We’d like to use our Graph framework to support
the graph nature of the web. The first step is to identify the relationships
between Graph classes and web site manager objects:
Graph:
Site
Node:
Page
Edge:
Links to other pages
[TBD]
In Graph, do we need some sort of invalidate()
command? (caching)
Design Model -
Putting It All Together
[TBD] A. Unified model
[TBD] B. Mapping to Java
These could be mapped as classes or interfaces.
[KEY] Use interfaces for interesting objects,
and classes for blobs of data.
In our case, a URL is mostly a “data bag”, so
we’ll make it a simple class. (We might decide to just use java.net.URL.)
public class URL {
private
String name;
public
URL(String name) {this.name = name;}
public
String toString() {return name;}
}
Site, Page, and Tool have more interesting behavior,
so they will be interfaces.

[TBD] C. Interconnection model
The model for interconnecting the pieces:

User Interface, V1
At this point, we can turn two teams loose in
parallel: one for implementation of the model, the other to develop the user
interface. At the end, we’ll integrate their efforts.

It’s helpful to “burst” this view apart, to see
what could build it in terms of UI widgets.

The Tool needs an on-screen representation (as a
JComponent in this case).
The easy way out is to add a method to Tool: public
void JComponent getComponent(). Then the user interface could ask for a
tool, and ask the tool for its component.
[KEY] Couple the user interface to the model,
not the model to the user interface.
We don’t want to depend “up”. So, we’ll
temporize, and assume there is a ToolComponentMap object, with a method
getComponent(Tool) that will find the component for us.
[TBD - defer commitment - Thimbleby]
The code for the panels is straightforward if
tedious:
[TBD - keep?]
public
URLPanel() {
setLayout(new BorderLayout());
add(new Jlabel(“URL”), “West”);
add(textfield, “Center”);
add(button, “East”);
button.addActionListener(new
ActionListener() {…});
textfield.addActionListener(new
ActionListener() {…});
}
public
ToolPanel() {
setLayout(new BorderLayout());
add(Tool[0], “Center”);
}
public
WSMPanel() {
setLayout(new BorderLayout());
add(new URLPanel(), “North”);
add(new ToolPanel(), “Center”);
}
Current Node
We’re trying to support this piece:
[TBD
- current node, in, & out]
This is really just a view on the Node object.
Notice that we can access the current page name
(via toString()), and the in and out nodes (and their names). Thus, we can
entirely display these items without even caring that they’re Pages (or Nodes).
[NOTE Box] Wait a minute!
We’ve talked about the display, the file tree,
and the current node. None of them cared that these were web pages! Can this be
right?
Yes, it is, and it reflects a philosophical
goal: keep things decoupled. At some point, yes, we must deal with HTML. But by
avoiding the dependency as much as possible, we let other pieces continue
development in parallel.
Node selection
JList inList = list of Node
JList outList = list of Node
setCellRenderer (ListCellRenderer)
setNodeRenderer (Renderer)
(with
defaults)
See CellRendererPane.
Setup list listeners. On click, make the
selection be the current node.
setSelection(Object)
(is
null ok? Yes - can deselect all nodes)
TBD - more on design.
WebGraph
Implementation
URL File
Edges
Relative to a "base" that defines a
prefix for the URL and the file.
Given a file, relative to “base,” find its Edges. We'll let Graph take File.
Each File will generate a node. We'll use a StreamTokenizer to look for
"<A HREF="...">" occurrences. This is not full HTML
parsing by any stretch. It's just a quick-and-dirty way to get the easy 95%.
WebBase
String
filePrefix
String
webPrefix
Tools
File Info Viewer
name-value
pairs
Readable:
true
Writable:
true
Length:
int
HTML Viewer
[]
Need: ability to change node.
The tool display is where we see this
application acting as another framework. The idea is that we'll provide a
design that can accommodate a number of tools.

Each tool will provide a panel that we can add
to the tab pane.
What does the tool look like?
We'll require it to be a subclass of JComponent,
so it can be put in the tab pane. We'd also like to know its name, and a tooltip
name for it.
[TBD ??]
What does the tool need to know? It needs to
know which page it's working on.
[Later - revoke the subclass idea - provide a
method to return JComponent.]
[Design with no central object - revoke later]
A tool now has these characteristics:
name
tooltip
text (long name) (description)
ObjectSelectionListener
(and
it's a JComponent)
Wait! Is a tool a component, or does it have
a component?
[TBD - no]
It's almost certainly better to make the tool
provide the component when asked. This will let us keep "being a
tool" an interface. It will let us use existing components rather than
forcing them to be in a particular spot in the class hierarchy.
public
interface Tool extends ObjectSelectionListener {
public
String getName();
public
String getDescription();
public
JComponent getComponent();
}
[TBD - easier to wrap]
Now the toolbox:
public
interface Toolbox extends ObjectSelectionListener {
public
void add(Tool);
public
void remove(Tool);
}
Toolbox
<> ---- Tool
Quickie implementation: use Vector &
JTabbedPane.
Tree Model
For the moment, let’s ignore all the stuff about
graphs, webs, and HTML, and take a detour. We’ll develop a component we might
have had lying around: a tree of Files, corresponding to a directory hierarchy.
(Many applications could use a tree widget based on the file system.)
The Swing library has an interface we will use:
TreeModel. We’ll conform to that interface, and provide a concrete
implementation focused on files. (As we’ll see later, Swing has been a bit
sloppy about package dependencies; this forces us to depend on a GUI library
for a basic data structure.)
To build a tree of files using Swing, it's most
natural to put them in a JTree object. The JTree requires a TreeModel, which is
the data model (as in model-view-controller). This will correspond to the
directory hierarchy.
The TreeModel is a Tree of File objects,
corresponding to the structure on disk. (Notice that we need this - not all
pages are linked together, and a tree view is often convenient.)
[TBD G - model]
We want to work with File objects, but a
TreeModel works with TreeNodes. We will wrap our files into a TreeNode by
implementing that interface:
[tbd]
We want to be somewhat careful in creating the
tree. Since filesystems can be large, we don't want to load the whole tree all
at once. Instead, we only want to load the nodes as needed. Thus, the first
step of most routines will be to ensure that the children (if needed) are
present.
We want to be lazy in creating trees. Since a
file system is potentially large, we don’t want to load it all at once.
Instead, we’ll load nodes as needed. Thus, most routines will instantiate their
children on demand.
[TBD] check isDirectory() once
Here’s a sample listener to verify our widget.
Here’s a demo GUI for it. [TBD JTree]
Problem: TreeModel and its base.
We can put it in the JTree like this:
[Code tbd]
Here's simple driver code so you can test this:
[Code tbd]
We can add a SelectionListener to print the
current file:
[Code tbd]
So - we have one part "done"!
Backtrack - TreeModel knows "base".
We could define the display for those items, and
let subclasses override the display methods if they want to be different. That
would be a white-box approach. Instead, we'll take a more black-box approach,
and have the idea of renderers, small pieces of code that handle the display of
a single item. (Swing does this for lists, tables, etc.)
[TBD - picture]
We'll provide default renderers that just do
"node.toString()" to get the value.
The Adapter
[TBD]
The file structure wasn’t really mentioned
before, but we need to deal with pages not just as they’re linked, but also as
they’re stored.
We have to relate the files contained in the
tree to the pages in our web.
The adapter will have to know a relationship,
e.g.,
http://node/dir
== /home/web/dir
(to realize that http://node/ maps to
/home/web/.) On the web side, the Nodes will be Pages.
HTML (At Last!)
How do we find HTML nodes?
Files ending in .htm, .html, or .shtml.
<A HREF=”string”>
capture
the filename using StringTokenizer
<[Aa][ \t]+[Hh][Rr][Ee][Ff][ \t]*=[
\t]*”[^”]*”>
HTMLGraph package --------à
Graph package
HTMLGraph -> Graph
HTMLEdge -> Edge
HTMLNode -> Node
Design Revisited
Earlier, we described the notification from
Graph to FileTree to toolbox, etc.
A useful technique for evaluating designs is to
consider the most likely changes, and see how well the design stands up to
them.
The most likely change is a new tool. We handle
this fairly well - all that's required is a new Tool subclass. Another Java application
could be adapted fairly easily.
Another change might be a new web
representation. We have three already: FileTree, Graph, and Tool. There's an
old design rule "0, 1, infinity." It tells you that once you have two
or more of something, then you need to consider the possibility of even more.
Another change might be moving to XML. [etc]