home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-05-08 | 10.3 KB | 272 lines |
- /*
- * Copyright (c) 1997-1998 Borland International, Inc. All Rights Reserved.
- *
- * This SOURCE CODE FILE, which has been provided by Borland as part
- * of a Borland product for use ONLY by licensed users of the product,
- * includes CONFIDENTIAL and PROPRIETARY information of Borland.
- *
- * USE OF THIS SOFTWARE IS GOVERNED BY THE TERMS AND CONDITIONS
- * OF THE LICENSE STATEMENT AND LIMITED WARRANTY FURNISHED WITH
- * THE PRODUCT.
- *
- * IN PARTICULAR, YOU WILL INDEMNIFY AND HOLD BORLAND, ITS RELATED
- * COMPANIES AND ITS SUPPLIERS, HARMLESS FROM AND AGAINST ANY CLAIMS
- * OR LIABILITIES ARISING OUT OF THE USE, REPRODUCTION, OR DISTRIBUTION
- * OF YOUR PROGRAMS, INCLUDING ANY CLAIMS OR LIABILITIES ARISING OUT OF
- * OR RESULTING FROM THE USE, MODIFICATION, OR DISTRIBUTION OF PROGRAMS
- * OR FILES CREATED FROM, BASED ON, AND/OR DERIVED FROM THIS SOURCE
- * CODE FILE.
- */
-
- //Title: JBuilder Tutorial
- //Version: 2.0
- //Copyright: Copyright (c) 1998
- //Author: Jens Ole Lauridsen
- //Company: Borland Int'l
- //Description: Tutorial of Distributed Computing using RMI and DataSetData.
-
- package borland.samples.tutorial.dataset.datasetdata;
-
- import borland.sql.dataset.*;
- import borland.jbcl.dataset.*;
- import borland.jbcl.util.*;
- import borland.jbcl.control.*;
- import java.rmi.*;
- import java.net.InetAddress;
- import java.rmi.server.UnicastRemoteObject;
- import java.util.*;
-
- // The DataServerApp is a RMI server which is why it extends UnicastRemoteObject.
- //
- public class DataServerApp extends UnicastRemoteObject implements EmployeeApi {
- ResourceBundle res = Res.getBundle("borland.samples.tutorial.dataset.datasetdata.Res");
-
- // The constructor simply displays a frame
- //
- public DataServerApp() throws RemoteException {
- frame = new DataServerFrame(this);
- frame.pack();
- frame.setVisible(true);
- }
-
- // The method main will do some RMI magic and construct an instance variable
- //
- public static void main(String[] args) {
- System.setSecurityManager(new RMISecurityManager());
- DataServerApp dataServerApp = null;
- try {
- dataServerApp = new DataServerApp();
- dataServerApp.bindToNamingService();
- }
- catch (Exception ex) {
- DataSetException.handleException(ex, true);
- System.exit(1);
- }
- }
-
- // bindToNamingService
- // RMI requires the actual hostname (not "localhost") in the URL.
- // We handle the error case where another service has already
- // been registered to RMI with the name: "DataServerApp".
- //
- void bindToNamingService() throws Exception {
- InetAddress addr = InetAddress.getLocalHost();
- String localHost = addr.getHostName();
- serviceURL = "//" + localHost + "/DataServerApp";
- try {
- Naming.bind(serviceURL, this);
- frame.textControl2.setText(res.getString("RS_Hostname")+": "+localHost);
- }
- catch (java.rmi.AlreadyBoundException ex) {
- MessageDialog dlg = new MessageDialog(frame, res.getString("RS_Error"), res.getString("RS_AlreadyRegistered"), ButtonDialog.YES_NO);
- dlg.setVisible(true);
- if (dlg.getResult() == ButtonDialog.YES) {
- Naming.rebind(serviceURL, this);
- }
- }
- catch (java.rmi.ConnectException ex) {
- ExceptionChain chain = new ExceptionChain();
- chain.append(ex);
- throw new DataSetException(DataSetException.GENERIC_ERROR, res.getString("RS_NoRegistry"), chain);
- }
- }
-
- // closing
- // This method just unbinds the service from RMI.
- // Its called as a result of closing the frame from ClientFrame.java.
- //
- void closing() {
- try {
- Naming.unbind(serviceURL);
- }
- catch (Exception ex) {
- // Ignore all excewptions...
- }
- }
-
- // Constants for the database connection properties.
- // We will use InterBase via Visigenic ODBC on our local machine.
- // You could replace this with any other database connection.
- //
- final String url = "jdbc:odbc:dataset tutorial";
- final String driver = "sun.jdbc.odbc.JdbcOdbcDriver";
- final String username = "sysdba";
- final String password = "masterkey";
- final String queryText = "select * from employee";
-
- // provideEmployeeData
- // This is the implementation from the EmployeeApi interface.
- //
- // We simply run the query, extract the data into a DataSetData structure, and
- // pass this as a result in this remote method call.
- //
- // DataSetData will be serialized using java serialization. Allthough a
- // QueryDataSet is serializable, the data will not be transferred by passing
- // the queryDataSet as the result. That is because only the properties of the
- // QueryDataSet are serialized not the data.
- //
- // Also note: that any DataSetException will be passed in the remote method
- // call as well.
- //
- // Last note: This server could perform much better if the connection
- // was kept between the client requests.
- //
- public DataSetData provideEmployeeData() throws RemoteException, DataSetException {
- frame.incrementUsage();
- Database db = new Database();
- QueryDataSet qds = new QueryDataSet();
- try {
- db.setConnection(new ConnectionDescriptor(url, username, password, false, driver));
- qds.setQuery(new QueryDescriptor(db, queryText, null, true, Load.ALL));
- qds.open();
- DataSetData data = DataSetData.extractDataSet(qds);
- return data;
- }
- finally {
- qds.close();
- db.closeConnection();
- }
- }
-
- // resolveEmployeeChanges
- // This is the implementation from the EmployeeApi interface.
- //
- // First we run the query again. This time however we only want the
- // metadata, so we specify MaxRows to 0.
- // Next, we populate the QueryDataSet with the data that was passed 'changes'.
- // Then, the changes are saved back to the Interbase database.
- // Last, the errors are returned as another DataSetData instance.
- //
- // Errors are handled by the installed ResolverListener see the ResolverHelp
- // class below in this source file.
- //
- public DataSetData resolveEmployeeChanges(DataSetData changes) throws RemoteException, DataSetException {
- frame.incrementUsage();
- Database db = new Database();
- QueryDataSet qds = new QueryDataSet();
- QueryResolver qr = new QueryResolver();
- ResolverHelp rh = new ResolverHelp();
- try {
- db.setConnection(new ConnectionDescriptor(url, username, password, false, driver));
- qds.setQuery(new QueryDescriptor(db, queryText, null, true, Load.ALL));
- qr.setDatabase(db);
- qr.addResolverListener(rh);
- qds.setResolver(qr);
- qds.setMaxRows(0);
- qds.open();
- changes.loadDataSet(qds);
- qds.saveChanges();
- return rh.getErrors();
- }
- catch (java.util.TooManyListenersException ex) {
- throw new DataSetException(ex.getMessage());
- }
- finally {
- qds.close();
- db.closeConnection();
- }
- }
-
- private String serviceURL; // Keep the service URL for the closing method.
- private DataServerFrame frame; // Keep the frame around for various messages.
- }
-
- // Errors.
- // Errors are handled in the following way in this tutorial. Note that this is
- // not the only nor the best way to handle errors, but it might give some good
- // ideas for the 'ultimate' implementation.
- //
- // The Resolver (in resolveEmployeeChanges) is told to ignore all errors. That
- // implies that all changes which doesn't cause any problems will be saved and
- // committed to the database.
- // All the errors will be logged by this class (ResolverHelp) into a DataSet
- // and be passed back to the client application via DataSetData. The client
- // application can then decide how to show the errors.
-
- class ResolverHelp extends ResolverAdapter {
-
- // insertError
- // This is an implementation of a method in ResolverListener
- //
- public void insertError(DataSet dataSet, ReadWriteRow row, DataSetException ex, ErrorResponse response) throws DataSetException {
- handleError(dataSet, ex, response);
- }
-
- // deleteError
- // This is an implementation of a method in ResolverListener
- //
- public void deleteError(DataSet dataSet, ReadWriteRow row, DataSetException ex, ErrorResponse response) throws DataSetException {
- handleError(dataSet, ex, response);
- }
-
- // updateError
- // This is an implementation of a method in ResolverListener
- //
- public void updateError(DataSet dataSet, ReadWriteRow row, ReadRow oldRow, ReadWriteRow updRow, DataSetException ex, ErrorResponse response) throws DataSetException {
- handleError(dataSet, ex, response);
- }
-
- // getErrors
- // This method will return a DataSetData with the accumulated errors.
- //
- DataSetData getErrors() throws DataSetException {
- return errorDataSet == null ? null : DataSetData.extractDataSet(errorDataSet);
- }
-
- // handleError
- // This method will log an error into the errorDataSet.
- // For each error we log
- // 1) The internalRow of the row in the dataset inside the client
- // application, that caused the problem. That information is stored
- // by the DataSetData.extractDataSetChanges method.
- // 2) The exception object itself.
- //
- private void handleError(DataSet dataSet, DataSetException ex, ErrorResponse response) throws DataSetException {
- createErrorDataSet();
- errorDataSet.insertRow(false);
- errorDataSet.setLong(internalRow,dataSet.getLong(internalRow));
- errorDataSet.setObject(exception,ex);
- errorDataSet.post();
- response.ignore(); // Force the resolver to ignore the error, and continue.
- }
-
- // createErrorDataSet
- // This method will create a dataSet used to accumulate the errors.
- //
- private void createErrorDataSet() throws DataSetException {
- if (errorDataSet != null)
- return;
- errorDataSet = new TableDataSet();
- errorDataSet.setColumns(new Column[]{new Column(internalRow,internalRow,Variant.LONG),
- new Column(exception,exception,Variant.OBJECT),
- });
- errorDataSet.open();
- }
-
- TableDataSet errorDataSet;
- static final String internalRow = "INTERNALROW"; // This column is included in the DataSetData created by extractDataSetChanges.
- static final String exception = "EXCEPTION"; // This column is chosen as the error content.
- }
-
-
-