The JDBC Optional Package for CDC-Based J2ME Applications

by Qusay H. Mahmoud
February 2003

The Connected Device Configuration (CDC) is at the heart of the Java 2 Platform, Micro Edition, supporting applications on high-end network-connected devices such as home appliances, set-top boxes, interactive TVs, and handheld PCs. It's natural to expect that many applications written for these devices will need access to information in databases, possibly from different vendors. In applications written for the Java 2 Platform, Standard Edition (J2SE), this kind of access is provided by the Java Database Connectivity (JDBC) API.  To provide CDC-based applications with database access, a subset of the JDBC 3.0 API has been defined as the JDBC Optional Package for CDC/Foundation Profile API.

This article presents an overview of optional packages and shows where they fit in the J2ME architecture, and then explores the JDBC optional package in more detail, comparing and contrasting it with JDBC 3.0. The article:

  • Summarizes the similarities and differences between the JDBC optional package and JDBC 3.0
  • Describes briefly each of the interfaces, classes, and methods that the optional package has inherited from JDBC 3.0
  • Lists the interfaces, classes, and methods not inherited

Note: This article assumes basic familiarity with JDBC.

Overview of Optional Packages

As you may already know, the J2ME defines two main components:

  • Configurations, composed of a Java virtual machine and a minimal set of class libraries. Think of a configuration as a vertical set of APIs that provides the base functionality for a particular range of devices that share similar characteristics, such as memory footprint and network connectivity. A configuration also defines a Java virtual machine to be used on different types of devices.
  • Profiles, a horizontal set of high-level APIs that defines the application life-cycle model, the user interface, and access to services provided by a category of devices.

Profiles extend configurations, and can themselves be extended by other profiles - and by optional packages, which offer standard APIs for using existing and emerging technologies to address specific market requirements. Figure 1 illustrates the software stack that includes the CDC and the Foundation Profile (CDC/FP):

Optional Packages in J2ME CDC/Foundation

Figure 1: Optional Packages in J2ME CDC/Foundation

At this writing, the Java Community Process has defined two optional packages for CDC/Foundation, one for Remote Method Invocation (RMI) and one for JDBC. The J2ME RMI Optional Package (RMI OP) is defined by JSR 66, and the JDBC Optional Package for CDC/Foundation Profile by JSR 169.

The RMI optional package is a subset of the RMI technology in J2SE. It enables applications written in the Java programming language and running on CDC-based networked devices to invoke each other's methods, and the methods of J2SE applications running on larger systems. The RMI optional package and JDBC 3.0 thus enable developers to create applications distributed across a variety of Java virtual machines, running on platforms ranging from handheld devices to network servers. The RMIOP reference implementation can be built with implementations of CDC/FP, including those extended by the Personal Basis Profile.

The JDBC Optional Package

The JDBC optional package has been defined to enable CDC developers to write applications that access relational databases. This package is a subset of the java.sql and javax.sql packages in JDBC 3.0, with the smaller footprint required by CDC-based applications.

Note: As of this writing, no reference implementation of the JDBC optional package exists. When an RI is released, you'll be able to build it with the CDC/FP using the OPT_PKGS= jdbc build option of CDC/Foundation or any other CDC-based profile.

To support the JDBC optional package, a device must meet the requirements for CDC/Foundation, plus an additional 256KB of RAM and 256KB of ROM.

Overview of Changes

The JDBC 3.0 API of J2SE includes functionality that is not applicable for, or not supported by, CDC/Foundation. As a result, some APIs had to be removed. The JDBC optional package is a strict subset of JDBC 3.0, however, so applications built using JDBC CDC/FP are upwardly portable to JDBC 3.0. Details appear later in this article, but here is a summary of the changes that have been made:

  • Support for connection pooling has been removed.
  • The classical way of creating connections, using the DriverManager interface, has been replaced. As a result, the interfaces DriverManager, Driver, and DriverPropertyInfo have been removed, along with the methods DatabaseMetaData.getURL(), RowSet.setURL(), and RowSet.getURL(). You should use the DataSource interface, which minimizes the connection overhead, to create connections.
  • The exception classes no longer write details of thrown exceptions to the log, but driver vendors write the output of toString() to the log. The toString() method is overridden by SQLException and all its subclasses.
  • The interface ParameterMetaData has been removed.
  • Support for setting parameters by name in the CallableStatement interface has been removed.
  • Support for SQL 99 types using the interfaces Array, Ref, Struct, SQLData, SQLInput, and SQLOutput has been removed.
  • The methods setTypeMap() and getTypeMap() have been removed, so you can't use them to perform custom type mapping.

DriverManager vs. DataSource

The DriverManager class, introduced in the original JDBC 1.0 API, requires the application to load a specific driver, using a hard-coded URL. The DataSource interface, introduced in the JDBC 2.0 API, is the preferred way to create connections, because it allows details about the underlying data source to be transparent to the application. An application can be directed to a different data source simply by changing the DataSource object's properties. Similarly, a DataSource implementation can be changed without changing the application code that uses it.

The DataSource is an interface, implemented by a driver manager, that acts as a factory for connections. The following snippet of code uses an instance of DataSource named SomeVendorDataSource to create a Connection to a database server listening at port 5000 on the machine employeeserver:


...
SomeVendorDataSource ds = new SomeVendorDataSource();
ds.setServerName("employeeserver");
ds.setPortNumber(5000);
Connection connection = ds.getConnection("useName",
"password");
...

Inherited Classes and Interfaces

The JDBC optional package for CDC/Foundation has inherited from J2SE's java.sql package the interfaces and classes described in Tables 1, 2, and 3:

Table 1: Interfaces Inherited from the java.sql Package

Interface Description
Blob Used to represent an SQL BLOB type
CallableStatement Used to execute SQL stored procedures
Clob Used to represent an SQL CLOB type
Connection Represents a session with a database
PreparedStatement Represents a precompiled SQL statement
ResultSet A table of data that represents a result set generated by executing a statement that queries the database
ResultSetMetaData Used to get information about the types and properties of columns in a ResultSet object
Savepoint A point within the current transaction that can be referenced from Connection.rollback()
Statement Used to execute and return the output of a static SQL statement

Table 2: Classes Inherited from the java.sql Package

Class Description
Date Used to identify an SQL DATE value
Time Used to identify an SQL TIME value
Timestamp Used to identify an SQL TIMESTAMP value
Types Defines the constants used to identify generic SQL types (also known as JDBC types)

Table 3: Exceptions Inherited from the java.sql Package

Exception Description
BatchUpdateException Thrown when an error occurs during a batch update operation
DataTruncation Thrown when JDBC unexpectedly truncates a data value during a read or write
SQLException Provides information related to a database-access or other type of error
SQLWarning Provides information related to database-access warnings

The javax.sql Package

The javax.sql package provides API for data-source access and manipulation of tabular data as JavaBeans. Originally developed as a supplement to the java.sql package, it is now included in J2SE, as of version 1.4. Table 4 describes the interfaces and the one class that the RMI optional package has inherited from the javax.sql package:

Table 4: Interfaces and classes inherited from the javax.sql package

Interface/Class Description
DataSource A factory for connections to the physical data source; should be used in place of DriverManager
RowSet Adds support to the JDBC API for the JavaBeans component model
RowSetInternal Implemented by a RowSet object to present itself to a RowSetReader or RowSetWriter
RowSetListener Implemented by a component that needs to be notified of events in a RowSet object
RowSetMetaData Represents an object that contains information about columns in a RowSet object
RowSetReader Represents a reader to populate a RowSet object with data
RowSetWrite Represents a writer to write changes back to the underlying data source
RowSetEvent The class instantiated to represent an Event object generated when an event occurs to a RowSet object

Detailed List of Changes

This section provides a detailed list of the interfaces, classes, methods, deprecated methods, and constants that have been removed in the process of subsetting the JDBC API for CDC/Foundation.

Classes and interfaces removed from the java.sql package

  • Array
  • Driver
  • DriverManager
  • ParameterMetaData
  • Ref
  • SQLData
  • SQLInput
  • SQLOutput
  • SQLPermission
  • SQLStruct

Classes and interfaces removed from the javax.sql package

  • ConnectionEventListener
  • ConnectionPoolDataSource
  • PooledConnection
  • XAConnection
  • XADataSource
  • ConnectionEvent

Methods (including constructors) and constants removed from the java.sql and javax.sql packages

  • java.sql.CallableStatement.Object getObject (int, java.util.Map)
  • java.sql.CallableStatement.getArray (int)
  • java.sql.CallableStatement.registerOutParameter(String, int)
  • java.sql.CallableStatement.registerOutParameter(String, int, int)
  • java.sql.CallableStatement.registerOutParameter (String, int, String)
  • java.sql.CallableStatement.setURL(String, java.net.URL)
  • java.sql.CallableStatement.setNull(String, int)
  • java.sql.CallableStatement.setBoolean(String, boolean)
  • java.sql.CallableStatement.setByte(String, byte)
  • java.sql.CallableStatement.setShort(String, short)
  • java.sql.CallableStatement.setInt(String, int)
  • java.sql.CallableStatement.setLong(String, long)
  • java.sql.CallableStatement.setFloat(String, float)
  • java.sql.CallableStatement.setDouble(String, double)
  • java.sql.CallableStatement.setString(String, String)
  • java.sql.CallableStatement.setBytes(String, byte[])
  • java.sql.CallableStatement.setDate(String, java.sql.Date)
  • java.sql.CallableStatement.setTime(String, java.sql.Time)
  • java.sql.CallableStatement.setTimestamp(String, java.sql.Timestamp)
  • java.sql.CallableStatement.setAsciiStream(String, java.io.InputStream, int)
  • java.sql.CallableStatement.setBinaryStream(String, java.io.InputStream, int)
  • java.sql.CallableStatement.setObject(String, Object, int, int)
  • java.sql.CallableStatement.setObject(String, Object, int )
  • java.sql.CallableStatement.setObject(String, Object)
  • java.sql.CallableStatement.setCharacterStream(String, java.io.Reader, int)
  • java.sql.CallableStatement.setDate(String, java.sql.Date, Calendar)
  • java.sql.CallableStatement.setTime(String, java.sql.Time, Calendar)
  • java.sql.CallableStatement.setTimestamp(String, java.sql.Timestamp, Calendar)
  • java.sql.CallableStatement.setNull (int, int, String)
  • java.sql.CallableStatement.getString(String)
  • java.sql.CallableStatement.getBoolean(String)
  • java.sql.CallableStatement.getByte(String)
  • java.sql.CallableStatement.getShort(String)
  • java.sql.CallableStatement.getInt(String)
  • java.sql.CallableStatement.getLong(String)
  • java.sql.CallableStatement.getFloat(String)
  • java.sql.CallableStatement.getDouble(String)
  • java.sql.CallableStatement.getBytes(String)
  • java.sql.CallableStatement.getDate(String)
  • java.sql.CallableStatement.getTimestamp(String)
  • java.sql.CallableStatement.getObject(String)
  • java.sql.CallableStatement.getObject (String, java.util.Map)
  • java.sql.CallableStatement.getRef (String)
  • java.sql.CallableStatement.getBlob (String)
  • java.sql.CallableStatement.getClob (String)
  • java.sql.CallableStatement.getArray (String)
  • java.sql.CallableStatement.getDate(String, Calendar)
  • java.sql.CallableStatement.getTime(String, Calendar)
  • java.sql.CallableStatement.getTimestamp(String, Calendar)
  • java.sql.CallableStatement.getURL(String)
  • java.sql.DatabaseMetaData.getURL()
  • java.sql.Connection.getTypeMap()
  • java.sql.Connection.setTypeMap(java.util.Map)
  • java.sql.PreparedStatement.setRef (int, Ref)
  • java.sql.PreparedStatement.setArray (int, Array)
  • java.sql.PreparedStatement.ParameterMetaData getParameterMetaData()
  • java.sql.ResultSet.getObject(int, java.util.Map)
  • java.sql.ResultSet.getRef(int)
  • java.sql.ResultSet.getArray(int)
  • java.sql.ResultSet.getObject(String, java.util.Map)
  • java.sql.ResultSet.getRef(String)
  • java.sql.ResultSet.getArray(String)
  • java.sql.ResultSet.updateRef(int, java.sql.Ref)
  • java.sql.ResultSet.updateRef(String, java.sql.Ref)
  • java.sql.ResultSet.updateArray(int, java.sql.Array)
  • java.sql.ResultSet.updateArray(String, java.sql.Array)
  • javax.sql.Rowset.getURL()
  • javax.sql.Rowset.setURL(String)
  • java.sql.CallableStatement.java.getBigDecimal(int, int)
  • java.sql.CallableStatement.getBigDecimal(int)
  • java.sql.CallableStatement.setBigDecimal(String, BigDecimal)
  • java.sql.CallableStatement.getBigDecimal(String )
  • java.sql.PreparedStatement.setBigDecimal(int, BigDecimal)
  • java.sql.ResultSet.getBigDecimal(int, int)
  • java.sql.ResultSet.getBigDecimal(String, int)
  • java.sql.ResultSet.getBigDecimal(int)
  • java.sql.ResultSet.getBigDecimal(String)
  • java.sql.ResultSet.updateBigDecimal(int, BigDecimal)
  • java.sql.ResultSet.updateBigDecimal(String, BigDecimal)
  • java.sql.Date(int, int, int) (constructor)
  • java.sql.Time(int, int, int) (constructor)
  • java.sql.Timestamp(int, int, int, int, int, int, int) (constructor)

Deprecated methods removed

  • java.sql.CallableStatement.getBigDecimal(int, int)
  • java.sql.Date.getHours()
  • java.sql.Date.setHours(int)
  • java.sql.Date.getMinutes()
  • java.sql.Date.setMinutes(int)
  • java.sql.Date.getSeconds()
  • java.sql.Date.setSeconds(int)
  • java.sql.DriverManager.getLogStream()
  • java.sql.DriverManager.setLogStream(PrintStream)
  • java.sql.PreparedStatement.setUnicodeStream(int, InputStream, int)
  • java.sql.ResultSet.getBigDecimal(int, int)
  • java.sql.ResultSet.getBigDecimal(String, int)
  • java.sql.ResultSet.getUnicodeStream(int)
  • java.sql.ResultSet.getUnicodeStream(String)
  • java.sql.Time.getDate()
  • java.sql.Time.setDate(int)
  • java.sql.Time.getDay()
  • java.sql.Time.getMonth()
  • java.sql.Time.setMonth(int)
  • java.sql.Time.getYear()
  • java.sql.Time.setYear(int)

Conclusion

This article presented an overview of the two optional packages currently available for CDC/Foundation, which support RMI and JDBC. The JDBC optional package enables your CDC-based J2ME applications to access data in relational databases from Oracle, Sybase, MySQL, and others. Subsetting the JDBC 3.0 API for CDC entailed removing some APIs that are not supported by CDC, or not suitable for CDC-based applications. The article described the JDBC 3.0 APIs that are included in the optional package, and listed the ones that aren't.

For more information

About the Author: Qusay H. Mahmoud provides Java consulting and training services. He has published dozens of articles on Java, and is the author of Distributed Programming with Java (Manning Publications, 1999) and Learning Wireless Java (O'Reilly & Associates, 2002).