A Partial Implementation of a Modular ... Safety Analysis C.

A Partial Implementation of a Modular System for Software
Safety Analysis
by
Sara C. Pickett
Submitted to the Department of Electrical Engineering and Computer Science
in partial fulfillment of the requirements for the degrees of
Bachelor of Science in Computer Science
and
Master of Engineering in Electrical Engineering and Computer Science
at the
MASSACHUSETTS INSTITUTE OF TECHNOLOGY
May 2000 @ Sara C. Pickett, MM. All rights reserved.
The author hereby grants to MIT permission to reproduce and distribute publicly
paper and electronic copies of this thesis document in whole or in part.
...
Author ..
..
.
....................................
Department of Electrical Engineering and Computer Science
May 22, 2000
/I
Certified by..
/7
Nancy G. Leveson
Professor
Thesis Supervisor
Accepted by ........
Arthur C. Smith
Chairman, Department Committee on Graduate Theses
MASSACHUSETT S INSTITUTE
OF TECHN XLOGY
ENG
JUL 2 7 2000
LIBRA RIES
A Partial Implementation of a Modular System for Software Safety
Analysis
by
Sara C. Pickett
Submitted to the Department of Electrical Engineering and Computer Science
on May 22, 2000, in partial fulfillment of the
requirements for the degrees of
Bachelor of Science in Computer Science
and
Master of Engineering in Electrical Engineering and Computer Science
Abstract
In this thesis, I describe how I designed and partially implemented an editor for SpecTRMRL documents, to be used as part of a cross-platform, extensible system for performing
software safety analysis. This editor, written using Java and Swing, allows for the creation
of links between areas of the document, tracks variable definition and usage, and provides
methods for saving and loading SpecTRM-RL documents. The editor was designed to later
be used as part of a much larger system which would allow analysis and execution of the
SpecTRM-RL document.
Thesis Supervisor: Nancy G. Leveson
Title: Professor
2
Acknowledgments
This work was partially supported by NSF Grant CCR-9996265.
Sun, Sun Microsystems, the Sun Logo, Solaris, Java, JavaBeans, JDK, JFC, Swing, and
all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in
the United States and other countries.
Microsoft Windows and Microsoft Word are either registered trademarks or trademarks
of Microsoft Corporation in the United States and/or other countries.
Macintosh, MacOS, and iMac are either registered trademarks or trademarks of Apple
Computer, Inc., registered in the U.S. and other countries.
Linux is a registered trademark of Linus Torvalds.
3
Contents
1
Introduction
1.1
1.2
2
3
4
7
M otivations . . . . . . . . . . . . . . . . . .
7
1.1.1
Motivations for Safety Analysis . . .
7
1.1.2
Motivations for Intent Specifications
8
1.1.3
Motivations for SpecTRM-RL . . . .
9
Background . . . . . . . . . . . . . . . . . .
9
Design Criteria
10
2.1
Extensibility and Modularity
. . . . . . . .
10
2.2
Cross-Platform Functionality
. . . . . . . .
11
2.3
Requirements Imposed by SpecTRM-RL . .
11
Implementation
13
3.1
Choosing JavaTM for the Programming Language . . . . . . . . . . . . . . .
13
3.1.1
13
Choosing Java Version 1.1 . . . . . . . . . . . . . . . . . . . . . . . .
3.2
Quick SpecTRM-RL Overview
. . . . . . . . . . . . . . . . . . . . . . . . .
13
3.3
Discussion of Implementation Details . . . . . . . . . . . . . . . . . . . . . .
14
3.3.1
Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
3.3.2
Location . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
3.3.3
The Status of Links . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
3.3.4
Component-Specific Data and Functionality . . . . . . . . . . . . . .
16
3.3.5
Saving and Loading Files . . . . . . . . . . . . . . . . . . . . . . . .
17
Conclusions
21
4.1
21
Discussion of the Future Directions . . . . . . . . . . . . . . . . . . . . . . .
4
4.2
Contributions . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . .
A Screenshots
21
23
A.1
Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
A.2
Example Screenshots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
B Code
26
B.1
BooleanAtom.java
. ... . .. ... .. .. . .. .. . .. .. . .. . .. ..
26
B.2
BooleanAtomEd.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
B.3
SimpleBooleanDocument.java . . . . . . . . . . . . . . . . . . . . . . . . . .
29
BA
BooleanExpr.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
B.5 BooleanExprEd.java
... . .. ... .. .. .. .. . .. . .. . .. . .. ..
31
B.6
SpecExprParsing.java
.. . .. ... .. .. . .. .. .. . .. . .. . .. ..
34
B.7
TestStuff.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
36
B.8
Output CommandComp.j ava . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
B.9
SpecTextBox.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
B.10 BooleanTableComp.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
B.11 BooleanTableModel.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
B.12 BooleanTableColumnModel.java
.. . ... . .. .. .. . .. . .. . .. ..
53
. .. .. .. ... .. .. . ... . .. . .. . .. .. .. .
54
B.14 SpecContext.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
B.15 SpecVar.java
.. .. .. .. .. ... .. .. .. .. . .. . .. . .. .. .. .
58
B.16 AlreadyDefinedException.java . . . . . . . . . . . . . . . . . . . . . . . . . .
60
B.17 StillInUseException.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
B.18 util.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
60
B.19 BasicWindowMonitor.java . . . . . . . . . . . . . . . . . . . . . . . . . . . .
61
B.13 SpecLocationjava
5
List of Figures
1-1
The structure of an intent specification, from [5].
2-1
Example of an Output Command Specification, showing fields, tables, variable usage, and links, from [4].
. . . . . . . . .
A-1 A blank Output Command Specification window, showing fields and tables.
8
12
24
A-2 The same Output Command Specification window, this time filled in with
the same information as in 2-1. . . . . . . . . . . . . . . . . . . . . . . . . .
6
25
Chapter 1
Introduction
In this thesis, I will discuss the implementation of an editor for Specification Tools and Requirements Methodology Requirements Language (SpecTRM-RL) which must work within
the framework of a system for documenting intent specifications which are used for doing
analyses of the safety of large scale software projects.
1.1
1.1.1
Motivations
Motivations for Safety Analysis
Most computer programmers work on non-safety-critical systems. A bug in the specification
or mis-implementation of the specification may result in some lost money for their employer,
lost time for their research group, or aggravation for the end user, but typically nothing truly
horrendous will occur. But in safety-critical systems, a serious flaw in a critical computer
program may result in a loss of life, a catastrophic environmental disaster, or the loss of
missions of dollars and years of research effort. Airplane autopilots, satellite controllers,
and nuclear power plant automation are all examples of safety-critical systems involving
computers.
Traditional programming validation techniques include testing, code reviews, and maybe
a little proof-writing for any particularly complex algorithms. But none of these techniques
are really up to dealing with large-scale safety critical systems.
7
Decomposition
Refinement
Environment
Operator
System
Components
System
Purpose
System
Principles
Intent
Blackbox
Behavior
I
Design
Representation
I
__________________________I
Code
(Physical
Representation)
Figure 1-1: The structure of an intent specification, from [5].
1.1.2
Motivations for Intent Specifications
Besides hardware failure of the machine(s) the software is running on, there are really only
two types of errors software can have. The software may meet its requirements specification,
but the behavior specified may not be what is desired from a system safety perspective, or
the software as implemented may not meet its specification [3, p. 157]. Common opinion is
that the first type of error is much more common than the second, but regardless, it's clear
that the specification of software requirements is central to the issue of software safety.
Because of this, much work has gone into exploring ideas about how software specifications should be written so as to promote safety. One of these ideas is Prof. Nancy
Leveson's "intent specifications" [5]. This format for writing specifications supports system
engineering by providing a way to record decisions at every step of design. To do this, it
has a structure with several dimensions of layers of specifications - one dimension for refinement, another for decomposition, and a third for levels of intent, with linkages between
and across layers to help record why decisions were made as they were. The intent levels are
System Purpose, System Principles, Blackbox Behavior, Design Representation, and Code
(effectively the Physical Representation).
8
1.1.3
Motivations for SpecTRM-RL
For the blackbox behavior level, some format for describing the blackbox behavior of the
system needs to be used. Although this could be merely a textual description of the desired behavior, that wouldn't be precise enough for most purposes. On the other hand, the
specification needs to be readable, or no one will read it to check its correctness. One language, SpecTRM-RL (Specifications Tools and Requirements Methodology-Requirements
Language) is designed to be both easy to use without extensive training and precise enough
to be formally analyzable by automated tools.[5] This language was based upon RSML
(Requirements State Machine Language)[7], and should be precise enough to be used in
completeness analysis[6], as well as other forms of analysis.
1.2
Background
As far as I have been able to determine, no previous attempts to write a SpecTRM-RL editor
have been made. An alpha version of an editor for RSML, the predecessor to SpecTRM-RL,
exists, named Nimbus. This editor relied heavily upon Microsoft WordTM templates and
macros, and is dependent upon the Microsoft WindowsTM platform in general.
9
Chapter 2
Design Criteria
Several design criteria for the intent specification system, and the SpecTRM-RL editor
which will be used within it, were identified right from the start. The main goal was for the
system be useful for system safety analysis and yet not easily made obsolete. The system
must be extensible, to allow for new forms of analysis to be performed, new document
formats to be understood, and other modifications to be made easily. The system must also
be usable on several different computing platforms, rather than relying on a single operating
system or closely related set of systems.
2.1
Extensibility and Modularity
Because no computer program can be considered complete and whole in its first version,
the intent specification system must be extensible. Both the addition of new functionality
and the routine maintenance of existing code need to be made as easy as possible. Future
changes might include new forms of analysis (based on the SpecTRM-RL itself, or on data
derived from it), new document formats based on the need of newer versions to include
more information, or new methods of loading documents (based on retrieving them from
the Internet or from a revision control repository). The overall intent specification system's
framework needs to be designed with extensibility and modularity in mind[1].
The SpecTRM-RL editor must support the modularity of the overall framework, both
by being written in as readable and modular a way as possible, and by conforming to
any requirements specified by the framework. However, since the framework wasn't finalized before this version of the editor was written, it probably does not entirely meet that
10
requirement.
2.2
Cross-Platform Functionality
It is also extremely important that the SpecTRM-RL editor be able to function on multiple
computing platforms. This is not only to allow more users to use the intent specification
system on their platform of choice, but also to prevent the system from being made obsolete
or unusable by the obsolescence or incompatible modification of the computing system it
depends on. Besides running on more than one type of hardware system and more than
one operating system, the programming language used to implement the system and any
other software components (such as libraries or communication protocols) that the system
depends on must be popular enough that continued availability and support seems likely.
2.3
Requirements Imposed by SpecTRM-RL
There are also some requirements imposed on the intent specification system and the
SpecTRM-RL editor by the format of the SpecTRM-RL language itself. The system must
be able to load and save SpecTRM-RL documents, but with few, if any, existing SpecTRMRL editors, backwards compatibility is not too much of an issue. However, clearly the editor
needs to allow the user to enter the information which is part of SpecTRM-RL, as described
in [4]. This information includes sections for output commands, operating modes, state values, input values, control inputs, display outputs, and macros. In each section, values for
various fields have to be filled in, and tables representing Boolean expressions have to be
created. Also, the user needs to be able to create links from one part of the SpecTRMRL document to another (or to a location in the larger intent specification document). In
addition to user created links, links should be automatically created between a variable's
definition and its usages.
11
Output Command
DOI-Power-On
Destination: DOI
Acceptable Values: (high)
Initiation Delay: 0 milliseconds
Completion Deadline: 50 milliseconds
Exception-Handling:
Feedback Information:
Variables: DOI-status-signal
Values: high (on)
Relationship: Should be on if ASW sent signal to turn on
time (latency): 2 seconds
Max. time: 4 seconds
Exception Handling: DO-Status changed to Fault-Detected
Min.
Reversed By:
Turned off by some other component or components. Do not know which ones.
Comments:
References:
4.7
4 2.4.5
CONTENTS
=
discrete signal on line PWR set to high
TRIGGERING CONDITION
Operating Mode
State Values
Operational
Not Inhibited
T
DOI-Status = On
F
Below-threshhold
T
Prev(Altitude) = At-or-above-threshold
T
Altitude
=
Figure 4: Example of an Output Specification
Figure 2-1: Example of an Output Command Specification, showing fields, tables, variable
usage, and links, from [4].
12
Chapter 3
Implementation
Choosing JavaTM for the Programming Language
3.1
Before any actual implementation could take place, I had to chose a programming language. After consulting with some other people, I chose Sun's JavaTM because it had the
important property of being available on several platforms (SolarisTM, Windows, LinuxTMI
and MacOSTM), and also because the SwingTM library[9] (part of the Java Foundation
Classes[11] suite) is considered to be very easy to use for creating GUIs.
3.1.1
Choosing Java Version 1.1
The editor was written using only methods and classes from JDKTM 1.1
110], even though
JDK 1.3 is the current version, because version 1.1 did not lack any of the functionality
needed and is the newest version available for some platforms (most notably MacOS). The
implementation of the outer intent specification editing framework may have to be written
using the relatively well-supported JDK 1.2, however.
Since Swing is included with every installation of JDK 1.2, but not with JDK 1.1, JDK
1.1 users will have to also have separately installed a copy of the Swing libraries. Once that
is done, however, the editor works identically under both version.
3.2
Quick SpecTRM-RL Overview
From the implementers point of view, the format of a SpecTRM-RL document is fairly
straight-forward.
For each section of the SpecTRM-RL document (such as the output
13
commands section), there will be some number of definitions which fit into that section.
Each definition will follow the template provided by SpecTRM-RL for that category. Each
template includes fields such as "Source", "Type", "Possible Values", or "Units" into which
information must be filled by the user. As well as text, these fields may contain links to other
portions of the document. Besides the text fields, the actual definition is given in terms
of a set of AND/OR tables which represent disjunctive normal form (DNF) compound
Boolean expressions. These tables hold simple Boolean expressions (such as "Altitude
=
Below-threshold") in their first column, and Boolean constants in their other columns.
3.3
Discussion of Implementation Details
Most of the implementation was relatively straight-forward. Each component of the SpecTRMRL document had some amount of component-specific data (the contents of a text field or
the contents of a table), but every component also had to know its current location and the
"context" within which it was created.
3.3.1
Context
Each component knows the "context" in which it was created - that is, which variables,
states, and macros have been defined and where they are used. This SpecContext class
is stored as a hash table, keyed by variable/state/macro name, which is used to store a
SpecVar which holds the name, type, location of definition, and a list of usage locations.
Usages can be added and removed for each variable, and variables can be added to the
context when they're defined, and removed when their definition is removed, but not until
all usages have been removed.
3.3.2
Location
The initial goal was to create some sort of reasonably sophisticated object which could be
used to record the location of objects (such as variable definitions and usages), so that the
location could be recorded and later looked up, possibly by clicking on hyperlinks to go to
that location.
In the existing implementation, every component knows its SpecLocation, and knows
how to modify that location object to obtain the locations of any other objects it contains.
14
It passes the child's location in to it when the child is created, and since that child will
also know how to modify that location to give locations to its children, the locations are
perpetuated.
These location objects are fine for being stored and retrieved to keep track of variable
usage, but a mechanism for scrolling to a given Swing Component based on a location
object has not been implemented.
In fact, the SpecLocations are basically strings. A
table's location might be "the table in the macro definition panel for Altitude-is-high", and
every table may know that in order to get the location of their fourth row, combine "row #4
of" onto the front of their own location, to produce the location "row #4 of the table in the
macro definition panel for Altitude-is-high". This implementation, while unsophisticated,
is at least nicely human readable.
3.3.3
The Status of Links
The ability to create references or hyperlinks to other parts of the SpecTRM-RL document
(and to other external documents) has not yet been implemented, since it proved to be
more complex than originally realized.
At first it seemed that URLs would be ideal for
this purpose - URLs seemed ideal for pointing to arbitrary files available on the Internet,
URLs starting with f ile: // could be used to link to other local files, and some sort of TAG
scheme could be used to link within SpecTRM-RL files, just as they're commonly used to
label parts of HTML files for linking. However, this scheme has several problems, mostly
related to tracking changes.
The first problem has to do with versioning. When you link to a file somewhere on
the Internet, you have no way of knowing when that file if that file was changed to say
something totally different than it did when you last viewed it. This is mostly a nuisance for
web page designers. However, for a system safety documentation tool, this seemed possibly
dangerous. A better system would have some concept of versioning, so that you would not
be automatically linked into the newest version of another document without reviewing it,
but at the same time you would be informed of modifications to other documents, so that
you could choose to update your links if appropriate. Although some system like this could
be based around URLs, it would require a lot of imposed structure that standard URLs
don't have.
As well as versioning, there's also the problem that there is no way of guaranteeing
15
that the remote document will continue to exist. Or that it will continue to exist in the
same location (it could be moved).
One can imagine working around these problems by
always going through a central authority before allowing document deletions to check if
other documents depend on your document, or always requesting the canonical location of
a document before attempting to find it. Some scheme to map CVS[2} repository files to
URLs would seem most appropriate, but at that point, why use URLs at all? But at the
same time, CVS doesn't satisfy all the requirements either.
Intra-document links are a much easier problem, since consistency checking within a
single SpecTRM-RL document, or even a few associated documents all on the local disk,
could be controlled by the SpecTRM-RL editor or the larger intent specification system.
However, although the existing editor keeps track of locations for every component, and
the locations of variable definitions and usages, it does not implement the hyperlinks connecting the two. The current editor keeps track of these "links", but they do not appear as
hyperlinks to the user, yet.
3.3.4
Component-Specific Data and Functionality
Fields
For each field in the template for a category, the text is entered into a JTextArea. As well
allowing the user to enter text and saving it as part of the document, each field does a
minimal amount of parsing on its contents to extract a list of variables that were used in
that field. This list can be used to construct links between variable definitions and variable
usages.
More extensive parsing and validation of the text might be possible, but most of the
fields seemed to be free-form, and so more extensive parsing was left to be implemented by
outer layers of analysis tools or future versions of the editor in order to avoid excessively
limiting the user in what they could enter and document.
Tables
Each definition table is a JTable to which rows and columns can be added as needed. The
leftmost column hold a Boolean expression and is effectively a JTextField, which can hold
a single line of text. That column is parsed enough to detect variables and logically link
16
variable usages to their definitions. A future version of the editor could do further parsing,
such as checking whether the text is a valid Boolean expression, but the current version
does not, as that functionality has been left to an outer layer syntax checking tool of some
sort. The other columns in the table are only allowed to hold simple Boolean values - true,
false, or don't care. Because of this, those columns are JTextField's which validate their
inputs and only allow "T", "F", or "."
to be entered.
Parsing
The contents of both the text fields and the Boolean expression columns have to be parsed
in order to find variables. The Boolean expression text is broken into "words" at whitespace,
while the text field parsing knows to also remove commas and periods from words. Then
each word is looked up to see if it's a defined variable/macro/state. If the word contains an
underscore, the portion of the word before the underscore is used as the name to be looked
up. (This is because the plan was to eventually have the first letter of the variable's type
be used as a subscript to the name wherever it appeared - for example foobarm whenever
the macro foobar was referred to. In the tradition of IBLTX, this would be entered by the
user as f oobarim.)
Once some of the words are determined to be variables, those the editor updates the
recorded usages for those variables. Eventually, it should also highlight the variables in
another color, and possibly add hypertext links to the variable definitions, but neither of
those have yet been implemented.
3.3.5
Saving and Loading Files
Using Serialization
At first, saving and loading SpecTRM-RL documents seemed almost trivial.
Java pro-
vides a process called "serialization" for automatically saving and loading objects to and
from disk. If a class is declared as implementing the Serializable interface, then a call
to java.io.ObjectOutputStream.writeObject(
ourObject ) is enough to save all in-
formation about ourObject to disk, including all non-transient member variables and all
information from superclasses.
This initially seemed ideal for saving SpecTRM-RL documents. Merely serialize the
17
top-level object which represents a "document", and all information about it would be automatically saved. Later create a new object using de-serialization, and the document would
be recreated. The problem with this is that many of the objects used in a SpecTRM-RL
document are Swing objects or extensions (subtypes) of Swing objects, and the serialization format for Swing objects has not yet be finalized, according to the many warnings in
the documentation[9]. This means that any documents saved by the editor running under
current versions of Java and current version of Swing would be unreadable to the editor
running under a future version of Swing.
Also, Swing's JTables, which were used to implement the DNF truth tables in SpecTRMRL, are not serializable, and so serialization could not be used without intermediate glue of
some sort being implemented. While not extremely difficult, this provided another reason
not to just use Java's serialization.
Overriding Serialization
At first the solution seemed simple - override the default implementation of writeObj ect 0
and readObject to save the relevant information about Swing-derived objects, including
instance variables and relevant information about the supertype in writeObject 0 and
then load the instance variables back in and reconstruct any desired information about
the supertype (such as which Components it contained, and how they were laid out) in
readObject 0. That's what Java lets you do if the supertype isn't serializable at all, so it
seemed reasonable to think that if you proceeded as if the supertype weren't serializable,
Java would let you do the serialization yourself.
Unfortunately, this turned out not to be the case. For example, if you don't save any
information about the supertype in your writeObject 0 method, that information is still
automatically recreated when you run readObject().
So there seemed to be no way of
serializing a class which extends a Swing class without also automatically serializing the
Swing class in a soon-to-be-incompatible way.
Actual Implementation
Since it was not possible to simply override the writeObject () and readObject () methods to avoid serializing the Swing objects, I had to write my own methods for saving and
loading all of the classes which were derived from Swing objects. The method for saving
18
was saveSelf ( java.io.ObjectOutputStream ) and the method for loading was a constructor taking a java. io. ObjectInputStream as its only argument. These methods had
to explicitly save all instance variables and any info from the supertype that needed saving.
Any information from the supertype that could be recreated (such as layout and positioning of the components) was discarded when saving and reconstructed when loading. Any
Swing-derived instance variables were saved using their saveSelf 0 methods, while any
non-Swing information was saved using just writeObject 0 for serialization.
The first thing to be careful about when doing the serialization by hand is that all
object must be read back in the same order that they were written.
Otherwise, the
saved objects may not be assigned to the correct member variables, which may cause
ClassCastExceptions on loading, and will definitely cause data corruption.
The second thing to be careful about has to do with the saving of container objects,
such as Vectors. To save a homogeneous (one whose elements are all of the same type)
Vector, it is sufficient to first save its length as an Integer using writeObj ect 0, and then
call saveSelf () on each of the elements. To load, first perform a readObject () to find out
the length, and then call the element type's constructor the appropriate number of times.
However, when the vector is non-homogeneous and it contains some Swing-derived elements, things become tricky. We can't just read the length and then call the constructor an
appropriate number of times, because there is no way of knowing which constructor to call.
readObj ect 0 is much more suitable in this regard, since it returns an Object for which the
caller can then check the type. Also, if the Vector contains some Swing-derived elements
and some non-Swing elements, it's not clear for any given element whether readObj ect 0
or a constructor should be called. For recursive Vectors of Vectors, things become even more
complicated, since the Integer marking the beginning of the Vector cannot be distinguished
from an Integer which is simply an element of the parent Vector.
Complications such as these make one with for the ability to use regular Java serialization, which automatically marks the type and size of everything in such a way as to make the
objects reconstructible with just a call to readObj ect ().
However, the non-homogeneous
recursive Vector of Vectors problem only came up in one place in the code - when saving
the SpecTextBoxes for the various category panels (OutputCommandComp, etc.). There, I
needed to save a Vector whose elements were each either a SpecTextBox or a sub-Vector
of SpecTextBoxes and sub-Vectors.
For that case, the easiest thing to do was to write
19
a Boolean flag out before each element, indicating which it was, so that the appropriate
method or constructor could be called when the data was read back in.
Although not elegant, this implementation of saving and loading works, and was relatively easy to implement. Some other methods were considered, but were rejected as being
too complicated to implement in a limited amount of time.
Other Possibilities
Both Java's standard object serialization and the solution that was actually implemented
have one serious undesirable property - the save files they produce are not human-readable
and are effectively readable only by Java programs. A more attractive solution in this regard
would be the use of XML[12] - a text-based universal format for structured documents and
data. The editor could either include code to produce and interpret XML text to represent
each component object, or could use some automated scheme for producing the XML. There
is, in fact, a proposal to allow Java serialization to automatically produce XML documents
from JavaBeansTM (and every Swing component is a JavaBean), but at this point it is only
a proposal. [8]
Mainly due to time constraints, neither of these options were implemented, but they
seem very interesting and deserve further exploration.
20
Chapter 4
Conclusions
4.1
Discussion of the Future Directions
Although the basic framework for the SpecTRM-RL editor is there, there are several obvious
steps that could be taken to improve it.
Improvements to the saved document format
(possibly using XML), the addition of the ability to print SpecTRM-RL documents, and
better feedback within the editor regarding variable usage and definition (either using text
coloring or highlighting, or by displaying the information in a separate window) would all
be good starts.
Besides improvements to the SpecTRM-RL editor, once a general intent specification
framework and editor are written, there will be plenty of work necessary in order to integrate them with the SpecTRM-RL editor. As well as being invoked by the outer intent
specification editor, and referring links to the outer editor, the SpecTRM-RL editor will
have to communicate with the SpecTRM-RL
/
RSML simulator, as well as with programs
of various sorts which would like to analyze the blackbox specification in various ways.
4.2
Contributions
This thesis contributes an actual implementation of a SpecTRM-RL editor that is usable,
although lacking in some features. It also documents some of the issues encountered while
exploring ways to implement the editor. Although Swing made it relatively easy to implement a GUI, it's still by no means trivial. And although there are a lot of built-in or
publicly available libraries for doing almost what was needed (URLs for inter-document
21
links, Serialization for document saving), adapting them to suit what was actually needed
and combining them all into the same piece of software proved to be rather challenging.
22
Appendix A
Screenshots
A.1
Details
These screen shots of the implementation were taken on an Apple iMacTM and on a SunTM
workstation. The MacintoshTM was installed with MacOS 8.6 with Macintosh Runtime for
Java (MRJ) version 2.2, which implements Sun's JDK 1.1.8 specification, and with Swing
1.1.1 (officially known as Java Foundation Classes (JFC) 1.1).
On the Sun workstation,
JDK 1.2.2 was used.
A.2
Example Screenshots
Figure A-1 shows a blank Output Command Specification window, while A-2 shows it filled
in.
23
Figure A-1: A blank Output Command Specification window, showing fields and tables.
24
Figure A-2: The same Output Command Specification window, this time filled in with the
same information as in 2-1.
25
Appendix B
Code
This code can also be found in
http://web.mit. edu/~sarac/Public/SpecTRM-RL-editor/SpecTRM-RL-editor-vl.0.
B.1
tar. gz
BooleanAtom.java
import java.io.Serializable;
public class BooleanAtom implements Serializable
private String value = "";
public BooleanAtomO
{
{
value =
}
10
public BooleanAtom(String s) {
if ((s == null) |I (s.equals(""))
II
(s.equals(" ")))
{
}
s = s.toUpperCase(;
if (!((s.equals("T")) II (s.equals("F")
(s.equals(". "))))) {
throw new IllegalArgumentException("Can't use \"" + s +
"\"
to construct a BooleanAtom.");
20
}
value = s;
}
public String toString()
{
return(value);
}
30
26
}
BooleanAtomEd.java
B.2
import java.awt.Component;
import java.util.*;
import javax.swing.table.*;
import javax.swing.*;
import javax.swing.event.*;
public class BooleanAtomEd extends JTextField implements TableCellEditor
protected transient Vector listeners;
protected transient BooleanAtom originalValue;
{
10
public BooleanAtomEd()
{
// construct a new JTextField with our document that
// disallows all chars except T/F/" "
super(new SimpleBooleanDocument(), null, 2);
// changing the alignment when editting is useful for debugging
//setHorizontalAlignment(JTextField.CENTER);
//
Can only ever be one character wide, so set
//
that as the true preferred width now.
20
setText("F");
setPreferredSize(getPreferredSize();
// Canonicalizeformat
setText(new BooleanAtomo.toStringo);
//
//
//
//
//
Scroll back to the left
This isn't actually useful here, since the constructor
is only called once for the entire table. But there are
30
a lot of issues here with tabbing through the table to
edit cells and where the insertion point ends up - FIXME
setScrollOffset(O);
listeners = new Vector0;
}
public Component getTableCellEditorComponent(JTable table,
40
Object value,
boolean isSelected,
int
row,
int column) {
if (value == null)
{
setText("");
return(this);
}
50
if (value instanceof BooleanAtom) {
setText(((BooleanAtom)value).toString();
} else {
27
throw new IllegalArgumentException(" BooleanAt omEd can only be" +
" used on BooleanAtom's.");
}
table.setRowSelectionInterval(row, row);
table.setColumnSelectionInterval(column, column);
originalValue = new BooleanAtom(getText();
60
7*
System. out.println( "BooleanAtomEd.getTableCellEditorComponentcalled" +
with arguements:\n" +
"value: \"" + value + "\"\n" +
"isSelected: \"" + isSelected + "\"\n" +
"row: \"" + row + "\"\n" +
"column: \""
+ column + "\"\n" +
70
*/
return(this);
}
public void cancelCellEditing()
{ fireEditingCanceledo; }
80
public Object getCellEditorValue() {
// Somewhere we should add a check here to only create a new
// BooleanAtom if the text changed (otherwise use the
/7 old one)? Is this the right place??? - FIXME
7*
Value called when:\n" +
System. out.println("BooleanAtomEd.getCellEditor
"old value was: \"" + originalValue + "\'\n"
+
"new value is: \""
+ getText() + "\'n"
+
90
*/
return new BooleanAtom(getTextO);
I
public boolean isCellEditable(EventObject eo)
{
public boolean shouldSelectCell(EventObject eo)
return true;
{
}
100
return true;
}
public boolean stopCellEditing()
{
fireEditingStopped(;
return true;
}
110
public void addCellEditorListener(CellEditorListener cel)
listeners.addElement(cel);
28
{
I
public void removeCellEditorListener(CellEditorListener
cel)
{
listeners.removeElement(cel);
}
120
protected void fireEditingCanceled()
setText(originalValue.toString());
{
ChangeEvent ce = new ChangeEvent(this);
for (int i = listeners.sizeo; i >= 0; i--) {
((CellEditorListener)listeners.elementAt(i)).editingCanceled(ce);
}
}
130
protected void fireEditingStopped() {
ChangeEvent ce = new ChangeEvent(this);
for (int i = listeners.size() - 1; i >= 0; i--) {
((CellEditorListener)listeners.elementAt(i)).editingStopped(ce);
}
}
}
B.3
SimpleBooleanDocument.java
import java.awt.Toolkit;
import javax.swing.*;
import javax.swing.text.*;
public class SimpleBooleanDocument extends PlainDocument
public SimpleBooleanDocument()
super(;
{
{
}
10
public void insertString(int offset, String str, AttributeSet a)
throws BadLocationException {
str = str.toUpperCaseo;
if ((getLength() + str.length() > 1) 11
!((str.equals("T")) 1| (str.equals("F")) 11
(str.equals(" ")) 11 (str.equals(" I. )))) {
Toolkit.getDefaultToolkit().beep();
}
else
{
super.insertString(offset, str, a);
}
}
}
29
20
B.4
BooleanExpr.java
java.util.Vector;
java.util.NoSuchElementException;
java.util.Enumeration;
java.io.Serializable;
import
import
import
import
public class BooleanExpr implements Serializable
private String value = "";
private Vector words;
private Vector spaces;
private Vector variables;
{
10
private SpecContext context;
private SpecLocation location;
public BooleanExpr(SpecContext c, SpecLocation
context = c;
location = 1;
value =
words =
spaces =
variables
1) {
20
I;
new VectorO;
new VectorO;
= new Vectoro;
}
public BooleanExpr(SpecContext c, SpecLocation 1, String s)
if (s == null) {
s=
{
"";.
}
30
context = c;
location
=
1;
value = "";
words = new Vectoro;
spaces = new VectorO;
variables = new Vectoro;
setValue(s);
//
40
does the checks for us
}
public void setValue(String s) {
// Set the value of the expression to something generated
// by the given string. Does parsing of the value, and updates
// the records of variable usages.
if (s.trim().equals(value.trim())) {
// the string didn't change, except for surrounding
//
whitespace.
// (Do we still want to continue in this case, to find
// any words which had been defined as variables since
//
we last lookeded at this Expr??? - FIXME
30
50
return;
}
60
words = new VectorO;
spaces = new VectorO;
// updates words and spaces
SpecExprParsing.splitString(s,
"
\t\n\r", words, spaces);
Vector oldVariables = variables;
variables = SpecExprParsing.loadVariables(words, location, context);
SpecExprParsing.unloadVariables(oldVariables, location, context);
70
// ideally, after this, instead of just keeping a flat list
// of words, some true parsing of operators and such would
//go on. - FIXME
// Should update value/s based on the little bit of parsing
// just done. i.e.: update subscripts to correspond var type,
// canonicalize whitespace. - FIXME
// Should eventually be able to do more sophisticated things
//
//
80
like link vars to definitions, mark other words with '-'s
as errors, and check syntax of expression, etc. - FIXME
System.out.println("BooleanExpr.setValue()
location +
"\n"
called in
"
+
+
"context:\n" + context +
"old value: \"" + value + "\"1\n" +
"new value: \"" + s + "\"\n");
90
value = s;
}
public String toString() {
// right now toString is being used to setText in the editor,
// so we'll need to fix that if we want to change things.
return(value);
100
}
}
B.5
import
import
import
import
import
BooleanExprEd.java
java.awt.Component;
java.util.*;
javax.swing.table.*;
javax.swing.*;
javax.swing.event.*;
public class BooleanExprEd extends JTextField implements TableCellEditor
31
{
protected transient Vector listeners;
protected transient BooleanExpr originalValue;
10
public BooleanExprEd() {
//
make a normal JTextField
super(;
// changing the alignment when editting is useful for debugging
//setHorizontalAlignment(JTextField.CENTER);
// Scroll back to the left
setScrollOffset(O);
20
listeners = new VectorO;
}
public Component getTableCellEditorComponent(JTable
Object value,
table,
boolean isSelected,
int row,
int column)
if (value == null)
{
30
{
return(this);
}
if (!(value instanceof BooleanExpr)) {
throw new IllegalArgumentException("BooleanExprEd can only be" +
used on BooleanExpr's.");
}
40
originalValue = (BooleanExpr)value;
setText(((BooleanExpr)value).toString());
table.setRowSelectionInterval(row, row);
table.set ColumnSelectionInterval (column, column);
System. out.println("BooleanExprEd.getTableCellEditorComponent" +
" called with arguements:\n" +
"value: \"" + value + "\"\n" +
"isSelected: \"" + isSelected + "\ "\n" +
50
"row: \"" + row + "\"A\n " +
"column: \"" + column + "\"\n" +
return(this);
}
60
public void cancelCellEditing() { fireEditingCanceledo; }
public Object getCellEditorValue(
{
32
System. out.println( "BooleanAtomEd.getCellEditorValue called when:\n" +
"old value was: \"" + originalValue + "\"\n" +
"new value is: \"" + getText() + "\ "\n" +
70
7/
does checking and updating of the usage count for us
originalValue.setValue(getText();
return(originalValue);
}
{
public boolean isCellEditable(EventObject eo)
public boolean shouldSelectCell(EventObject eo)
return true;
}
80
{
return true;
}
public boolean stopCellEditing()
fireEditingStopped(;
return true;
{
90
}
public void addCellEditorListener(CellEditorListener
listeners.addElement(cel);
cel)
{
}
public void removeCellEditorListener(CellEditorListener
cel)
{
100
listeners.removeElement(cel);
}
protected void fireEditingCanceled()
setText(originalValue.toString();
{
ChangeEvent ce = new ChangeEvent(this);
for (int i = listeners.sizeo; i >= 0; i--)
{
((CellEditorListener)listeners.elementAt(i)).editingCanceled(ce);
}
110
}
protected void fireEditingStopped( {
ChangeEvent ce = new ChangeEvent(this);
for (int i = listeners.size() - 1; i >= 0; i--)
{
((CellEditorListener)listeners.elementAt(i)).editingStopped(ce);
}
}
120
}
33
B.6
import
import
import
import
SpecExprParsing.java
java.util.Vector;
java.util.Enumeration;
java.util.NoSuchElementException;
java.util.StringTokenizer;
public class SpecExprParsing
{
// characters that are not allowed inside of names
public static final char[] ILLEGAL-CHARS = {
10
Y* ,,
20
};
//
//
//
//
//
/
//
//
'-' is not here, because it's used so much, but
that means that names *must* be seperated from
operators by whitespace, otherwise we can't tell
the variable named "alt-high" from the expression
"alt" minus "high".
The other operators are still excluded from being
in variable names in order to avoid still more
confusion.
30
// Strings that are allowed to stand by themselves
//
as operators. (This basically includes everything
// used as a word in a boolean expression, excluding
// the names of variables/states/macros.)
// Not Used!
public static final String[] OPERATORS =
{
1>11,
40
")",
"FROM"
};
50
public static void splitString(String s, String delimiters,
Vector words, Vector spaces) {
// modifies words and spaces to hold the words and intervening spaces from s,
// where what constitutes a space is defined by the delimiters.
34
StringTokenizer st = new StringTokenizer(s, delimiters, true);
String curSpace = "";
while (st.hasMoreTokenso) {
String token = st.nextTokeno;
60
if ((token.length() == 1) && (delimiters.indexOf(token) != -1))
{
//
}
it's a delimter
curSpace = curSpace.concat(token);
else {
// it's a word
words.addElement(token);
70
// save the previous run of spaces, since it's complete
spaces.addElement(curSpace);
curSpace =
}
}
}
public static Vector loadVariables(Vector words,
SpecLocation location, SpecContext context)
Vector variables = new Vectoro;
{
80
Enumeration e = words.elementsO;
while (e.hasMoreElementso) {
String word = (String)e.nextElement(;
// this may result in a variable that appears
//
twice in the expression appearing twice in
// the variables vector and having it's usage
// location added twice. But that doesn't really
//
matter as long as it's deleted twice too!
try
{
// variable names cannot contain
'.'s, so if
there is one, it must be there to indicate
// type, and so we need to trim it before we
// do the lookup.
String varname;
if (word.lastIndexOf('2) I= -1) {
varname = word.substring( 0,
word.lastIndexOf(' _));
7/ need to check that the rest *is* just the
7/ type, like it's supposed to be. - FIXME
} else {
varname = word;
90
//
100
}
SpecVar var = context.getVarNamed(varname);
var.addUsage(location);
variables.addElement(varname);
} catch (NoSuchElementException ex) {
7/ just
means it wasn't a defined variable
}
35
110
}
return(variables);
}
120
public static void unloadVariables(Vector variables,
SpecLocation location, SpecContext context)
// unloads the given variables from the location and context
{
Enumeration e = variables.elements();
while (e.hasMoreElementso) {
String varname = (String)e.nextElement(;
//
remove each old variable's usage. This will
130
// work okay, because any that are still in the
// new expression will have just been added a
// second time, and so this code will just remove
//
//
//
the second usage. So it's not too inefficient.
(And really, since a BooleanExpr is only going
to consist of 1-15ish words, this isn't bad.)
SpecVar var = context.getVarNamed(varname);
var.delUsage(location);
140
I
}
}
B.7
TestStuff.java
import javax.swing.table.*;
import
import
import
import
javax.swing.*;
java.awt.*;
java.awt.event.*;
java.io.*;
public class TestStuff
{
public static OutputCommandComp myc;
10
public static void main(String[] args)
try
{
{
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout();
SpecContext sp = new SpecContext(;
sp.addDef("varl", "variable",
20
new SpecLocation("example location of def for varn"));
sp.addDef("macro I", "macro",
new SpecLocation("example location of def for macrol"));
sp.addDef("state3", "state",
new SpecLocation("example location of the def for state 3"));
36
SpecVar s = sp.getVarNamed(" state3");
s.addUsage(new SpecLocation( "example location of some usage of state3"));
s.addUsage(new SpecLocation("example location of some other usage of state3"));
InputStream is = new FilelnputStream("example.save");
ObjectInputStream ois = new ObjectlnputStream(is);
30
myc = new OutputCommandComp(sp, new SpecLocation("the command output panel"));
myc = new OutputCommandComp(ois);
panel.add(myc);
JButton saveB = new JButton("Save");
saveB.addActionListener(new ActionListenerO {
public void actionPerformed(ActionEvent ev)
{
40
try {
System.out.println("starting.
OutputStream os
=
. \n");
new FileOutputStream("example. save");
ObjectOutputStream oos = new ObjectOutputStream(os);
myc.saveSelf(oos);
}
catch (Exception ex)
ex.printStackTrace(;
{
50
}
}
panel.add(saveB, BorderLayout.SOUTH);
JFrame f = new JFrameo;
f.addWindowListener(new BasicWindowMonitorO);
60
JScrollPane jsp = new JScrollPane(panel);
jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL-SCROLLBARALWAYS);
jsp.setHorizontaIScrollBarPolicy(JScrollPane.HORIZONTAL-SCROLLBARALWAYS);
f.getContentPane(.add(jsp);
f.pack(;
f.setVisible(true);
70
}
catch (Exception e)
e.printStackTraceo;
{
}
}
}
80
37
B.8
OutputCommandComp.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
public class OutputCommandComp extends JPanel
static Object[] fieldnames
=
{
{
"Destination",
"Acceptable Values",
new Object[J {
"Units",
"Granularity",
"Exception Handling",
"Hazardous Values"
10
},I
"Timing Behavior",
new Object[] {
"Initiation Delay",
"Completion Deadline",
"Output Capacity Assumptions",
new Object[] {
"Load",
"Min. time between outputs",
"Max. time between outputs",
20
}1
"Hazardous timing behavior",
"Exception-Handling"
},
"Feedback Information",
new Object[] {
"Variables",
"Values",
"Relationship",
"Min. time (latency)",
"Max. time",
"Exception Handling"
30
},
"Reversed By",
"Comments",
"References"
static Object[] tables =
new Object[I {
40
{
new Object[] {
new Object[] {"", "", ""},
new Object[] {"", "", ""}
50
38
};
}
}
Vector textBoxes;
Vector valueNames;
Vector valueTables;
60
SpecContext context;
SpecLocation location;
public OutputCommandComp(SpecContext context, SpecLocation location)
superO;
{
this.context = context;
this.location = location;
70
textBoxes = CreateBoxes(fieldnames, context, location);
valueNames = new VectorO;
valueTables = new Vectoro;
for (int i=O; i < tables.length; i++) {
JTextField tf = new JTextField((String)((Object [])tables[i])[O]);
valueNames.addElement(tf);
Vector tableData = util.ArrayToVector((Object [])((Object [])tables[i])[11);
BooleanTableComp t = new BooleanTableComp( tableData,
context,
location.plus("table #" +
(i + 1) + " in"));
valueTables.addElement(t);
80
}
putThingsInPanel(textBoxes, valueNames, valueTables);
}
90
private void putThingsInPanel(Vector textBoxes, Vector valueNames,
Vector valueTables) {
setLayout(new BoxLayout(this, BoxLayout.Y.AXIS));
AddTextBoxes(textBoxes, this);
// put a 10 pixel margin around everything
setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
100
add(Box.createRigidArea(new Dimension(0,20)));
JLabel def = new JLabel("DEFINITION");
Font defFont = new Font(def.getFont(.getName(,
def.getFont(.getStyle(,
def.getFonto.getSize() + 2);
def.setFont(defFont);
def.setBorder(BorderFactory.createEmptyBorder(O,200,0,0));
add(def);
39
AddTables( valueNames, valueTables );
110
private Vector CreateBoxes(Object[] names,
SpecContext context, SpecLocation location)
Vector textBoxes = new Vector(;
for
{
(nt i = 0; i < names.length; i++) {
if (names[il instanceof String) {
SpecTextBox field = new SpecTextBox((String)names[i], context,
location.plus("in the field \"" +
names[i] + "\" of"));
textBoxes.addElement(field);
}
else
120
{
if (names[i] instanceof Object[]) {
textBoxes.addElement(CreateBoxes((Object[ ])names[i},
context, location));
}
else
{
//
shouldn't have any other types in here
throw new IllegalArgumentExceptionO;
}
}
130
}
return(textBoxes);
}
private void AddTextBoxes(Vector boxes, JPanel p)
{
140
for ( int i = 0; i < boxes.sizeo; i++ )
{
if (boxes.elementAt(i) instanceof SpecTextBox) {
SpecTextBox field = (SpecTextBox)boxes.elementAt(i);
field.setAlignmentX(Component.LEFTALIGNMENT);
p.add(field);
p.add(Box.createRigidArea(new Dimension(0, 5)));
}
else
{
if (boxes.elementAt(i) instanceof Vector) {
JPanel innerp = new JPanel();
innerp.setLayout(new BoxLayout(innerp, BoxLayout.YAXIS));
innerp.setAlignmentX(Component.LEFTALIGNMENT);
150
// recurisively add in the other fields
AddTextBoxes((Vector)boxes.elementAt(i), innerp);
//
indent by 60 pixels
JPanel indentp = new JPanel();
160
indentp.setLayout(new BoxLayout(indentp, BoxLayout.X-AXIS));
indentp.setAlignmentX(Component.LEFT...ALIGNMENT);
indentp.add(Box.createRigidArea(new Dimension(20,0)));
indentp.add(innerp);
p.add(indentp);
}
else
//
{
shouldn't have any other types in here
40
throw new IllegalArgumentException(;
}
170
}
}
}
private void AddTables( Vector valueNames, Vector valueTables
for
){
(nt i = 0; i < tables.length; i++) {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.YAXIS));
JPanel p2 = new JPanel();
p2.setLayout(new BoxLayout(p2, BoxLayout.X.AXIS));
p2.add(new JLabel(" = "));
JTextField tf = (JTextField)valueNames.elementAt(i);
p2.add(tf);
p2.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
p.add(p2);
180
190
BooleanTableComp t = (BooleanTableComp)valueTables.elementAt(i);
t.setBorder(BorderFactory.createEmptyBorder(2,25,2,2));
p.add(t);
p.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
p.setAlignmentX(Component.LEFT-ALIGNMENT);
add(p);
}
}
200
public void saveSelf(java.io.ObjectOutputStream out)
throws java.io.IOException {
// This method saves this to the stream
// we can't just use straight serialization, because because Swing's
// implementation is going to change soon, and so is no good for saving
//
documents!
// have to manually process the Vectors, because they're full of things
210
7/
that can't be serialized, but rather have to be saveSelf'd.
saveTextBoxes(textBoxes, out);
out.writeObject( new Integer(valueNames.size() );
for (nt i=0; i <valueNames.size(); i++) {
String s = ((JTextField)valueNames.elementAt(i)).getText(;
out.writeObject(s);
}
out.writeObject( new Integer(valueTables.sizeo) );
for (nt i=0; i<valueTables.sizeo; i++) {
((BooleanTableComp)valueTables.elementAt(i)).saveSelf (out);
I
out.writeObject(context);
out.writeObject(location);
41
220
I
230
private void saveTextBoxes(Vector textBoxes, java.io. ObjectOutputStream out)
throws java.io.IOException {
// Because textBoxes may be a recursive Vector of Vector, we have to
// process it a little bit differently.
For each element, we have to
// save whether it's a subvector or not, so that we know whether to recurse
// or to just call the SpecTextBox constructor. (Although each sub-vector
//
//
//
starts with an Integer (the length) and not a SpecTextBox, we can't detect
that on the fly, because reading the Integer is done with readObject, and
reading the SpecTextBox is done with a SpecTextBox constructor.
240
out.writeObject( new Integer(textBoxes.size()
for (int i=0; i<textBoxes.sizeo; i++)
);
{
if (textBoxes.elementAt(i) instanceof SpecTextBox) {
out.writeObject(new Boolean(false)); // isn't a Vector
((SpecTextBox)textBoxes.elementAt(i)).saveSelf (out);
} else {
if (textBoxes.elementAt(i) instanceof Vector) {
out.writeObject(new Boolean(true)); // *is* a Vector
saveTextBoxes ((Vector)textBoxes.elementAt (i), out);
} else {
// should never get here
throw new IllegalArgumentException(;
}
}
250
}
}
private Vector loadTextBoxes(java.io.ObjectInputStream in)
throws java.io.IOException, ClassNotFoundException {
260
// See the comment for saveTextBoxes() on why this has to be done this way
Vector textBoxes = new VectorO;
int
for
tbSize = ((Integer)in.readObject().intValue(;
(nt i=0; i<tbSize; i++) {
Boolean isSubVector = (Boolean)in.readObjecto;
if (isSubVector.booleanValueo) {
textBoxes.addElement( loadTextBoxes(in) );
} else {
textBoxes.addElement( new SpecTextBox(in) );
270
}
}
return(textBoxes);
}
public OutputCommandComp(java.io.ObjectInputStream in)
throws java.io.IOException, ClassNotFoundException {
// This constructor is equivalent to a "load" method.
// we can't just use straight serialization,because because Swing's
// implementation is going to change soon, and so is no good for saving
// documents!
42
280
super(;
// load stuff from stream
textBoxes = loadTextBoxes(in);
290
valueNames = new Vectoro;
int vnSize = ((Integer)in.readObjecto).intValue(;
for (int i=O; i<vnSize; i++) {
valueNames.addElement( new JTextField( (String)in.readObject()
}
) );
valueTables = new Vectoro;
int vtSize = ((Integer)in.readObject().intValue(;
for (nt i=0; i<vtSize; i++) {
valueTables.addElement( new BooleanTableComp(in) );
300
}
context
location
=
=
(SpecContext)in.readObject(;
(SpecLocation)in.readObject(;
// reconstruct the rest
putThingsInPanel(textBoxes, valueNames, valueTables);
}
310
B.9
SpecTextBox.java
import
import
import
import
javax.swing.*;
java.awt.*;
java.awt.event.*;
java.util.Vector;
public class SpecTextBox extends JPanel implements FocusListener
private JLabel 1;
private JTextArea ta;
{
10
private SpecContext context;
private SpecLocation location;
private
private
private
private
private
String
String
Vector
Vector
Vector
name;
value;
words;
spaces;
variables;
public SpecTextBox(String name, SpecContext context, SpecLocation location)
super(;
this.name = name;
constructRest(name);
43
{
20
value =
ta.setText(value);
30
words = new Vectoro;
spaces = new Vector(;
variables = new VectorO;
this.context = context;
this.location = location;
}
private void constructRest(String name) {
// sets value, ta, and 1, and adds everything to the panel
40
setLayout(new BoxLayout(this, BoxLayout.XAXIS));
1
= new JLabel(name + ":");
L.setAlignmentY(Component.TOPALIGNMENT);
// can set to height to one, as it will expand as needed.
ta = new JTextArea(1, 30);
ta.setBorder(BorderFactory.createEtchedBorder();
50
ta.setLineWrap(true);
ta.setWrapStyleWord(true);
ta.setAlignmentY(Component.TOP-ALIGNMENT);
//
//
set the FocusListener, so that we can process its contents
when it loses focus.
ta.addFocusListener(this);
add(l);
60
add(Box.createRigidArea(new Dimension(5,0)));
add(ta);
}
public JTextArea getJTextArea()
return(ta);
{
}
70
public void focusGained(FocusEvent e)
// don't care about gaining focus
{
}
void setValue(String s) {
// update the words and variables Vectors, and correspondingly
// update the context based on what in the usage has changed.
if (s.trim().equals(value.trim())
{
//
//
the string didn't change, except for surrounding
whitespace.
//
//
(Do we still want to continue in this case, to find
any words which had been defined as variables since
// we last lookeded at this Expr??? - FIXME
44
80
return;
}
words = new Vectoro;
spaces = new VectorO;
// updates words and spaces
SpecExprParsing.splitString(s, " \t\n\r,
90
.",0
words, spaces);
Vector oldVariables = variables;
variables = SpecExprParsing.loadVariables(words, location, context);
SpecExprParsing.unloadVariables(oldVariables, location, context);
//
//
Should update value/s based on the parsingjust done.
7/
Should eventually be able to do more sophisticated things
to definitions, mark other words with '...'s
100
i.e.: update subscripts to correspond var type. - FIXME
// like link vars
//
as errors, and check syntax of expression, etc. - FIXME
System.out.println("SpecTextBox. setValue ) called in " +
location + "\n" +
"context:\n" + context +
"old
value:
\"
"new value: \""
110
+ value + "1\"1\n" +
+ s + "\"\n");
value = s;
I
public void focusLost(FocusEvent e) {
// parse the contents of the TextArea which just lost
7/ focus.
7/
120
update various values, based on the current text in the TextArea
setValue(getJTextAreao.getText());
I
public void saveSelf(java.io.ObjectOutputStream out)
throws java.io.IOException {
// This method saves this to the stream
/7
/7
7/
we can't just use straight serialization, because because Swing's
130
implementation is going to change soon, and so is no good for saving
documents!
out.writeObject(name);
out.writeObject(value);
//
//
7/
even those these are derived from value, save them too,
so that we don't have to worry about whether variables are
loaded from the file before or after their definitions.
out.writeObject(words);
out.writeObject(spaces);
out.writeObject(variables);
out.writeObject(context);
45
140
out.writeObject(location);
I
public SpecTextBox(java.io.ObjectInputStream in)
throws java.io.IOException, ClassNotFoundException {
// This constructor is equivalent to a "load" method.
// we can't just use straight serialization, because because Swing's
// implementation is going to change soon, and so is no good for saving
// documents!
150
super(;
// load stuff from stream
name = (String)in.readObject(;
160
// create derived things, and add them to the panel
constructRest(name);
// these affect some things set in constructRest()
value = (String)in.readObject(;
ta.setText(value);
words = (Vector)in.readObject(;
spaces = (Vector)in.readObject(;
variables = (Vector)in.readObjecto;
170
context = (SpecContext)in.readObjecto;
location = (SpecLocation)in.readObjecto;
}
}
B.10
import
import
import
import
import
BooleanTableComp.java
javax.swing.*;
javax.swing.table.*;
java.awt.*;
java.awt.event.*;
java.util.Vector;
public class BooleanTableComp extends JPanel
{
private JTable t;
10
private BooleanTableModel btm;
private SpecContext context;
private SpecLocation location;
public BooleanTableComp(SpecContext c, SpecLocation 1)
{
this(null, c, 1);
}
public BooleanTableComp(Vector TableData, SpecContext c, SpecLocation 1)
superO;
46
{
20
context = c;
location
=
1;
if (TableData == null) {
btm = new BooleanTableModel(context, location);
}
else
{
btm = new BooleanTableModel(TableData, c, 1);
}
30
t = constructTable(context, location, btm);
putThingsInPanel(t);
}
private JTable constructTable(SpecContext c, SpecLocation 1, BooleanTableModel btm) {
JTable t;
BooleanTableColumnModel tcm = new BooleanTableColumnModel();
t = new JTable( btm, tcm );
t.setAutoCreateColumnsFromModel(true);
t.setBorder(BorderFactory.createEtchedBorder();
40
t.setDefaultEditor(BooleanAtom.class, new BooleanAtomEdo);
t.setDefaultEditor(BooleanExpr.class, new BooleanExprEd();
return(t);
}
50
private void putThingsInPanel(JTable t) {
// puts the table and some other things in the panel.
// used by both deserializationand the constructor.
JButton rowB = new JButton("New Row");
rowB.setMnemonic( 'R');
rowB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev)
{
btm.addEmptyRowO;
60
}
});
JButton colB = new JButton("New Column");
colB.setMnemonic( 'C');
colB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev)
btm.addEmptyColumn(;
{
}
70
});
//
7/
//-
The mnemonics don't actually work, because everything
I try just tries to edit the table part of things.
FIXME, somehow
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y.AXIS));
buttonPanel.add(rowB);
buttonPanel.add(colB);
80
47
// The table should be in it's own scrollpane, to keep
//
//
//
the buttons in sight at all times. But when we put it
in one, the headers become visible, and the default size
becomes weird. - FIXME
setLayout(new BoxLayout(this, BoxLayout.X-AXIS));
add(t);
add(Box.createRigidArea(new Dimension(5,0)));
add(buttonPanel);
90
}
public void saveSelf(java.io.ObjectOutputStream out)
throws java.io.IOException {
// This method saves this to the stream
// we can't just use straight serialization, because because Swing's
// implementation is going to change soon, and so is no good for saving
//
100
documents!
btm.saveSelf (out);
out.writeObject(context);
out.writeObject(location);
}
public BooleanTableComp(java.io.ObjectInputStream in)
throws java.io.IOException, ClassNotFoundException {
// This constructor is equivalent to a "load" method.
// we can't just use straight serialization, because because Swing's
// implementation is going to change soon, and so is no good for saving
//
documents!
// load stuff from
stream
btm = new BooleanTableModel(in);
context = (SpecContext)in.readObjecto;
location = (SpecLocation)in.readObject(;
}
B.11
110
120
// reconstruct the rest
t = constructTable(context, location, btm);
putThingsInPanel(t); // initialize our parent
BooleanTableModel.java
import javax.swing.table.*;
import javax.swing.*;
import java.util.Vector;
public class BooleanTableModel extends AbstractTableModel
48
{
private
private
private
private
Vector exprs = new VectorO;
Vector atoms = new VectorO;
SpecContext context;
SpecLocation location;
10
public BooleanTableModel(SpecContext c, SpecLocation 1)
{
supero;
context = c;
location
=
1;
// make sure that all tables have at least two columns and one row
Vector v = new VectorO;
v.addElement(new BooleanExpr(context, location.plus("row #1 of")));
v.addElement(new BooleanAtomo);
20
addRow(v);
}
public BooleanTableModel(Vector v, SpecContext c, SpecLocation 1) {
// requires: vector v must be a vector of vectors full of data to
// put into the table, and there must be at least one subvector (row)
// which must contain at least 2 elements (columns), and the first
30
super(;
context = c;
location
for
=
1;
(nt r = 0; r < v.sizeo; r++) {
Vector row = (Vector)v.elementAt(r);
40
addRow(row);
}
}
public void addColumn(Vector columnData) {
// add a new column of BooleanAtoms to the table
if (columnData.sizeo != getRowCount()) {
throw new IllegalArgumentException("The number of elements to be" +
" added must match the size of" +
" the column in the table.");
50
}
Vector v = new VectorO;
for (int r=0; r < getRowCount(; r++) {
if (columnData.elementAt(r) instanceof String) {
60
// call BooleanAtom constructor on Strings
v.addElement( new BooleanAtom((String)columnData.elementAt(r))
} else {
// will cause an exception if the type is wrong
v.addElement((BooleanAtom)columnData.elementAt(r));
}
}
49
);
atoms.addElement(v);
// tell listeners that a new column has been added
70
fireTableStructureChanged(;
}
public void addRow(Vector rowData) {
// add a new row to the table (must consist of
// one BooleanExpr and the rest BooleanAtoms
//
if there are no columns yet, you don't have to match the
// current number of columns!
80
if ((getRowCount() != 0) && (rowData.sizeo != getColumnCount()) {
throw new IllegalArgumentException("The number of elements to be added" +
" must match the size of the row in" +
" the table.");
}
if (rowData.elementAt(0) instanceof String) {
exprs.addElement( new BooleanExpr( context,
location.plus("row #" +
(getRowCounto + 1) +
(String) rowData.elementAt(0)) );
} else {
// this is actually relatively weird, because how can they know the
// location before it's put in the table??? but with the string case
// taken care of above, and the add empty below, it doesn't matter
// too much! - FIXME, sarac
"
of"),
90
//
will cause an exception if the type is wrong
exprs.addElement((BooleanExpr)rowData.elementAt(0));
}
100
//
getRowCount() will always say there is at least one row, since we just
added the expression, so we have to subtract 1.
if (getRowCount( == 1) {
// special case out the first row
//
for
(nt c=l; c < rowData.sizeo; c++) {
Vector v = new VectorO;
BooleanAtom ba;
if (rowData.elementAt(c) instanceof String) {
ba = new BooleanAtom((String)rowData.elementAt(c));
}
else
110
{
//
will cause an exception if the type is wrong
ba = (BooleanAtom)rowData.elementAt(c);
}
v.addElement(ba);
atoms.addElement(v);
}
120
} else { // not the first row
for (nt c=1; c < rowData.sizeo; c++) {
// will cause an exception if the type is wrong
BooleanAtom ba;
if (rowData.elementAt(c) instanceof String)
50
{
ba = new BooleanAtom((String)rowData.elementAt(c));
}
else
{
ba
=
(BooleanAtom)rowData.elementAt(c);
}
((Vector)atoms.elementAt(c-1)).addElement(ba);
130
}
}
//
tell listeners that a row was added to the end
fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1);
}
public void addEmptyColumn() {
// add a new column to the table made up of
// some BooleanAtom's created with the default constructors
140
Vector v = new VectorO;
for (int r=0; r < getRowCount(; r++)
v.addElement(new BooleanAtomo);
{
}
addColumn(v);
150
}
public void addEmptyRow () {
// add a new row to the table made up of a BooleanExpr
// and some BooleanAtom's created with the default constructors
Vector v = new VectorO;
v.addElement(new BooleanExpr(context, location.plus(" row #" +
(getRowCount( + 1) +
of ")));
for (int c=1; c < getColumnCount(; c++)
v.addElement(new BooleanAtomo);
160
{
}
addRow(v);
}
170
public int getRowCount()
return exprs.sizeo;
{
}
public int getColumnCount()
if (atoms.sizeo == 0) {
return(1);
}
else
{
{
180
return( atoms.size() + 1);
}
}
51
public Class getColumnClass(int c)
if (c == 0) {
return(BooleanExpr.class);
} else {
return(BooleanAtom.class);
{
190
}
}
public String getColumnName(int c)
return("col #" + (c + 1));
{
}
public boolean isCellEditable(int r, int c)
public Object getValueAt(int r, int c)
if (c == 0)
}
{
return(true);
}
200
{
{
return(exprs.elementAt(r));
else {
return(((Vector)atoms.elementAt(c -
1)).elementAt(r));
}
}
210
public void setValueAt(Object value, int r, int c) {
if (c == 0) {
if (!(value instanceof BooleanExpr)) {
throw new IllegalArgumentException("Only BooleanExpr values can go in" +
" the first column of the table.");
}
}
exprs.setElementAt(value, r);
else {
if (!(value instanceof BooleanAtom)) {
throw new IllegalArgumentException("Only SimpleBoolean values can go" +
in the later columns of the table.");
220
}
((Vector)atoms.elementAt(c -
1)).setElementAt(value, r);
}
fireTableCellUpdated(r, c);
}
230
public void saveSelf(java.io.ObjectOutputStream out)
throws java.io.IOException {
// This method saves this to the stream
//
//
//
we can't just use straight serialization, because because Swing's
implementation is going to change soon, and so is no good for saving
documents!
out.writeObject(exprs);
out.writeObject(atoms);
out.writeObject(context);
out.writeObject(location);
240
}
52
public BooleanTableModel(java.io.ObjectInputStream in)
throws java.io.IOException, ClassNotFoundException {
// This constructor is equivalent to a "load" method.
// we can't just use straight serialization, because because Swing's
// implementation is going to change soon, and so is no good for saving
//
250
documents!
supero;
exprs = (Vector)in.readObject(;
atoms = (Vector)in.readObjecto;
context = (SpecContext)in.readObjecto;
location = (SpecLocation)in.readObject(;
}
260
//
debugging method, for dumping the data in the table.
public void dumpo {
System.out.println(" exprs: 11+ exprs);
System.out.println("atoms: "+ atoms);
for
(nt r = 0; r < exprs.sizeo; r++) {
System.out.print(" i ");
System.out.print(exprs.elementAt(r) + "i");
270
for
}
c = 0; c < atoms.sizeo; c++) {
System.out.print(((Vector)atoms.elementAt(c)).element At(r) + "I");
(nt
System.out.println(;
}
}
280
B.12
BooleanTableColumnModel.java
import javax.swing.table.*;
public class BooleanTableColumnModel extends DefaultTableColumnModel
public BooleanTableColumnModel()
super(;
{
{
public void addColumn(TableColumn aColumn) {
if (aColumn.getModelIndexo != 0) {
// should find out width of one char in current font,
// instead of hard-coding this. - FIXME, sarac
aColumn.setPreferredWidth(15);
aColumn.setMinWidth(15);
aColumn.setMaxWidth(15);
}
53
10
super.addColumn(aColumn);
20
}
}
B.13
SpecLocation.java
import java.io.Serializable;
{
public class SpecLocation implements Serializable
private String value;
// I have *no* idea how these will actually be eventually implemented.
//
//
URLS? Document Positions? Copies of objects?
//
need a real, non-trivial implementation, that has support
for jumping to locations, etc. That will cause almost
//
everything to change. - FIXME
public SpecLocation(String s)
value = s;
10
{
}
public SpecLocation plus(String s) {
// a method to take part of a SpecLocation, and
// combine it with this SpecLocation to produce a
// a new one.
//
20
//
//
with the current implementation, it takes a String
and we just concat that string onto the front of
this.toString, but there are much better ways.
7/
//
(if we were doing URLs or directories or chapter/section/
figure numbers, we might concat onto the end.)
30
return( new SpecLocation(s +
"
+ this.toString()
);
}
public boolean equals(SpecLocation otherSL) {
// seems like a reasonable definition, especially
//
given our current [lack of] implementation for
//
SpecLocation.
return( toString(.equals(otherSL.toString()
);
}
40
public boolean equals(Object otherSL) {
if (otherSL instanceof SpecLocation) {
return( equals( (SpecLocation)otherSL
} else {
// if it's not a SpecLocation, it's
7/ not the same.
)
);
definitely
return( false );
54
}
50
}
public String toString()
{
return(value);
}
B.14
import
import
import
import
SpecContext.java
java.util.Hashtable;
java.util.Enumeration;
java.util.NoSuchElementException;
java.io.Serializable;
public class SpecContext implements Serializable
//
need to keep track of:
//
defined variables
77
defined macros
{
10
// each has:
// a name (alpha-numeric, no [white]spaces, no underscores?)
7/
/7
//
a type (variable, macro, state)
the location of its definition
a list of places where it appears
// don't allow underscores in names, that way we can use them
7/ as a notation for subscripts
// don't allow whitespace in names, so that it's clear where they
7/ end and begin when appearing in text.
//
//
probably going to want the list itself to be a hashtable,
which means "names" will have to be hashable.
//
Keeping things SYNCronized:
7/
//
7/
everytime something that uses a definition is updated,
any new usages that are added need to be added to the table
under the variable used.
20
30
// any old usages that are removed need to be removed from the
//
table under the variable no longer used.
7/
//
7/
7/
everytime something that creates a definiton is updated,
if a new definition is created, it's added to the table
if an old definition is removed, it can only be removed
if the variable doesn't appear anywhere (better than leaving
dangling links - design decision).
//
7/
7/
//
how to represent locations?
if we keep a pointer to the object, we may be able to find
out where it is, but what if the object is removed from the
55
40
// document without
//
//
//
//
//
7/
//
telling us?
when something is removed, every variable it uses needs to
be updated in the table.
-
(prevents nastier schemes, and no more onerous than making
defining objects remove all usages before letting them be
removed.)
-
this way moving the objects won't be a problem.
-
for this to work, must always use the "same" objects, rather
//
50
than replacing them arbitrarily. (ie, replacement will be
7/
//
//
equivalent to removal and recreation, in two steps.)
could keep some reference to some sort of canonical "document
that forces the URL/anchor issue now, which seems
// location", but
/7
7/
77
like a good thing to avoid if we can (although we'll have to
face it eventually).
77
7/
7/
/7
7/
Can't just keep copies of objects, because we want the overall
7/
Contexts are a way of tying together a single definition with
7/
multiple usages, based on the name given to what is defined.
/7
(Link between the two needs to be bi-directional, so we can
/
60
context to be able to include references to other documents, I
think, plus we'd have to rebuild the context every time we load
a file, if they aren't more canonical than just a copy of the
object where the definition/usage appears.
70
find both definitions and usages at will.)
private Hashtable table;
public SpecContext() {
table = new Hashtableo;
80
}
public void addDef(String name, String type, SpecLocation definition)
throws AlreadyDefinedException, IllegalArgumentException {
try {
SpecVar vax = getVarNamed(name);
/7 if that didn't throw an exception, the variable
90
7/ is
already defined.
throw new AlreadyDefinedException("
}
\""
+ name + "\""
"was already defined.");
catch (NoSuchElementException e) {
/7 do nothing, we were just checking.
+
}
SpecVar var = new SpecVar(name, type, definition);
table.put(name, var);
}
100
public SpecVar getVarNamed(String name) throws NoSuchElementException
56
{
SpecVar var = (SpecVar)table.get(name);
if (var != null) {
// found it, done
return(var);
110
I
// no where else to search
throw new NoSuchElementException("No such key named \"" + name +
"1\"1 in the given context.");
}
//
Don't need to write add usage / get usage methods, since
// the user can manipulate the SpecVar once it's been fetched.
120
public void removeVarNamed(String name)
throws NoSuchElementException, StillInUseException
{
SpecVar var = getVarNamed(name);
if (var.countUsages( != 0) {
throw new StillInUseException("Couldn't remove variable \""
in use.");
+ "\", as it was still
+ name
130
I
table.remove(name);
}
public Enumeration getVarso
return(table.keys();
I
{
140
public int sizeO
{
return(table.sizeo);
}
public String toString(
{
String answer = "\n(---- Begin Context ---- \n";
Enumeration e = getVars(;
while (e.hasMoreElementso) {
answer = answer + getVarNamed((String)e.nextElement()) + "\n";
150
}
answer = answer +
"----
End Context ---- )\n\n";
return( answer
}
}I
160
57
B.15
import
import
import
import
SpecVar.java
java.util.Vector;
java.util.NoSuchElementException;
java.util.Enumeration;
java.io.Serializable;
public class SpecVar implements Serializable
private
private
private
private
{
String name;
String type;
SpecLocation defLoc;
Vector usageLocs; // Vector of SpecLocation's
10
public SpecVar(String name, String type, SpecLocation defLoc)
throws IllegalArgumentException {
for
(nt
i = 0; i < name.length(; i++)
{
// check each character for whitespace
if (Character.isWhitespace(name.charAt(i))) {
throw new IllegalArgumentException("No white space allowed in" +
variable names.");
20
}
//
check each character against the illegal characters
for (int j = 0; j < SpecExprParsing.ILLEGAL-CHARS.length; j++)
if (name.charAt(i) == SpecExprParsing.ILLEGAL-CHARS[j]) {
{
throw new IllegalArgumentException("While trying to create variable named \""
+ name +
"\":
Illegal character '" +
name.charAt(i) +
"'
not allowed in name.");
}
}
30
}
this.name = name;
if (!(type.equals("macro") jj type.equals("state") j
type.equals("variable"))) {
throw new IllegalArgumentException("While trying to create \""
40
+ name +
A SpecVar's type must be" +
macro, state, or variable.");
"\":
}
this.type = type;
this.defLoc = defLoc;
50
this.usageLocs = new Vectoro;
}
public String getName()
return(name);
{
}
58
public String getTypeo
return(type);
{
}
60
public SpecLocation getDefLoc()
return(defLoc);
{
}
public void addUsage(SpecLocation usage) {
// usages may appear more than once, and so may have
// to be deleted more than once, but that's the caller's
// concern.
70
// (i.e., if a variable is used more than once in a given
// section, the caller can count that as more than one usage,
//
as long as they're consistent.)
usageLocs. addElement (usage);
}
public void delUsage(SpecLocation usage) throws NoSuchElementException
// usages may appear more than once, and so may have
// to be deleted more than once, but that's the caller's
// concern.
{
80
//
//
search from the back of the vector, for a little better
efficiency, given the way BooleanExpr is implemented.
int position = usageLocs.lastlndexOf(usage);
if (position == -1)
{ // usage not found
throw new NoSuchElementException(" \"" + name +
"\":
doesn't have the usage \""
+ usage +
90
"\".");
}
usageLocs.removeElementAt(position);
}
public Enumeration getUsages()
{
return(usageLocs.elements());
}
100
public int countUsages()
{
return(usageLocs.sizeo);
}
public String toString()
{
String answer = "l;
110
answer = answer + "The " + getType() + " named \""
+ getName() + "\"
getNameo + "...
+ getTypeo.charAt(0) + ") is defined at:\n";
answer = answer + "\t" + getDefLoc() + "\n";
59
(i.e.,
"
+
if (countUsages() == 0) {
answer = answer + "and is *not* used.\n";
} else {
answer = answer + "and is used in:\n";
120
Enumeration e = getUsages(;
while (e.hasMoreElementso) {
answer = answer + "\t" + (SpecLocation)e.nextElement() + "\n";
}
}
answer = answer + "\n";
return(answer);
130
}
I
B.16
AlreadyDefinedException.java
public class AlreadyDefinedException extends Exception
public AlreadyDefinedException()
superO;
{
{
}
public AlreadyDefinedException(String s)
super(s);
{
10
B.17
StillInUseException.java
public class StillInUseException extends Exception
public StillInUseExceptiono
super(;
{
{
}
public StillInUseException(String s)
super(s);
{
10
B.18
util.java
import java.util.Vector;
public class util
{
60
,1
public static Vector ArrayToVector( Object[] a
Vector answer = new VectorO;
for
(nt i = 0; i < a.length; i++) {
if (a[i] instanceof Object[]) {
answer.addElement(ArrayToVector( (Object[])a[i] ));
else {
answer.addElement(a[i]);
}
}
){
10
}
return( answer );
}
}
B.19
BasicWindowMonitor.java
import java.awt.event.*;
import java.awt.Window;
public class BasicWindowMonitor extends WindowAdapter
public void windowClosing(WindowEvent e)
Window w = e.getWindowo;
w.setVisible(false);
w.disposeo;
System.exit(O);
}
{
{
10
}
61
Bibliography
[1] Patrick Anderson.
A modular framework for reusable research software.
Master's
thesis, Massachusetts Institute of Technology, 2000.
[2] Per
Cederqvist.
Version
management
with
CVS.
http://www.gnu.org/manual/cvs-1.9/cvs .html, 1993.
[3] Nancy Leveson. Safeware: System Safety and Computers. Addison-Wesley, 1995.
[4] Nancy Leveson. Draft intent specifications (including SpecTRM-RL) user manual. Not
yet published, 2000.
[5] Nancy Leveson. Intent specifications: An approach to building human-centered specifications. IEEE Transactions on Software Engineering, January 2000.
[6] Nancy G. Leveson. Completeness in formal specification language design for process
control systems. To be published in Proceedings of Formal Methods in Software Practice, August 2000.
[7] Nancy G. Leveson, Mats P. E. Heimdahl, and Jon Damon Reese. Designing specification languages for process control systems: Lessons learned and steps in the future. In
Proceedings of the 7th European Engineering Conference held jointly with the 7th ACM
SIGSOFT symposium on Foundations of software engineering, September 1999.
[8] Philip
Milne
and
Kathy
Walrath.
Long-term
persistence
for
JavaBeans.
http://java. sun. com/products/jfc/tsc/articles/persistence/index.html,
2000.
[9] Sun
Microsystems,
Inc.
Swing
1.1.1
API
specification.
http: //java. sun. com/products/jf c/swingdoc-api-1.1.1/, 1993-1999.
62
[10] Sun
Microsystems,
Inc.
Java
platform
1.1
API
specification.
http: //java. sun. com/products/jdk/1.1/docs/api/packages .html, 1995-1999.
[11] Sun
Microsystems,
Inc.
Java
foundation
classes:
Now
and the
future.
http: //java. sun. com/products/jf c/whitepaper .html, 2000.
[12] World Wide Web Consortium (W3C).
http://www.w3.org/XML/, 1994-2000.
63
Extensible Markup Language (XML).