written by Francis Chan (fchan@eecs.berkeley.edu)
Java applets and applications are receiving increasing support and popularity from WWW users, as well as system and application developers. The first wave of applets were client-side applications that were downloaded as complete applications. With the use of Java network and socket infrastructure, then came a new class of applications, such as on-line games, chat rooms, whiteboards, that provide limited (real-time) interactivity and data transaction to users. We believe that it is time to extend the boundaries and build a "Java Client Persistent Object Management" infrastructure that allows not just dynamic interaction, but one that utilizes a data-backend, such as a file server or a database, to support persistent objects. The ability to manage objects across the network (WAN or Internet) is of paramount importance especially in applications such as web-based electronic design.
The Java-based PersistentObject package allows Java (client) objects to be managed and manipulated by a network data server. In addition to object storage and retrieval, it also allows capabilities that the remote data backend provides to be extended to client users.
The PersistentObject package allows fields of (persistent) objects to be stored in internal data structures. For remote object management, these information are then extracted to compose a string according to a client-server communication protocol which is then sent over to the data server. The data server then translates the messages received and recreates the object at the data backend. (Object processing in terms of connections/attachments can then take place at the backend. These "connection" relationships forms the basis of representing object fields, vectors, etc..) The client applications can also utilize the capabilities that the data server provides, among these capabilities are: querying and versioning. Moreover, infrastructure that is useful to the general user, such as directory objects for data management and an object browser, is provided as part of the PersistentObject package. (It also serves as an example of the coding requirements for the package.)
The API of the PersistentObject package is simple and intuitive so that application developers can easily utilize the features provided. The package is also flexible and extendible so that it could be tailored towards application-specific needs. Its distributability and scalability make it an attractive means for networked object processing.
The simple API, flexible policy control and inherent advantages of Java as an object-oriented programming language makes the persistent object package a powerful tool and the task to develop applications which uses it straight-forward. Complemented by its distributability and open server needs, the PersistentObject package presents a scalable means to distributed object management in a networked environment.
One of the main goals of building the PersistentObject package was to provide a simple, extendible and flexible tool to empower application developers and users to add value to a networked environment. The overhead for using the package is minimal, and exists mainly in object definition and instantiation. The simple API, which consists of commands such as load, save, connect, etc., allows the complexity of the underlying operations (object persistence, network implementation and workings and interactions of the base classes) to be completely abstracted away from the user.
The current implementation of the package stores and retrieves only the pre-designated fields of the objects. Other fields (private, static, etc.) in the object will be automatically skipped when performing network operations. A similar mechanism has been implemented in the Object Serialization portion of the Java Remote Method Invocation system provided by Sun where static fields and fields that are declared transient will not be processed for remote operations.
The package is flexible in handling policies such as caching and security. While the infrastructure is present for implementing these policies (such as a isDirty field and a dbId field in the objects), no policy is enforced in the current implementation. Application developers are free to use the structures provided to implement the policies that suit their application-specific needs.
Objects can be retrieved either by a unique object id that is issued by the data backend or by a user-defined field that is concatenated after the database directory structure.
Due to the object-oriented nature of Java, it is very easy to extend the functionalities of the base package. For instance, developers are free to create additional objects that inherit from PersistentObject or to simply override existing methods.
The classes are organized in a functionally-modular way so that any component can be changed if certain parameters need to be altered, such as the client-server communication protocol (PO_CommandConstructor.java) or the network connection (PO_NetClient.java) mechanism.
The location where objects are to be loaded from and saved can be changed at the individual-object level (by calling setServer, setPort). This ability allows parallel and distributing processing across the network.
Although the package is built with the intentions of interfacing with a object-oriented database (Objectivity*) backend, its use of generic Java Sockets and transmission of strings make it flexible enough to interface with any backend data server or proxy server.
The table below describes the tradeoffs between choosing different data backends:
|
| |
|
| |
|
|
While the use of an object-oriented data backend currently suffers from slight deficiencies such as inflexible object additions, it was adopted due to its critical ability to preserve object properties and thus provide object manipulation.
Several levels of object security can be offered by the PersistentObject package and its corresponding data server:
In addition to the basic network operations:
Command |
Description |
save | Saves a copy of the object to the data server |
versionSave | Saves a new version of the object to the server |
load | Loads the object with the corresponding ID |
versionLoad | Loads the object with the corresponding ID and version |
a number of object manipulation mechanisms have been implemented as a part of the package:
Command |
Description |
connect | Connects 2 objects in the data backend |
disconnect | Disconnects the objects in the data backend (if they are attached) |
deleteObj | Delete the object in the data backend (all attached objects will also be automatically deleted) |
detachFrom | Detach the current object from the specified directory object (if an attach is made at the directory object level) |
The support of versioning is of great importance, especially to applications and processes such as electronic circuit design and software engineering. Versioning capabilities are built on-top of the basic save/load mechanisms. They are enabled by backend mechanisms and a version (string) field in each persistent object on the front end. The client-end versioning capabilities, which includes, save, retrieve, browse, etc., are described below.
Any (Persistent) object can be saved as a new version using versionSave
Three types of versioned-object retrieval mechanisms are provided:
Users can browse different versions of an object with a graphical user interface - a feature similar to the browsing of contents under a directory object.
Although versioning capabilities are built-in, objects that do
not require versioning need not deal with the implementation.
While versioning mechanisms are provided with the package, other
more sophisticated versioning policies that applications need
can be built on top of underlying capabilities.
The core of the PersistentObject package has itself been used to implement some of the more advanced features that were deemed important and useful to general applications.
In order to facilitate a directory structure in the OODB server, a special class of PersistentObject (DirObject) was implemented. In addition to the PersistentObject functionality, DirObjects also provide special connection-related commands such as detach and getContext.
A Database Browser (graphical user interface) (DBDialog) has been implemented in Java to allow users of the system to peruse the directory structure.
As a basic extension of the package, DataObjects can be used to allow users to easily take advantage of a network data server. Any files or data that can be translated to a string representation can be saved to and retrieved from the data server with the use of this class.
QueryObject was implemented in order to provide a more flexible and effective retrieving mechanism and take advantage of backend intelligence. Currently, the "keyField" (first field) of the object can be used to a pattern matching retrieval. Plans have been made in expand the protocol and package to allow:
VersionObject was implemented to represent a version
object node in the data backend. It acts as the point where the
traversal of versioned objects is performed.
The PersistentObject package consists of 9 main modules/files.
Their respective functionality are described below:
Module-level organization of the PersistentObject package.
Module |
Description |
PersistentObject | This is the main class of the package and the class which all objects which need network access inherits. It is responsible for management of object-specific internal information and network operations, which includes:
|
PO | This is the class where all the static final constants that the PersistentObject package uses are defined and declared.
|
PO_CommandConstructor | The is the class which is responsible for the preparation of commands/ instructions that are to be sent to the network server.
|
PO_NetClient |
This is the class which handles the opening and closing of network connections.
|
PO_ObjectInfo |
This is the class which stores the information (className, content_string, id) of an object queried.
|
DirObject |
This is the class which represents a node of the directory structure of the remote data server.
|
QueryObject |
This is the class which is used to query data at a remote server.
|
VersionObject |
This is the class which is used to represent VersionObject nodes at the data backend.
|
DataObject |
This is the class which enables users to directly access a remote data server (save, load, query, etc.) with minimal implementation.
|
The 2 internal data structures that enable the translation
and manipulation of objects by client methods and remote data servers are:
fieldTypeArray and objFieldVector.
fieldTypeArray - this is an array which stores the type of each field of the object to enable correct type-casting and manipulation.
Regular object types that are currently supported by the package are as follows:
Special/derived object types supports are as follows:
objFieldVector - this is a vector that holds a copy of the fields of the Object which are processed for operations, such as save.
The communication protocol between the client and server follows a modified version of the HTTP protocols. The string "\n\r" is used to delimit fields, with a double occurrence indicating the end of the message. The protocol is fairly efficient in the sense that minimal overhead is sent along with the message. (To read more about the actual protocol, click the above link).
The protocol was designed to translate objects into a string representation and to allow future extensions to handle more functions, such as queries, proxy operations and remote commands/RPC. Although short and straight-forward, this protocol can be used to create and link existing objects in a completely arbitrary manner (partly inspired by the contents and containers relationship in OCT). The persistent objects used in the front-end clients are mirrored onto the server over the network using a translation mechanism that the protocol enables.
Currently, if the object developer wishes to take advantage of and inherit the PersistentObject class, he/she needs to implement the following code segments:
*Example source code is provided at the end for illustrative
purposes.
Although the PersistentObject class is functional at the present stage, there are many directions of extending its functionality and improving its robustness. Some of the possibilities are discussed below.
Currently, use of the PersistentObject class requires the object developer to absorb an initial code implementation cost. Such an overhead, though minimal (for this design), can be further reduced by the development and incorporation of a preprocessor that parses the object (.java) files and automatically generate and compile the code for network object management. However, at this stage, this would be a task that provides little value-added to the development of object management with a Java front-end and thus we do not have immediate plans of developing this particular module.
With an object-oriented data management backend, the application can intelligently make use of server processing power by "shifting" some of the computation/analysis of objects operation to the backend. Load balancing and distribution between a Java application front-end and server backend serves as great future extension of this project or an independent project on its own.
While the package allows for retrieval of individual objects from different servers and ports, the mechanisms for locating an object by providing user-specified properties has not been implemented. Even though resource location is an important aspect of a distributed environment, the discussion and implementation of resource location on top of the persistent object management package is outside the scope of this project. However, efficient resource location itself serves as an interesting and challenging reseach and engineering topic.
The current PersistentObject package has provided many enabling mechanisms in the areas of caching, security, versioning etc.. Application-specific or generic policies can be implemented using the underlying structures and mechanisms.
Different methods and measures can be taken to improve the authenticity, integrity and privacy of the data transmitted to and from the data backend.
The piece of source code below (Class Definition)
is used to illustrate the implementation details of a sample (Persistent)
object definition. The bold portions of the program indicate
the additional code that has to be written to use the package.
The Application Use portion is used to illustrate
how (Persistent) object are/can be used in applications.
import java.util.*; public class WPField extends PersistentObject{ // essential fields of the object private String id; private String name; private int anInt; private char aChar; private boolean boolT; private boolean boolF; private double aDoub; private float aFloat; private int int2; // for network object management
public WPField(String id, String name){ this.id = id; this.name = name; // set some of the fields for testing anInt = 8; aChar = 'a'; boolT = true; boolF = false; aDoub = 13.40; aFloat = 3.401e+37f; int2 = -150; // for Network Persistent Object Management
} // print all the field for information verification public void printFields() { System.out.println("id: " + id); System.out.println("name: " + name); System.out.println("anInt: " + anInt); System.out.println("aChar: " + aChar); System.out.println("boolT: " + boolT); System.out.println("boolF: " + boolF); System.out.println("aDoub: " + aDoub); System.out.println("aFloat: " + aFloat); System.out.println("int2: " + int2); return; } /* *------------------------------------------------------------------- * * The following are methods that object developers need to implement * in order to make extending the Persistent Object work * *------------------------------------------------------------------- */ /** * * The Member object construction should be followed by * a Load so that the essential object field will be set * */
/** * * Sets up the Vector that that contain the "essential" fields * of the object * * (this is a method that a preprocessor can automatically generate * and hence provide more abstraction for the object developer) */
/** * * Loads the object using a string identifier from a network * (persistent object storage) database * backend(and sets it's fields) * */ public boolean load(String strId) { if (loadObject(this.objectClassName, strId, 0, null) == false) { System.out.println("Couldn't load object " + objectClassName + " with strId " + strId); return false; } getObjFields(); return successfulTransmit; }
}
The relevant part of a sample application is provided below:
if (testSave == true) { WPField obj = new WPField("fchan", "Francis Chan"); if (obj.save() != PO.ERROR) { System.out.println("Save Works!"); System.out.println("\n\n"); } else System.out.println("Save doesn't work!"); } if (testLoad == true) { WPField obj = new WPField(); if (obj.load("fchan") == true) { obj.printFields(); System.out.println("\n\n"); } else System.out.println("Load doesn't work!"); }
Detailed information of the package can be found at:
http://embedded.eecs.berkeley.edu/Alumni/fchan/docs/PerstObj/package
Code documentation generated using javadoc can be found at:
http://embedded.eecs.berkeley.edu/Alumni/fchan/docs/PerstObj/doc
Modified: April 16, 1997
Feedback: (
fchan@eecs.berkeley.edu)