Chapter 5

                                                Implementation

 

 

Previous

Table of Contents

Next

 

 

5.0 Introduction

The next stage of the Object Modelling Technique (OMT) is the implementation of the design.  Implementation is the process of translating the detailed design into code (Schach, 1997).  This should be a relatively straightforward process as all the difficult design decisions and ideas have already been clarified and refined, at this stage the design is not final and will be revised as additional functionality is identified.  Along with writing the code the system must be clearly documented, as this helps simplify any maintenance that must be performed on the system after implementation and testing have been performed. 

 

This chapter outlines how a programmer would typically use JDBC to perform database access and communications.  Then it demonstrates how the framework developed here can be used to provide easier database access.  Using this simplified abstraction of JDBC, a mechanism for object relational mapping and a prototype which demonstrates its usage is then developed.

 

5.1 Implementing JDBC

The first thing that a database application must do is open a connection with a database.  Database applications can have one or more connections with a single database, or it can have connections with many different databases (Javasoft, 1996). JDBC enables this by creating a Connection object.  The Connection object is subsequently used for all communications between the application and the database.  There are two steps involved in opening a connection with a database.

1.      Loading the driver.

2.      Making the connection.

Drivers can be loaded in two ways, firstly all the available drivers can be specified in a list and the driver manager works through them until the correct driver for the specified database is loaded.  Secondly, the programmer can explicitly load a required driver by specifying the name of the driver.  For example when loading the JDBC: ODBC driver the following code is used;

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

 
 

 

 


The next step in establishing a connection is to tell the driver to create a connection to a specified database.  The database is specified using a Universal Resource Locator (URL).  JDBC URL’s provides a very flexible method of naming databases as they are an extension of Web URLs, a JDBC URL is made up of three parts;

   jdbc:<subprotocol>:<subname>

 
           

 

 

The first part of a JDBC URL is always “jdbc”.  The “subprotocol” is usually the driver or database connectivity mechanism, which may be supported by one or more drivers.  The “subname” provides a way for identifying the database.  As the JDBC ODBC bridge driver is being used to connect to an Access database, the URL required to do so is shown below, Access7 is a Data Source Name (DSN) identifying the target database.

    String url="jdbc:odbc:Access7";

 

 
 

 

 


A Connection object can now be created, the target database supports a username and a password so this is included when creating the connection;

   Connection conn=DriverManager.getConnection(url,"user","password");

 
 

 

 

 


Once a connection has been opened database queries, updates or data definition tasks can be executed.  Depending on which task a programmer wishes to carry out there are a number of things that can be done, but first a Statement object must be created.

 

5.1.1 JDBC Statements

Statement objects are used to send SQL statements to the target database.  They are created using an open Connection object, for example;

   Statement stmt = conn.createStatement();

 
 


           

 

The Statement object together with a SQL string can now be executed.  The type of SQL statement will determine what method will be used to execute it.  The executeQuery method is used to search and retrieve values from a database and the executeUpdate method is used for data definition and database update statements.  For example the following statement creates a database table named cars which contains three columns;

   Stmt.executeUpdate(“CREATE TABLE Car (Reg-no var char(12),”+

        “Make varchar(12), Model varchar(12)”);

 
           

 

 

 

Values are also entered into a database using the executeUpdate method.  The following statement stores a Toyota Carina and its registration number in a database;

   Stmt.executeUpdate(“INSERT INTO Car VALUES(‘95 DL 2772’, ‘Toyota’,

                                                  ‘Carina’);

 
 


           

           

           

5.1.2 Retrieving Data

Retrieving stored information from a database is more complicated than storing information.  It involves using a SQL command to perform a search based on search criteria, the query is executed using the executeQuery method.  A ResultSet object is created based on the query to hold the results, which can then be manipulated or displayed, for example;

    ResultSet rst = stmt.executeQuery(“SELECT Regno, Model FROM Car”);

 

 
 


           

 

The rst variable is an instance of the ResultSet class.  When executed it will contain rows of registration numbers and models of cars that are stored in the Car table.  To access the values held in the ResultSet a loop is used, a cursor marks the position of the current row of the ResultSet and tells if any more rows exist.  This is done using the next method.  JDBC does not support scrollable cursors due to the fact that most DBMS do not support them (Hamilton et al., 1997).  As a result it is not possible to use JDBC as it stands to move backwards in a ResultSet.

 

The values in each column of the ResultSet are accessed using a getXXX method of the appropriate type.  For example to access the Regno column, which is stored in the database as a varchar, the getString method is used.  The getString method converts the value from the database type to a Java string.  The getInt and getFloat methods would be used to access integer and float values if their equivalent exist in the database.  The following code retrieves the values from the rst ResultSet object and displays them;

   While(rst.next()){

                         String s = rst.getString(“Regno”);

                         String t = rst.getString(“Model”);

                         System.oun.println(s + “     ” + t);

   }

 
           

 

 

 

 

 

 

In the previous code sample, each column was accessed by name.  The columns in a ResultSet, can also be accessed by number from left to right.  Both methods of identifying the columns will provide the same result, but using an index is slightly more efficient.

 

The getString method converts the value stored in the database to a Java string.  It is quite a powerful method and can be used to access all SQL types (Hamilton et al., 1997).  It is useful in situations were the column type is not known and is used when accessing data from ResultSets in this project, see appendix A.

 

5.1.3 Meta Data

Metadata is used to find out information about a database and generated ResultSets.  It is useful in scenarios where information is not known about the database and the layout of the data stored in the tables.  It is used to enable programs to dynamically discover this information at runtime.  JDBC uses the ResultSetMetaData and the DatabaseMetaData classes to provide this information.

 

The ResultSetMetaData class is used to find out information about generated ResultSets.  A ResultSetMetaData object is first created for a specific ResultSet, for example;

        ResultSetMetaData rmeta = rst.getMetaData();

 

 
 


           

The rmeta object can now be used to discover information about the rst ResultSet object.  The ResultSetMetaData getXXX methods are used to discover this information, for example, getColumnCount will return the number of columns in the table and getColumnName will return the name of a specified column.  The implementation of both these methods can be seen on Appendix A where they were used to dynamically find out and display information for any SQL query.

 

5.2 Exception Handling

Correcting errors caused by faulty or inappropriate code has traditionally cost a lot of money and effort in the past.  Maintenance was the largest phase in the software development life cycle (Elshoff, 1976; Daly, 1977; Zelkowitz et al., 1979; Boehm,  1981).  Errors can be minimised by using an appropriate software development methodology (Schah, 1997) such as OMT, which focuses on the design of the intended system.  But at the end of the day it is up to the programmer to implement this design.  The language chosen to implement the system can play an important role in generating reliable code.  Java is an excellent language in this regard, Jaworski (1997) verifies this;

“The Java language eliminates whole classes of errors that result from the use of dangerous programming constructs such as pointers and automatic type conversions.  The simplicity and familiarity of the language also reduces the occurrence of programming errors”.

Java allows runtime errors and exceptions to be caught and effectively dealt with.  Java’s exception handling is a significant new feature of the Java language and is similar but not the same as, exception handling in C++ (Flanagan, 1996).

 

To catch and deal with exceptions in Java, the blocks of statements for which exception processing is to be performed is surrounded by a try statement.  At the end of the try block is a catch clause which specifies what type of exceptions the programmer expects might occur and how to deal with them (Flanagan, 1996; Hamilton et al., 1997).  For example;

 

 

                                                                                         try(

                      // Code that could generate an exception is placed here.

                      // If an exception is generated, the catch block will deal with it.

                } catch(SQLException e){

                      // Handle the exception object e of type SQLException

                      // or of a subclass of that type.

                }

 
           

 

 

 

 

 

 

 

As a result all exception handling is located together, this provides a different scenario to traditional programming languages, as exceptions had to be pre-empted and checks made before the code could be executed (Freeman & Ince, 1996).

 

When a class is written the type of exceptions which can occur is indicated using the throws keyword.  Operations involving an instance of these classes are surrounded by a try block and the mentioned exceptions are dealt with by the catch block.

 

When writing database applications exception handling is important.  JDBC provides a comprehensive mechanism for catching exceptions.  Most of the java.sql classes throws an exception, the most common being the SQLException object.  The SQLException class provides information about errors which occur when accessing a relational database.  It is an extension of the java.lang.Exception class (Hamilton et al., 1997).  For example when loading the JDBC ODBC database driver the ClassNotFoundException  is thrown and must be caught;

                try {

                                class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);

                }

                catch(java.lang.ClassNotFoundException e){

                                System.err.print(“ClassNotFoundException : “);

                                System.err.println(e.getMessage());

                }

 
           

 

 

 

 

 

 

 

When creating Connections, Statements and accessing the database to perform any database related task the try catch blocks are used.  The programmer developing the application must perform all the necessary catching of thrown exceptions.  By creating a higher level on top of JDBC, the programmer will not be concerned with these exceptions as they are dealt with behind the scenes.

 

5.3 Developing a Higher Level Abstraction of JDBC

In the design chapter, the structure of this higher level abstraction of JDBC was first designed.  The abstraction consists of one main class, which encapsulates details about database Connections, Statements and ResultSets.  The class also contains the necessary methods to perform database operations.  The initial class diagram for the DatabaseConnect class is shown in fig 5.1.

 

 

It depicts the sequence of events which occur when the class is initialised and the order in which the methods are executed.  First a connection is opened with a database, which depends on which constructor was used.  The default constructor accepts no parameters and connects to the default database i.e. Access7.  If the second constructor is used the programmer can specify which database to connect to.  When a connection is opened a Statement object can then be created.  SQL commands can be executed using the exeSql method which takes the SQL command as a parameter.  A ResultSet object is created using the createResultSet method  which accepts a SQL query as the basis for creating the ResultSet object.  The Connection, Statement and ResultSet objects can be closed using the closeXXX methods or they can all be closed together using the closeAll method.

5.3.1 Visibility Modifiers

When developing the higher level abstraction, Java’s visibility modifiers were used when declaring variables and methods.  Visibility modifiers specify how the variables and methods of a class will be seen and used by another programmer using the DatabaseConnect class.  Java provides five main visibility modifiers.

1.      Public.

2.      Private.

3.      Protected

4.      Private Protected.

5.      Default.

By declaring a class, variable or method public this means they are visible every-where.  Private methods and variables can only be seen and used by methods within the same class.  They are not inherited by subclasses like other variables and methods.  A private protected method or variable is only visible within its own class and within subclasses.  A protected method or variable is visible within the class which defines it and within subclasses and classes belonging to the same package as the defining class.  Protected and private protected visibility is used to hide methods and variables from classes that use the defining class, but it enables classes which extend the defined class to see and use them.  The default visibility is more strict than protected.  A variable or method which does not specify a visibility modifier during declaration receives default visibility.  This means the variable or method can only be seen and used from within the same class that defines it and in classes belonging to the same package but not in subclasses. 

 

When implementing the DatabaseConnect class, all of the variables were declared protected except for the ResultSet and ResultSetMetaData variables which were declared public.  This means a programmer using the DatabaseConnect class can not see the protected variables, but it allows the programmer to extend the functionality offered by defining a subclass of DatabaseConnect, which can use them.  The ResultSet and ResultSetMetaData variables were declared public to enable a programmer using the DatabaseConnect class more freedom of choice when working with ResultSets.  All of the methods were declared public.  This enables them to be seen and used from any location, they provide the interface for the DatabaseConnect class and specify how the class will be used.

5.3.2 Instance Variables and Methods

Along with the visibility modifier Java provides two main ways in which a variable or method can be used.  They can either belong to the defining class or belong to an instance of the class.  All of the variables defined for the DatabaseConnect class belong to instances of the class, i.e. whenever a new object is created a new instance of each of the variables are also created.  Some class methods were used, both class methods and variables are created using the static keyword.  Static or class variables are accessed via the defining class and only one instance of each class variable and method exists for the defining class.  This is also true for class methods and provides syntax similar to non object-oriented programming languages.

 

5.4 Framework for Object-Relational Mapping

While the DatabaseConnect class was designed to be implemented directly by programmers developing database applications, the mechanism for object relational mapping was designed as a base or parent class for programmers using it.  This means the programmer will create a new class that is a subclass of the Mapping class.  Java enables subclasses to be created using the extends keyword, for example; 

   public class Car extends Mapping{

 
 

 

 


The Mapping class contains two constructors, the first allows a new instance of an object to be initialised and stored.  The second is used to reinitialise an object that has been previously stored.  Both of the Mapping constructors accepts three parameters which specifies the number of attributes which the new object will contain, the database table column name of the primary key and the primary key of the object being initialised.  The difference between the call to each constructor is the sequence by which the input parameters are passed to the constructors.  When a Mapping constructor is called it sets the fields variable to the same value as the number of object attributes.  It then initialises a new DatabaseConnect object, this is illustrated in fig 5.2. 

 

 

The createSql and attributes variables are initialised and the object name variable is set to the same name as the calling object.  This is done by creating an instance of the Java.lang.Class class i.e. fClass.  The object fClass is initialised to the same values as the calling class instance using the “this” keyword.  The objectName variable is then set using the getName method as shown below.

private Class fClass = this.getClass();

objectName = fClass.getName();

 
 

 

 


The Mapping class is designed to provide a direct mapping between an objects attributes and the corresponding values stored in a relational database table.  To enable an instance of a subclass of the Mapping class to keep track of it’s attributes,

three classes were created to hold the attribute values.  These classes are named Fint, Fdouble and Fstring.  The classes store the information normally contained within the data types int, double and the String object.  They allow the Mapping class to dynamically access both the name and the contents of the new objects attributes.  This enables the Mapping class to use the attribute name and data type when creating a new database table and the attribute value when storing the subclass in a database table.  The three classes are similar in structure, so the class diagram for Fdouble is illustrated in fig 5.3;

 

 

The Mapping class uses the three classes via the methods createString, createInt and createDouble.  When these methods are called they increment the fieldcount variable, append the attribute name and data type to the createSql variable and add the attributes to the attributes variable.

 

The Mapping object can now be used to create a database table for its class type, or if one exists it can be stored.  These actions are carried out using the createTable and store methods.  The implementation of both these methods are similar, see fig 5.4, they first append the appropriate commands to the SQL statement to be executed.  They then execute the SQL statement using a DatabaseConnect object, they finally close the database Statement and Connection objects.

 

5.5 Implementing the Graphical User Interface.

The prototype application consists of a single class “Gui”.  Gui is made up of four text fields, to accept user input values, a text area to display the results and a button, which initialises the connection to a database.  When the button is pressed the connection is triggered using an action listener, which is associated with the button by creating a new instance of an inner class.

 

 

The inner class  must be defined within the main class.  Shown below are the lines of code which define an action listener, associates it with a button and the definition of the inner class.

 

Gui.HandleButton btn = new Gui.HandleButton();

ConnectButton.addActionListener(btn);

 

class HandleButton implements ActionListener{

     public void actionPerformed(ActionEvent ev){

       

          // Code which is executed when connectButton

          // is pressed, is placed here.

     }

}

 
 

 

 

 

 

 


 

 

The values are extracted from the text fields and used as the parameters for creating a database connection, or as the query to be performed on the database.  Once a query has been inserted and the connect button pressed, a connection is opened with the database using an instance of the DatabaseConnect class.  This enables the query to be issued and the results to be displayed in the text area.  Fig 5.5 shows the layout of the prototype database application.

 

 

5.6 Conclusion

This chapter outlines how JDBC provides functionality via the Java language.  It then describes the features of Java which were used to implement this project.  Based on the OMT design carried out in chapter four, the class DatabaseConnect was implemented, which enables a connection to be opened with a database, queries to be executed and the results to be returned.  The Mapping class, which provides the framework for object relational mapping, was then implemented.  The OMT design simplified the process of implementing the project by clearly specifying the components of each class, but it was not sufficient when designing the low level actions of the class.  JSP schematics (Culwin, 1998) helped in this regard.  The next stage in the system development process involves evaluating the implementation in terms of how it meets the original requirements, as outlined in the problem statement.  The next chapter is concerned with evaluation of this system.

Previous

Table of Contents

Next

 

Home