Design Overview
Goals
The library has been written with the following goals in mind:
- Ease of use. Third parties should be able to learn how to use the library very easily.
The library is comprehensively javadoc'd and this document tries to explain how it fits together.
The bundled CVS command line tool (i.e. e.g. java -jar org-netbeans-lib-cvsclient.jar -d :pserver:anoncvs@netbeans.org:/cvs co javacvs)
also enables programmers to see how it works. It is hoped that the
library provides enough abstraction to avoid the need for anything more than basic understanding
of how the CVS protocol works.
- Extensibility. The library provides a framework for processing CVS commands. Should the
protocol be extended or altered, it should be easy to modify the library to handle this.
- Compatibility. The command-line CVS implementation from
www.cvshome.org is by far the most common way of interacting with
CVS repositories. Full compatibility with that tool is required, and the user should be able to
switch between that tool and one using this library without either tool breaking. Any incompatibility
should be considered a bug in this library.
However, should a more efficient way of storing administrative files and information be developed for use by this library, it should be possible to specify easily an alternative implementation of various functions to improve performance at the expense of compatibility.
- Quality. The library should be written with maintainability in mind. All code must adhere to
the coding standards and all methods must have appropriate javadoc comments. Any significant changes must
be discussed on the javacvs-dev mailing list before being committed to the repository.
The current implementation is the result of looking at the published protocol document only
(version 1.10). The C implementation of the CVS tool has been consulted only where the protocol
specification was ambiguous or unclear.
Classes
UML diagrams
Thanks to
Financial Finesse for donating the work of
Myron Ahn, who created these UML diagrams that show the structure of the
library:
- Main classes.
- Events.
- Requests and Responses.
- Builders and InfoContainers.
Making a connection
Making a connection with a server using standard CVS can be achieved in several ways, e.g. server,
pserver, kserver and so on. Currently
pserver and
server are supported. The interface
org.netbeans.cvsclient.connection.Connection provides a mechanism for getting input and output streams for communicating with the server, and for setting up those streams.
PServerConnection adds extra calls to set up pserver-specific information, such as the port
number.
Passwords
Password scrambling could be done in different ways although the author is unaware of more than one
scheme being in existence. However, for future expandability, a
Scrambler interface exists,
and
StandardScrambler implements it, scrambling characters as described in the CVS protocol
document 1.10.
The storing of the password in a
.cvspass file is not part of the protocol hence is not
part of the library. It could be added to a utilities package, perhaps. A method exists in the test
harness to do this, though and this can be used freely.
Logging
The command-line CVS client has the facility to log data transmitted between client and server. The
library provides the same facility. The log destination can be set using the property "cvsClientLog".
Either set it to a file location (where it will write log information) or to the value "system" to make
it send output to stderr. The filename, if specified, will have .out and .in appended to it for
data transmitted to and received from the cvs server respectively.
Communication with the server
The
org.netbeans.lib.cvsclient.Client class is responsible for the coordination of communcation with the server.
It accepts a
org.netbeans.lib.cvsclient.connection.Connection object to provide the channel for communication. Most of its work
is done by delegation. Once you have constructed a
Client you typically pass it
org.netbeans.lib.cvsclient.command.Command instances to execute.
The CVS protocol is defined in terms of
requests and
responses. However, these do not map directly to anything that an average CVS user could relate to. A typical CVS command, such as
update or
commit requires using several requests and processing a variety of responses from the server. The
request and
response packages handle these protocol elements and are discussed later.
Issuing Commands
The
org.netbeans.lib.cvsclient.command package contains the commands that users of
the API use. To send a CVS command, the user constructs an object that extends
Command
and sets some parameters on it (optionally) before passing the command to the
Client
instance to execute. The commands implement all or nearly all of the options available in the CVS
command line client. Global options can be set using the
GlobalOptions class.
Currently implemented commands are:
- add
- checkout
- commit
- diff
- log
- remove
- status
- tag
- update
Command Details
The implementation of each command basically involves putting together a list of requests. Users of
the library do not really require to know the details of this.
Since many of the commands' request sequences are very similar, a generic implementation
of
Command is provided that many commands can easily subclass,
BasicCommand. The interface
org.netbeans.lib.cvsclient.ClientServices provides the command with any
facilities it might require to create the requests, such as getting information from the
administrative files (e.g. the Entries file).
Requests and Responses
Request classes essentially just format data and send it to the server over the
OutputStream.
Again, the user of the library is not concerned with the actual implementation of the
Request
classes.
Responses read data from the server, and verify it is what is expected and perform various functions
depending on that data, for example writing files or updating administrative files. One issue with
the handling of responses is that the server intermingles the transmission of character data and
bytes (file transmissions). This means that
Readers and
Writers cannot be
used. This has caused problems with Japanese localisation - for more details see
this bug report.
Admin Files
The writing of the administrative details (commonly stored in a CVS subdirectory under each directory)
is handled by an
AdminHandler. The
Client class delegates various things to
the installed handler. Currently there is only one handler supplied, the
StandardAdminHandler (that provides compatibility with standard command-line CVS) but
it is hoped that this could be extended to provide a high-performance handler.
Events
The client application is informed of the changes a command has made by being sent a series of events.
For example, if you perform an update and a file is changed, you are sent a
FileUpdatedEvent.
This is a list of events current fired:
FileAddedEvent. Indicates that a file has been added (created).
FileInfoEvent. Fired when a structure containing data has been completed (see
builders for details).
FileRemovedEvent. Indicates that a file has been removed (deleted).
FileUpdatedEvent. Indicates that an existing file has been updated.
MessageEvent. A message has been sent from the server that should be displayed to the
user.
EnhancedMessageEvent. Messages that are generated by the library to help the cvs
client software display extra information to the user. Tells the client about files being sent to the
server and also files being merged.
FileInfoContainers
For commands that return a lot of structured data, such as
Log, the library provides classes that
parse the output of CVS commands and turn them into useful data structures. This saves the application
programmer from writing a lot of event handling code.
The classes that parse the output and turn it into a meaningful structure are known as
builders.
The structures themselves are known as
FileInfoContainers. There are several subclasses that are of
interest to the library user:
DefaultFileInfoContainer. Contains generic information about files such as type (is it a
directory?) and state (was it updated or merged?).
CommitInformation. Populated after execution of a commit command. Includes the
revision of the file.
LogInformation. Populated after execution of a log command. Therefore contains
a great deal of information!
ModuleListInformation. Contains the list of modules (e.g. after the equivalent of
cvs co -c).
PipedFileInformation. When you pipe information using -p, the file is saved as a temp
file and this class enables you to find out the details for that file.
RemoveInformation. Details of a file that has been removed.
StatusInformation. Populated after execution of a status command. Also contains
quite a lot of information.
AddInformation. Populated after executing the add command. Allows you to determine
if the file has been resurrected or if it was added for the first time.