Java Client Persistent Object Management

written by Francis Chan (fchan@eecs.berkeley.edu)


Objective

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.

Introduction

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.

Package Description

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.

Simple

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.

Flexible

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.

Extensible

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.

Distributed

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.

Server Requirements

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:
Server Type
Capability/Advantage
Disadvantage
Object-Oriented Database
  • Object characteristics and properties can be preserved.
  • The whole database needs to be recompiled/re-linked after the manual entry of any new schema (object definition), which requires database administrator access.
Relational Database
  • Fairly flexible in object addition, deletion and manipulation.
  • Can provide built-in database capabilities (e.g. query, attribute processing).
  • Requires mapping of object from object-oriented structure to a relational representation.
  • Object properties may not be accurately represented (such as links, sharing objects).
  • Not much room for object manipulation.
File Server
  • Minimal extra software required.
  • Complex object mapping techniques is required.
  • An (intelligent) transaction manager in the native environment has to be implemented.

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.

Security

Several levels of object security can be offered by the PersistentObject package and its corresponding data server:

  1. Objects can only be accessed by their owner (performing a check on the DB identifier)
  2. Objects with read-only permission can be read by anyone, while objects with write permission enabled can be modified by anyone. (These are implemented with the use of a permission field in both the front-end and back-end objects.)

Object Manipulation Mechanisms

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)

Versioning

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.

Save

Any (Persistent) object can be saved as a new version using versionSave

Retrieval

Three types of versioned-object retrieval mechanisms are provided:

  1. Retrieving a specific version (e.g. version A.B)
  2. Retrieving the latest release (with version flag set as "R")
  3. Retrieving the latest version (with version flag set as "L")

Browse

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.

Mechanisms

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.

Extensions in the Package

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.

Directory Objects

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.

Data Objects

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.

Query Objects

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:

Version Objects

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.

Technical Description

Module Organization

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:
  • instantiating internal data structures for further processing
  • setting and updating remote server
  • saving and retrieving remotely
  • parsing network servers' responses
  • setting connections with other PersistentObjects or DirObjects
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.

Internal Data Structures

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.

Client-Server Communication Protocol

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.

Implementation Requirements

Currently, if the object developer wishes to take advantage of and inherit the PersistentObject class, he/she needs to implement the following code segments:

  1. Add the extends PersistentObject clause during object definition

  2. Make the method call
    netObjSetup(int numField, int numObjField, String objectClassName)
    with the corresponding arguments during object construction. (This method call takes care of the setting up of the internal data structures for remote data transaction.)

  3. Implement the (object-specific) method
    setObjFields().
    For each of the field of the object, the object developer must make a call
    setField(int nthField, VARIABLE_TYPE variable_name, int type)
    with the respective order of the field, the field name and specify the type.

  4. Implement the method
    getObjFields()
    For each of the field of the object, the object developer must make a call
    getField(int nthField, INDICATOR_TYPE INDICATOR)
    with the respective order of the field and the field_type indicator.

*Example source code is provided at the end for illustrative purposes.

Future Extensions and Considerations

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.

Preprocessor of Source Class Files

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.

Client-Server Load Distribution

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.

Resource Location

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.

Object Management Policies

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.

Security

Different methods and measures can be taken to improve the authenticity, integrity and privacy of the data transmitted to and from the data backend.

  1. Authorized access of objects on the backend (login/password). Session control and efficient multi-user support will likely be the next developmental focus.
  2. Check-length of protocol message to provide greater security measures for verifying that message received is in fact message sent.
  3. Checksum or other encryption schemes (e.g. digital signatures) can be added to the transmission and receipt of message streams to ensure privacy of network session.

Example Source Code

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.

Class Definition (WPField)

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 static final String objectClassName = "WPField";
public static final int numField = 9;
public static final int numObjField = 0;
  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
netObjSetup(numField, numObjField, objectClassName);
  }

  // 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
   *
   */

public WPField() {

netObjSetup(numField, numObjField, objectClassName);
}
  
  /**
   *
   * 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)
   */
protected void setObjFields() {

setField(0, this.id, PO.STRING);
setField(1, this.name, PO.STRING);
setField(2, this.anInt, PO.INT);
setField(3, this.aChar, PO.CHAR);
setField(4, this.boolT, PO.BOOLEAN);
setField(5, this.boolF, PO.BOOLEAN);
setField(6, this.aDoub, PO.DOUBLE);
setField(7, this.aFloat, PO.FLOAT);
setField(8, this.int2, PO.INT);

}

  /**
   *
   * 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;
  }
protected void getObjFields(){

this.id = getField(0, PO.STRING_INDICATOR);
this.name = getField(1, PO.STRING_INDICATOR);
this.anInt = getField(2, PO.INT_INDICATOR);
this.aChar = getField(3, PO.CHAR_INDICATOR);
this.boolT = getField(4, PO.BOOLEAN_INDICATOR);
this.boolF = getField(5, PO.BOOLEAN_INDICATOR);
this.aDoub = getField(6, PO.DOUBLE_INDICATOR);
this.aFloat = getField(7, PO.FLOAT_INDICATOR);
this.int2 = getField(8, PO.INT_INDICATOR);

}
}

Application Use

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!");
    }

Package Distribution Information

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)