ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button
Don Bales

Flawed JDO Points the Way to the "Objectbase"

by Donald Bales, author of Java Programming with Oracle JDBC
04/24/2002

There's been a lot of hype lately about Java Data Objects (JDO). It appears to be the new silver bullet that will alleviate all of our coding drudgery. JDO threatens the livelihood of products such as object/relational mapping utilities that map Java objects to relational data. Because of this, and for other reasons, JDO has received more than its fair share of bad press. To be fair however, JDO does have it merits.

My own take on why the specification evolved is simple: I too am tired of writing JavaBeans to present data from a relational database as objects in my Java programs. I've written lightweight JavaBeans, that simply hold data like a structure and have accessor and mutator methods, to heavyweight JavaBeans, that know how to retrieve and persist themselves.

I have two issues with JDO. The first is that somehow SQL has become a bad thing. SQL remains one of the major breakthroughs in our industry. Its non-procedural mechanics freed us from the high priests that used to control persisted data, and its power to bring together formerly unrelated populations of information still make it the most powerful computing tool of our time. The second is that JDO's abstraction treats a Database Management System (DBMS) like a file. Restated, instead of treating a database like an extension of memory for your application, you end up treating it like a file in a file system, where you open the file, read it into your application, write any changes back out to disk, and then close the file. This kind of behavior does not properly facilitate multi-user access.

Most importantly though, is that a workaround like JDO is indicative of a more fundamental problem: as object-oriented programmers, we have been leveraging object-orientation to improve how we build software, but we have not applied it to solving the business problems for which we write software. We are, for lack of a better term, stuck in the world of functional decomposition. Rather than view the world in a natural way, we abstract things in the real world by categorizing information about them, but ignore their behaviors.

You can see evidence of this predominant way of thinking in the way we communicate. Take the word database for example. Our everyday language is imbued with this word. Object and object-relational persistence vendors call their solutions object database management systems, and object-relational database management systems. Even the employees at Oracle call their persistence solution an object-relational database. What we really need is a different term: objectbase. We need to move our thinking and our problem domain object models into an object persistence layer: an objectbase.

JDO itself is a sentinel that we need to make the paradigm shift from a database -- a place where we persist information -- to an objectbase -- a place where we persist information and behavior. I'm fortunate to have lived through one such paradigm shift, from ISAM/VSAM files, hierarchal databases, and network databases to relational databases. So for me, the shift in thought is not so difficult. But what is an objectbase?

To some, an objectbase is a place where you store and retrieve binary executables that can be accessed as needed anywhere at any time. Computers and networks will be extremely different than they are today when that definition of an objectbase is fulfilled. I, just like you, need a solution now. And that solution currently exists in the form of object-relational (OR) technology. With OR, you define object types in the objectbase, use a tool to generate your JavaBeans to mirror the objectbase types, and then use the Java Database Connectivity (JDBC) API, or SQLJ, to access objects from Java. Oracle's implementation of OR provides you with all of the strengths of their relational database, plus the ability to add methods to object types (or user defined types (UDTs), as they are called in SQL:1999). In this article, in an effort to give you a fair comparison of what is necessary to use OR with JDBC vs. JDO, I'll be showing you how to insert, update, and select a person object using JDBC in a similar fashion to "Using Java Data Objects," published recently on OnJava.com.

Creating a User Defined Type

The first step is to create a user defined type (UDT). To do so, you'll use the SQL CREATE TYPE command, as in this example:

create type PERSON_TYPE as object (
name        varchar2(255),
address     varchar2(255),
ssn         varchar2(255),
email       varchar2(255),
home_phone  varchar2(255),
work_phone  varchar2(255) )

The primary data types you have available to use in defining a new type are those supported by your OBMS vendor. For Oracle, the three most common primary types are: DATE for date and time values, NUMBER for numeric values, and VARCHAR2 for textual values. Here, I've defined a new type, named PERSON_TYPE.

Creating an Object Table

The next step is to create a table based upon our new UDT. A table based upon a UDT is called an object table. To create an object table, you'll use the SQL CREATE TABLE command, as in this example:

create table PERSON_OBJECT_TABLE
          of PERSON_TYPE

Here, I've created an object table named PERSON_OBJECT_TABLE based upon the UDT PERSON_TYPE. This is the table I'll be working with in the example demonstration program. It's important to note that for this example, I've decided to use the object references created by the objectbase as a unique identifier for my object relationships. As an alternative, I could have just as easily used primary and foreign keys, and constraints, as I would with a relational database.

Creating a Mirror Java Class

Once a UDT is created in your database, you can create a mirror class for your Java program by coding a JavaBean that implements the SQLData interface, or, if you're using Oracle, you can use the JPublisher Utility to generate a JavaBean for you. Example 1 is a hand-coded class, Person, to mirror the objectbase's UDT PERSON_TYPE.

Class Person consists of:

  • A list of private variables to hold the data values from the objectbase.
  • A no-argument constructor.
  • A getSQLTypeName() method to provide the JDBC driver with the objectbase UDT name.
  • A readSQL() method to assign the private variables their corresponding objectbase values.
  • A writeSQL() method to save the private variable's values to the objectbase.
  • A set of accessor and mutator methods.

Example 1. The Person class

import java.io.*;
import java.sql.*;

/**
A mirror class to hold a copy of SCOTT.PERSON_TYPE
*/
public class Person implements SQLData, Serializable {
  private String = name;
  private String = address;
  private String = ssn;
  private String = email;
  private String = home_phone;
  private String = work_phone;

  public Person() {
  }
  // SQLData interface
  public String getSQLTypeName()
   throws SQLException {
    return "SCOTT.PERSON_TYPE";
  }
  public void readSQL(SQLInput stream, String type)
   throws SQLException {
    name        = stream.readString();
    address     = stream.readString();
    ssn         = stream.readString();
    email       = stream.readString();
    home_phone  = stream.readString();
    work_phone  = stream.readString();
  }
  public void writeSQL(SQLOutput stream)
   throws SQLException {
    stream.writeString(name);
    stream.writeString(address);
    stream.writeString(ssn);
    stream.writeString(email);
    stream.writeString(home_phone);
    stream.writeString(work_phone);
  }
  // Accessors
  public String getName() {
    return name;
  }
  public String getAddress() {
    return address;
  }
  public String getSsn() {
    return ssn;
  }
  public String getEmail() {
    return email;
  }
  public String getHomePhone() {
    return home_phone;
  }
  public String getWorkPhone() {
    return work_phone;
  }
  // Mutators
  public void setName(String name) {
    this.name  = name;
  }
  public void setAddress(String address) {
    this.address  = address;
  }
  public void setSsn(String ssn) {
    this.ssn  = ssn;
  }
  public void setEmail(String Email) {
    this.email  = email;
  }
  public void setHomePhone(String homePhone) {
    home_phone  = homePhone;
  }
  public void setWorkPhone(String workPhone) {
    work_phone  = workPhone;
  }
}

Coding a JavaBean like this is not hard, but it is tedious. The readSQL() and writeSQL() methods simply read and write the data values from or onto their respective streams in the order in which the attributes exist in the UDT.

Add The New Object Type to the JDBC Type Map

Before you can use your mirror class to retrieve objects from, and to save objects to, an objectbase, you need to let the JDBC Connection you'll be using know that a mirror class exists, and to which UDT it should be mapped. To accomplish this, you'll update the connection's type map.

The type of Connection object, whether it comes from DriverManager or a DataSource, is of no consequence; either will work. In the demonstration program from Example 2, DemonstrateOR, I use a Connection object returned from DriverManager. First, the program gets the current type map from the connection by calling its getTypeMap() method. Next, the program adds an entry to the Map object using its put() method, passing the name of the UDT, and a copy of the mirror class, Person. Last, the program stores the updated type map in the connection by calling its setTypeMap() method, passing the updated Map object. At this point, the JDBC driver knows what Java class to instantiate when a copy of the UDT is retrieved from the objectbase, and vice versa.

Pages: 1, 2

Next Pagearrow