public int ejbCreateString username, String passwordthrows CreateException, RemoteException {} public void ejbPostCreateString course, String instructor { public int ejbCreateString user
Trang 1public int ejbCreate(String username, String password)
throws CreateException, RemoteException {}
public void ejbPostCreate(String course, String instructor) {
public int ejbCreate(String username, String password)
throws CreateException, RemoveException {InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup( "java:comp/env/jdbc/AccountsDB" );
Connection conn = ds.getConnection();
"INSERT INTO acc_acc (null, ?, ?, ? ,?)");
Trang 2stmt.executeUpdate();
stmt.close();
} conn.close();
} catch (Exception ex) {
throw new java.rmi.RemoteException( "ejbCreate Error", ex ); }
DataSource ds = (DataSource) ctx.lookup( "java:comp/env/jdbc/AccountsDB" );
Connection conn = ds.getConnection();
stmt.close();
conn.close();
} catch (Exception ex) { throw new java.rmi.RemoteException( "ejbLoad Error", ex ); }
if ( ! found ) throw new java.rmi.RemoteException( "Bean not found" );
Trang 3In this code, the database table is checked for a row with a specific acc_id value If a match is found, all of the bean’s attributes are set based on the returned row; otherwise, an exception is thrown.
ejbStore()
The ejbStore() method is responsible for placing the bean’s information back into the database table This isn’t an INSERT into the table, but an UPDATE of
a previously created row The code might look like this:
public void ejbStore()
throws java.rmi.RemoteException
{
boolean found = false;
try { InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup( "java:comp/env/jdbc/AccountsDB" );
Connection conn = ds.getConnection();
stmt.close();
conn.close();
} catch (Exception ex) { throw new java.rmi.RemoteException( "ejbLoad Error", ex ); }
}
This code performs an UPDATE on the database table using the values stored
in the attributes of the bean
ejbRemove()
The ejbRemove() method is designed to delete the rows from the database for the table based on the current acc_id of the bean The code looks like this:public void ejbRemove()
throws java.rmi.RemoteException
Trang 4boolean found = false;
try { InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup( "java:comp/env/jdbc/AccountsDB" );
Connection conn = ds.getConnection();
}
ejbFindByPrimaryKey()
The ejbFindByPrimaryKey() method returns a String representation of the mary key for the current bean The code checks to make sure the row exists in the table before returning the account id The code for the method is
pri-public String findByPrimaryKey() throws RemoteException {
try {InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup( "java:comp/env/jdbc/AccountsDB" );
Connection conn = ds.getConnection();
"findByPrimaryKey Error", ex );
}} catch (Exception ex) { throw new java.rmi.RemoteException( "ejbLoad Error", ex ); }
}
Trang 5Setter/Getter Methods
You need to implement all of the setter/getter methods defined in the CMP bean
in the BMP bean, but you have to set/get the attributes of the bean yourself Once all of the methods have been placed in the bean, there will be no notice- able difference between the CMP and the BMP beans.
What’s Next
In this chapter, we presented a simple example of how to build an entity bean that will access data in a MySQL database using the Connector/J driver In the next chapter, we build a MySQL database interface
Trang 7I n previous chapters, we have explored many of the elements involved in
bringing MySQL and Java together to address database-related needs In this chapter, we shift our focus to building a general database application For the sake of maximizing both generality and potential usefulness, we will build a graphical interface for MySQL Such an application offers ample oppor- tunity to demonstrate a number of Java’s strengths, both in terms of the lan- guage itself and its ability to work with data sources via the JDBC API.
The application we present in this chapter is built around the notion of base tasks Over the course of development, we introduce four such tasks The first provides information about the underlying JDBC driver and database prod- uct, including names and version numbers The second provides an interface for executing arbitrary SQL queries The third provides the user with informa- tion regarding the column definitions for a given table Finally, we define a task that allows the user to insert a new row into an existing table Along the way,
data-we also develop a number of utility classes that support extensibility by simplifying input, output, task delegation, exception handling, and session ini- tiation Given our focus, the user interface is of course less refined than it might
be for a production application Furthermore, depending on user needs, the individual tasks might lack a degree of functionality (e.g., meaningful handling
of binary data); however, the application should convey some of what is possible and provide a foundation for developing and implementing more sophisticated tasks.
Building a General Interface
for MySQL
C H A P T E R
12
247
Trang 8With the exception of the most generic of interfaces, the range of operations you might need to carry out on a data source is so diverse that attempting to capture all of them in a single application is impractical While generic inter- faces certainly have their place, they tend to require more knowledge and expe- rience on the part of the user By moving away from a generic interface, you find it becomes easier to tailor operations to specific user tasks.
It is the notion of specific user tasks that drives the design of our MySQL face However, if the interface is to remain generally useful, it is important that the task code not be tied too tightly to framework of the interface Unless the addition and removal of tasks is straightforward, an interface that is useful for one user might very well be useless for another An obvious approach to addressing this issue involves viewing tasks as removable modules and building
inter-a frinter-amework in support of such modules While it is not within the scope of this chapter to build a complete, full-featured framework for such modules, the example application does provide one possible approach to developing such a framework.
Accepting that our interface is to be built around task modules, the obvious question becomes one of what constitutes a task From the user’s perspective,
a task is some useful unit of work; whether that corresponds to retrieving a ial piece of information from the database or carrying out a complex transac- tion depends on the needs of a particular user From the perspective of our interface design, a task is an entity that has a name, a delegate class, and a flag indicating whether it is currently enabled The name is a simple task identifier used by interface components that must deal with task identity The delegate class represents the type of the object to which task completion is delegated The enabled flag provides a technique for specifying whether the task is to be considered active by the interface This task definition is captured and encap- sulated by the TaskDefinition class shown in Listing 12.1.
triv-package mysqljava;
public class TaskDefinition
{
public TaskDefinition( String name,
Class delegate, boolean enabled ){
Listing 12.1 The class representing task modules (continues)
Trang 9private String name;
private Class delegate;
private boolean enabled;
}
Listing 12.1 The class representing task modules (continued)
Holding to the goal of simple task addition and removal, defined tasks are vided through a configuration file containing entries like the following:
at Listing 12.2 to see how the configuration file is processed to generate a task list Given an InputStreamReader representing a configuration file, an object of type Tasks parses the task definition entries, converts the fields to appropriate types, creates corresponding TaskDefinition objects, and makes the task list available via an Enumeration.
Trang 10StringTokenizer taskTok = new StringTokenizer( taskLine,
Listing 12.2 The class representing the list of defined tasks modules (continues)
Trang 11Class taskClass = null;
String taskClassName = taskTok.nextToken();
String taskName = taskTok.nextToken();
TaskDefinition def = new TaskDefinition( taskName,
taskClass,taskEnabled );
taskDefs.add( def );
}
private Vector taskDefs = new Vector();
final static int TOKEN_NUM = 3;
final static String DELIM = ":";
}
Listing 12.2 The class representing the list of defined tasks modules (continued)
Trang 12SQL Exceptions
One common feature shared by most of the JDBC API methods is that they make use of the SQLException class, either directly or indirectly, through derived exception classes As such, it is worth a little upfront effort to provide some generalized SQLException processing For the purposes of our sample application, we limit ourselves to a single message-processing method This method, defined in our SqlExceptionReader class, is shown in Listing 12.3.
In addition to the functionality inherited from the java.lang.Exception, ception provides a SQLState code, a vendor-specific exception code, and the ability to chain additional SQLException objects The readException() method
SQLEx-of SqlExceptionReader extracts the additional fields, stepping through the exception chain if necessary, and builds an exception message containing the available information.
msg.append( "Exception " + exceptionNumber + ": \n" );
msg.append( " Message: " + sqlX.getMessage() + "\n" );
msg.append( " State : " + sqlX.getSQLState() + "\n" );
msg.append( " Code : " + sqlX.getErrorCode() + "\n" );
Trang 13MySQL Connections
Since a data source connection is a prerequisite for any task involving nication with a database, it makes sense to capture the required connection data in a common class We do this with the ConnectionData class shown in Listing 12.4 This class represents a host name and port, a database name, and
commu-a userncommu-ame commu-and pcommu-assword Accessors for userncommu-ame commu-and pcommu-assword commu-are provided, along with an accessor that returns a MySQL-compatible URL of the formjdbc:mysql://hostname:port/database_name
Perhaps more useful is the class’s buildConnection() method, which uses the contained URL data, username, and password to obtain and return a Connec- tion object As is seen in the listing, we opted to use the DriverManager approach to obtaining a Connection object Depending on your environment, it might make more sense to obtain Connection objects from a source imple- menting the DataSource or ConnectionPoolDataSource interfaces specified in the javax.sql package.
public String getPassword()
Listing 12.4 The class used for establishing database connections (continues)
Trang 14}
private String hostName;
private String dbName;
private String port;
private String username;
private String password;
}
Listing 12.4 The class used for establishing database connections (continued)
Trang 15The Task Delegate
In defining the interface’s view of a task, we introduced the notion of a task delegate As implied by the name, this is an entity to which the interface dele-
gates responsibility for task execution, whatever that might involve The gate might in turn hand over responsibility for portions of the task to other entities; however, a major design goal is that our interface need not be con- cerned with what happens after it has dispatched the task In working toward this goal, we introduce the TaskDelegate Java interface shown in Listing 12.5 This is a Java language interface that must be implemented by any class that is
dele-to serve as a task delegate When a delegate’s execute() method is invoked, the caller is responsible for providing an appropriate session object The method’s return value indicates only whether the task is successfully dispatched; this does not necessarily correspond to successful task execution.
While TaskDelegate is trivial in appearance, it is an important piece of our design In addition to explicitly stating the method(s) that delegates must support, it allows the interface to treat all task delegate objects as instances of type TaskDelegate, regardless of the underlying object type This allows our interface to rely on polymorphism for proper dispatch and simplifies the process of obtaining delegate instances via Java’s reflection facilities The net result is that our interface is capable of dispatching tasks in a straightforward manner without any knowledge of the task’s implementation, aside from the name of its delegate class.
Listing 12.5 The task delegate interface.
The Task Manager
Access to defined tasks begins with the task manager This is a graphical face that supports task selection and input of database connection parameters Figure 12.1 shows a task manager with four defined tasks Our task manager consists of two primary pieces The first, and more interesting of the two, is the
Trang 16inter-TaskPanel class shown in Listing 12.6 The second is the TaskManager class shown in Listing 12.7.
The TaskPanel class, with the help of its three inner classes, provides the bulk
of the task management interface The inner classes include ConnectionPane, TaskPane, and TaskHandler, which are responsible for connection parameter input, task selection, and task dispatch, respectively The ConnectionPane sim- ply provides for input of the information required by our ConnectionData class, namely a host name and port, a database name, and a username and password The TaskPane provides a set of buttons for task selection The number of but- tons, and the manner in which they are named, is based on the task list that is loaded when the application is launched; in other words, the buttons corre- spond to the enabled tasks specified in the configuration file The TaskHandler class is an ActionListener responsible for handling ActionEvents associated with the buttons on the TaskPane.
When a user clicks on a task button, the TaskHandler requests the tionData object associated with the ConnectionPane and attempts to build a connection with the specified database If it obtains a valid Connection object, it then requests the task list and iterates through the list looking for a TaskDefinition object with a name that matches that provided by the task but- ton If a matching TaskDefinition is located, reflection is used to obtain an instance of the corresponding delegate class The delegate object is then cast
Connec-to a TaskDelegate since that is known Connec-to be a least common denominaConnec-tor for all delegate classes Finally, the TaskDelegate execute() method is used to dispatch the task.
The second piece of our task manager, the TaskManager class, is the tion driver It parses the configuration file, builds the task list, and provides the main application frame and menu bar By default, it expects to find a configu- ration file named tasks.conf; however, an alternate configuration file may be provided via the command line.
applica-Figure 12.1 The task manager.
Trang 17The Task Manager 257
setLayout( new BorderLayout() );
connPane = new ConnectionPane();
connPane.setBorder( new TitledBorder( "Connection Data" ) );
taskPane = new TaskPane();
taskPane.setBorder( new TitledBorder( "Tasks" ) );
add( connPane, BorderLayout.NORTH );
add( taskPane, BorderLayout.SOUTH );
}
private Tasks taskList;
private ConnectionPane connPane;
private TaskPane taskPane;
class ConnectionPane extends JPanel
Trang 18new String( passwordField.getPassword() );
ConnectionData data = new ConnectionData(
hostNameField.getText(),dbNameField.getText(), portNumberField.getText(),usernameField.getText(), password );
return (data);
}
private JLabel hostNameLabel = new JLabel( "Host Name:" );private JLabel dbNameLabel= new JLabel( "Database Name:" );private JLabel portNumberLabel =
new JLabel( "Port Number:" );private JLabel usernameLabel = new JLabel( "Username:" );private JLabel passwordLabel = new JLabel( "Password:" );
private JTextField hostNameField = new JTextField( 20 );private JTextField dbNameField = new JTextField( 20 );private JTextField portNumberField =
new JTextField( "3306", 6 );private JTextField usernameField = new JTextField( 20 );private JPasswordField passwordField =
new JPasswordField( 20 );}
class TaskPane extends JPanel
{
TaskPane()
{
int taskCount = TaskPanel.this.taskList.getTaskCount();
int rows = ((taskCount % COLS) == 0)
? (taskCount / COLS): ((taskCount / COLS) + 1);
setLayout( new GridLayout( rows, COLS ) );
Listing 12.6 The task manager's TaskPanel component (continues)
Trang 19The Task Manager 259
taskButtons = new JButton[taskCount];
TaskHandler handler = new TaskHandler();
Enumeration tasks = taskList.getTasks();
String taskName = taskDef.getName();
taskButtons[task] = new JButton( taskName );
taskButtons[task].addActionListener( handler );
add( taskButtons[task++] );
}
}
private JButton[] taskButtons;
final static int COLS = 2;
ConnectionData connData = connPane.getConnectionData();
Connection conn = connData.buildConnection();
if ( conn == null )
{
String msg = "Could not build connection Check\n"
+ "provided connection data and verify\n"
Trang 20JOptionPane.ERROR_MESSAGE );
return;
}
String taskName = ae.getActionCommand();
Enumeration tasks = taskList.getTasks();
boolean dispatched = false;
Class delegateClass = taskDef.getDelegate();
Object delegateObject = delegateClass.newInstance();TaskDelegate delegate = (TaskDelegate)delegateObject;
dispatched = delegate.execute( conn );
if ( ! dispatched ){
String msg = "Could not execute task: "
+ taskDef.getName();
JOptionPane.showMessageDialog(
TaskPanel.this, msg,
"Task Failure",JOptionPane.ERROR_MESSAGE );
}}
catch( InstantiationException iX )
{
String msg = "Failed to instantiate "
+ "delegate for task: "
+ taskDef.getName();
Listing 12.6 The task manager's TaskPanel component (continues)
Trang 21The Task Manager 261
JOptionPane.showMessageDialog(
TaskPanel.this, msg,
"Task Failure",JOptionPane.ERROR_MESSAGE );
Trang 22public class TaskManager extends JFrame
frameContainer.setLayout( new BorderLayout() );
frameContainer.add( new TaskPanel( taskList ) );setContentPane( frameContainer );
addWindowListener( new WindowHandler() );
fileExit.addActionListener( new MenuHandler() );}
private JPanel frameContainer = new JPanel();
private JMenuBar menuBar = new JMenuBar();
private JMenu fileMenu = new JMenu( "File" );
private JMenuItem fileExit = new JMenuItem( "Exit" );
private Tasks taskList;
class WindowHandler extends WindowAdapter