Principles

JSO works as a persitence layer, encapsulating O-R mapping and database access, so that you don't have to worry about it. You should only code your classes (according to some rules) and let JSO do the rest. Persistence code in your application should be limited to calls to JSO's API, requesting the storage or the retrieval of objects.

You don't need to specify how your object model will be mapped to the database. JSO will inspect your classes in runtime (through Java's reflection API) and store them transparently. You don't even have to know how the database is modeled. In fact, you should not access the database directly, only through JSO. This runtime mapping forbids JSO accessing legacy data.

Before running your application you should create an empty database and grant permissions to a specific user. This database and user will be passed to JSO, through configuration (properties) files, which will initialize the database upon startup. After that, persistence services become available to the application. As your application request those services, storable classes are inspected and their definitions are stored in the database. Also, new tables are created to house their instances.

Requirements

JSO's major goal is to provide persistence to Java objects in relational databases, acting as persistence layer and handling the problem known as "impedance mismatch". This layer should exempt application developers from implementing persistence code (like SQL statements) or specifying mapping metadata (like XML descriptors). Some requirements were defined for this layer:

Almost all requirements are applied. Garbage collection must suffer some improvements and schema evolution has currently no support.

To be used with JSO, relational databases must fulfill some requirements:

Architecture

The persistence layer implemented by JSO is divided in two main modules:

Many kinds of configurations may be obtained with this architecture. The simplest one consists of the application program, the controller, the manager ant the database running on the same computer, with the first three running on the same Java virtual machine. This configuration is considered to be a local one, because the communication between the manager and the controller is made through local calls.


Local configuration

A more complex configuration could be obtained running the database and the controller in one node of a network and programs and managers in other nodes. This configuration is considered to be distributed, because the managers communicate to the controller through remote calls (RMI).


Distributed configuration

The many possible configurations are defined through a "storage environment" (net.sf.jso.StorageEnvironment). This environment has the ability to start and stop local and distributed application programs, connecting the managers to the controller.

When a distributed configuration is used the environment creates a "home" to the controller and registers it in the RMI registry of the node. The remote reference to the home may be acquired by a name specified by the developer. The remote reference to the controller may be acquired through the home, after an authentication process. The authentication consists of the validation of a user name and a password, also specified by the developer.


Distributed applications obtaining remote references to storage controllers

Features

The fulfillment of the requirements and the use of the architecture discussed above allow JSO to offer the following features:

As we mention in the
to do section there are other features we wish to implement in the future.

Rules

JSO offers a great level of freedom to developers for the implementation of storable classes. In spite of that, some rules apply:

  1. To be stored by JSO a class must implement the interface net.sf.jso.Storable or be one of the following:
    • net.sf.jso.text.Text
    • java.lang.Boolean
    • java.lang.Byte
    • java.lang.Character
    • java.lang.Double
    • java.lang.Float
    • java.lang.Integer
    • java.lang.Long
    • java.lang.Short
    • java.lang.String
    • java.util.Date
    • java.util.Collection
    • java.util.List
    • java.util.Map
    • java.util.Set
    • java.sql.Time
    • java.sql.Timestamp
    The net.sf.jso.Storable interface is merely a marker and has no fields or methods, like the java.io.Serializable interface.
  2. Every Storable class must have a public void constructor.
  3. A Storable class must not have its qualified name started by jso (case insensitive) and must not have the character '_'.
  4. A Storable class must not be final
  5. Fields of Storable classes may be any of the Java primitive types or a reference to any of the classes listed in item 1.
  6. Fields with modifiers final, static, transient or volatile will not be stored.
  7. Array fields will not be stored.
  8. A Storable class must not have any fields named oid (case insensitive).
  9. Queries are only allowed over "accessible" fields. A field is considered accessible if:
    • The field is public.
    • The field has a corresponding getter method.
    • The field is declared as such through class metadata (more on this later).
  10. Binary relationships between classes are supporte through container classes:
    • Collections (Collection, List or Set).
    • Maps (Map).

Storable objects

Basically, storable objects are all instances of Storable classes and all classes listed in the first rule (as seen in the previous topic. Storable classes (and objects), writen by the developer, may also use additional features: object metadata, class metadata and callback methods.

Besides its own value (values of fields), a storable object also has storage metadata. This metadata represents information about the storage process of an object. This information may be used by the application for some purpose. Storable classes my declare a field called jsoMetadata, of type net.sf.jso.StorableMetadata, and that field will be updated every time the storable object suffer the action of the storage manager. Through the StorableMetadata interface the developer may get the manager which performed the last persistence operation on the object, object's identification (OID) and if the object is a summary object.

A summary object is an object that has been retrieved from the database with only part of its value, more specifically only with the value of its summary fields. These fields may be specified through class metadata (as we will see below) and can be considered as a "projection" of the object's field set. The definition of these fields is optional and the lack of it makes the summary of the object equal to the complete set of fields. Nevertheless, using this feature may be very usefull. For example, when displaying the result of a query usually a list containing only some of the classe's fields is shown to the user. The fields shown in the list may be defined as the summary fields. The queries may then use summary objects as results to save resources.

To specify the summary fields, and other "storable" characteristics, of a class, the developer may use class metadata. The first time a Storable class is presented to JSO it is inspected and some information is obtained and stored in the database, for later use. At this point an opportunity is given to the developer to supply more information about how the class should be stored or used. A Storable class may implement the static method jsoClassMetadata() (no parameters or throws clauses) that returns an object of the type net.sf.jso.schema.StorableClassMetadata. When a class is inspected this method is called (if it exists) and its result is used to inform JSO about more class' characteristcs.

The StorableClassMetadata class allows the developer inform JSO:

Finally, Storable objects may be aware of persistence events (operations). Three callback methods may be declared in the Storable class:

All three methods return nothing, have no parameters and do not throw checked exceptions.

String x Text

In Java the java.lang.String class is commonly used to store strings of many sizes, from simple words to long texts. Storing strings in a database, nevertheless, requires some distinguishment. The storage cost of arbitrarily long strings is inevitably higher than that of short strings.

In order to provide means for the developer making such distinguishment JSO offers the class net.sf.jso.text.Text. Short strings (containing up to 255 characters) should be represented by the String class while long strings should be represented by the Text class. Strings are stored in the database as columns of the VARCHAR JDBC type while Texts are stored as columns of the LONGVARCHAR JDBC type.

The Text class works in a similar way to the String class. It is also immutable and offers a subset of the String class interface. The use of the concatenation operator (+) is not possible though.