LDO Lightweight Data Objects SourceForge.net Logo
SourceForge Download Install Documentation Credits
 
LDOs are lightweight Data Objects, Java classes that provide access to a table or view in a SQL database in a simple manner. The advantages of LDOs over more complex and capable database access classes and Object/Relational mapping frameworks are:

LDOs came about due to frustrations using other database access tools, particularly those that provided a results container that did things on behalf of the row objects, ranther than allowing objects representing rows handle internal row matters themselves. This seemed to us like a more simple object-oriented approach.

LDOs were first used on web application projects with the Enhydra framework. Later they were used on the server side of a distributed desktop application. They had become a design pattern that worked. The code was reused in the copy, paste, and modify style.

The LDO Wizard was created to eliminate some of the drudgery of that type of code reuse. It is intended for initial code generation that is close to what is needed. Code rework is still required to make the LDO fit an application's needs exactly, but it is of the more interested sort that allows the programmer to address user needs with ingenuity.

LDO Wizard
The LDO Wizard allows the the programmer to specify Java class attributes such as the Class name, a superclass name if any, and a package. A set of checkboxes controls what methods the generated LDO will have. Most LDOs don't need to update the database, for heavy database update work an Object/Relational framework may be worth the trouble. However, in some cases the occasional update is more easily handled with an LDO. The LDO wizard optionally generates code for such inserts, updates, and/or deletes.

The LDO wizard will generate a JUnit test class for each LDO class. The JUnit test classes inherit from BaseDOTest. A template for BaseDOTest is provided with the LDO wizard software. It can be customized for the specific project if the generated JUnit test classes are to be used for the project.

The Select Statement input dialog provides the most useful feature of the LDO Wizard. It allows the programmer to create and debug the SQL Select statement in their favorite SQL Query tool, then copy and paste it into the LDO Wizard. The LDO Wizard does not execute the SQL statement itself, it merely parses the statement in order to determine what instance variables are needed in the generated Java class.

Once the select statement has been parsed the programmer can set the Java data type of each column, and can specify what columns will be used in a WHERE clause to retrieve a single row from the database table.

The Generate Java Code button prompts for a file name and location, and creates the Java code that will implement the LDO. The following is an example of the generated code.

package com.test;

import java.sql.*;
import java.util.ArrayList;

/** The TestDO represents rows in the TEST table. */

public class TestDO extends BaseDO {
  private BigInteger col1;
  private String col2;
  private Blob col3;
  private String col4;
  private Timestamp col5;
  public static final String COL1_COLUMN_NAME = "COL1";
  public static final String COL2_COLUMN_NAME = "COL2";
  public static final String COL3_COLUMN_NAME = "COL3";
  public static final String COL4_COLUMN_NAME = "COL4";
  public static final String COL5_COLUMN_NAME = "COL5";

  /** Get all the records from the database. Returns an array of instances of TestDO.*/
  public static TestDO[] getTestDOs(Connection con) throws SQLException {
    String query = "SELECT  COL1, COL2, COL3, COL4, COL5 FROM TEST";
    PreparedStatement stmt = null;
    ArrayList outputArray = new ArrayList();
    try {
      stmt = con.prepareStatement(query);
      ResultSet result = stmt.executeQuery();
      while (result.next()) {
        //construct an instance
        outputArray.add(new TestDO(result));
      }
    }
    finally {
      stmt.close();
    }
    return (TestDO[])outputArray.toArray(new TestDO[outputArray.size()]);
  }

  /** Get a record from the database for a specified key. Returns an instance of TestDO or null if no record is found.*/
  public static TestDO getTestDO(BigInteger col1, String col2,  Connection con) throws SQLException {
    String query = "SELECT  COL1, COL2, COL3, COL4, COL5 FROM TEST WHERE COL1 = ? AND COL2 = ? ";
    PreparedStatement stmt = null;
    TestDO newDO = null;
    try {
      stmt = con.prepareStatement(query);
      stmt.setBigDecimal(1, null == col1 ? null : new BigDecimal(col1));
      stmt.setString(2, col2);
      ResultSet result = stmt.executeQuery();
      if (result.next()) {
        //construct an instance
        newDO = new TestDO(result);
      }
    }
    finally {
      stmt.close();
    }
    return newDO;
  }

  /** Creates a new instance with the id initialized from its sequence. The instance can then be populated and its insert() method called to insert it into the database. */
  public static TestDO newInstance(Connection con) throws SQLException {
    String query = "SELECT SEQ_COL1.NEXTVAL AS COL1 FROM DUAL";
    PreparedStatement stmt = null;
    TestDO newDO = new TestDO();
    try {
      stmt = con.prepareStatement(query);
      ResultSet result = stmt.executeQuery();
      if (result.next()) {
        newDO.setCol1(null == result.getBigDecimal(COL1_COLUMN_NAME) ? null : result.getBigDecimal(COL1_COLUMN_NAME).toBigInteger());
      }
      else {
        throw new SQLException("Could not get new COL1 from SEQ_COL1");
      }
    }
    finally {
      stmt.close();
    }
    return newDO;
  }

  /** Default constructor for this class, which returns a new empty object which can be populated and inserted. */

  public TestDO() {
    super();
  }

  /** Constructor for this class, which returns a new object populated with data returned from the database. */

  public TestDO(ResultSet result) throws SQLException {
    col1 = null == result.getBigDecimal(COL1_COLUMN_NAME) ? null : result.getBigDecimal(COL1_COLUMN_NAME).toBigInteger();
    col2 = result.getString(COL2_COLUMN_NAME);
    col3 = result.getBlob(COL3_COLUMN_NAME);
    col4 = result.getString(COL4_COLUMN_NAME);
    col5 = result.getTimestamp(COL5_COLUMN_NAME);
  }

  public String toString() {
    return "TestDO[col1=" + col1 + ",col2=" + col2 + ",col3=" + col3 + ",col4=" + col4 + ",col5=" + col5 + "]";
  }

  /** Inserts the instance into the database. If the Connection parameter has autocommit enabled the insert will be committed. Otherwise it is up to the caller to manage the connection and commit or rollback as required. */
  public void insert(Connection con) throws SQLException {
    String query = "INSERT INTO TEST (COL1, COL2, COL3, COL4, COL5) VALUES (?, ?, ?, ?, ?)";
    PreparedStatement stmt = null;
    try {
      stmt = con.prepareStatement(query);
      stmt.setBigDecimal(1, null == col1 ? null : new BigDecimal(col1));
      stmt.setString(2, col2);
      stmt.setBlob(3, col3);
      stmt.setString(4, col4);
      stmt.setTimestamp(5, col5);
      stmt.executeUpdate();
    }
    finally {
      stmt.close();
    }
  }

  /** Updates the instance in the database. If the Connection parameter has autocommit enabled the update will be committed. Otherwise it is up to the caller to manage the connection and commit or rollback as required. */
  public void update(Connection con) throws SQLException {
    String query = "UPDATE TEST SET COL3 = ?, COL4 = ?, COL5 = ? WHERE COL1 = ? AND COL2 = ? ";
    PreparedStatement stmt = null;
    try {
      stmt = con.prepareStatement(query);
      stmt.setBlob(1, col3);
      stmt.setString(2, col4);
      stmt.setTimestamp(3, col5);
      stmt.setBigDecimal(4, null == col1 ? null : new BigDecimal(col1));
      stmt.setString(5, col2);
      stmt.executeUpdate();
    }
    finally {
      stmt.close();
    }
  }

  /** Deletes the row for the instance from the database. If the Connection parameter has autocommit enabled the delete will be committed. Otherwise it is up to the caller to manage the connection and commit or rollback as required. */
  public void delete(Connection con) throws SQLException {
    String query = "DELETE FROM TEST WHERE COL1 = ? AND COL2 = ?  ";
    PreparedStatement stmt = null;
    try {
      stmt = con.prepareStatement(query);
      stmt.setBigDecimal(1, null == col1 ? null : new BigDecimal(col1));
      stmt.setString(2, col2);
      stmt.executeUpdate();
    }
    finally {
      stmt.close();
    }
  }

  public BigInteger getCol1() {
    return col1;
  }

  public void setCol1(BigInteger value) {
    col1 = value;
  }

  public String getCol2() {
    return col2;
  }

  public void setCol2(String value) {
    col2 = value;
  }

  public Blob getCol3() {
    return col3;
  }

  public void setCol3(Blob value) {
    col3 = value;
  }

  public String getCol4() {
    return col4;
  }

  public void setCol4(String value) {
    col4 = value;
  }

  public Timestamp getCol5() {
    return col5;
  }

  public void setCol5(Timestamp value) {
    col5 = value;
  }

}


The LDO Wizard is written in Ruby. It can be easily modified to change the specifics of the generated Java code. The User Interface is implemented using the vruby toolkit. This limits the LdoWizard to MS Windows, but LDO java classes may be used in any development environment. If a non-Windows version of the LdoWizard is desired it can easily be built using one of Ruby's cross-platform GUI toolkits.