home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / TRIAL / JBUILDER / JSAMPLES.Z / DataServerApp.java < prev    next >
Encoding:
Java Source  |  1998-05-08  |  10.3 KB  |  272 lines

  1. /*
  2.  * Copyright (c) 1997-1998 Borland International, Inc. All Rights Reserved.
  3.  * 
  4.  * This SOURCE CODE FILE, which has been provided by Borland as part
  5.  * of a Borland product for use ONLY by licensed users of the product,
  6.  * includes CONFIDENTIAL and PROPRIETARY information of Borland.  
  7.  *
  8.  * USE OF THIS SOFTWARE IS GOVERNED BY THE TERMS AND CONDITIONS 
  9.  * OF THE LICENSE STATEMENT AND LIMITED WARRANTY FURNISHED WITH
  10.  * THE PRODUCT.
  11.  *
  12.  * IN PARTICULAR, YOU WILL INDEMNIFY AND HOLD BORLAND, ITS RELATED
  13.  * COMPANIES AND ITS SUPPLIERS, HARMLESS FROM AND AGAINST ANY CLAIMS
  14.  * OR LIABILITIES ARISING OUT OF THE USE, REPRODUCTION, OR DISTRIBUTION
  15.  * OF YOUR PROGRAMS, INCLUDING ANY CLAIMS OR LIABILITIES ARISING OUT OF
  16.  * OR RESULTING FROM THE USE, MODIFICATION, OR DISTRIBUTION OF PROGRAMS
  17.  * OR FILES CREATED FROM, BASED ON, AND/OR DERIVED FROM THIS SOURCE
  18.  * CODE FILE.
  19.  */
  20.  
  21. //Title:        JBuilder Tutorial
  22. //Version:      2.0
  23. //Copyright:    Copyright (c) 1998
  24. //Author:       Jens Ole Lauridsen
  25. //Company:      Borland Int'l
  26. //Description:  Tutorial of Distributed Computing using RMI and DataSetData.
  27.  
  28. package borland.samples.tutorial.dataset.datasetdata;
  29.  
  30. import borland.sql.dataset.*;
  31. import borland.jbcl.dataset.*;
  32. import borland.jbcl.util.*;
  33. import borland.jbcl.control.*;
  34. import java.rmi.*;          
  35. import java.net.InetAddress;
  36. import java.rmi.server.UnicastRemoteObject;
  37. import java.util.*;
  38.  
  39. // The DataServerApp is a RMI server which is why it extends UnicastRemoteObject.
  40. //
  41. public class DataServerApp extends UnicastRemoteObject implements EmployeeApi {
  42.   ResourceBundle res = Res.getBundle("borland.samples.tutorial.dataset.datasetdata.Res");
  43.  
  44.   // The constructor simply displays a frame
  45.   //
  46.   public DataServerApp() throws RemoteException {  
  47.     frame = new DataServerFrame(this);
  48.     frame.pack();
  49.     frame.setVisible(true);
  50.   }
  51.   
  52.   // The method main will do some RMI magic and construct an instance variable
  53.   //
  54.   public static void main(String[] args) {
  55.     System.setSecurityManager(new RMISecurityManager());
  56.     DataServerApp dataServerApp = null;
  57.     try {
  58.       dataServerApp = new DataServerApp();
  59.       dataServerApp.bindToNamingService();
  60.     }
  61.     catch (Exception ex) { 
  62.       DataSetException.handleException(ex, true);
  63.       System.exit(1);
  64.     }
  65.   }
  66.  
  67.   // bindToNamingService
  68.   // RMI requires the actual hostname (not "localhost") in the URL.
  69.   // We handle the error case where another service has already 
  70.   // been registered to RMI with the name: "DataServerApp".
  71.   //
  72.   void bindToNamingService() throws Exception {
  73.     InetAddress addr = InetAddress.getLocalHost();
  74.     String localHost = addr.getHostName();
  75.     serviceURL = "//" + localHost + "/DataServerApp";
  76.     try {
  77.       Naming.bind(serviceURL, this);
  78.       frame.textControl2.setText(res.getString("RS_Hostname")+": "+localHost);
  79.     }
  80.     catch (java.rmi.AlreadyBoundException ex) {
  81.       MessageDialog dlg = new MessageDialog(frame, res.getString("RS_Error"), res.getString("RS_AlreadyRegistered"), ButtonDialog.YES_NO);
  82.       dlg.setVisible(true);
  83.       if (dlg.getResult() == ButtonDialog.YES) {
  84.         Naming.rebind(serviceURL, this);
  85.       }
  86.     }
  87.     catch (java.rmi.ConnectException ex) {
  88.       ExceptionChain chain = new ExceptionChain();
  89.       chain.append(ex);
  90.       throw new DataSetException(DataSetException.GENERIC_ERROR, res.getString("RS_NoRegistry"), chain);
  91.     }
  92.   }
  93.  
  94.   // closing
  95.   // This method just unbinds the service from RMI.
  96.   // Its called as a result of closing the frame from ClientFrame.java.
  97.   //
  98.   void closing() {
  99.     try {
  100.       Naming.unbind(serviceURL);
  101.     }
  102.     catch (Exception ex) {
  103.       // Ignore all excewptions...
  104.     }
  105.   }
  106.   
  107.   // Constants for the database connection properties.
  108.   // We will use InterBase via Visigenic ODBC on our local machine.
  109.   // You could replace this with any other database connection.
  110.   //
  111.   final String  url         = "jdbc:odbc:dataset tutorial";
  112.   final String  driver      = "sun.jdbc.odbc.JdbcOdbcDriver";
  113.   final String  username    = "sysdba";
  114.   final String  password    = "masterkey";
  115.   final String  queryText   = "select * from employee";
  116.  
  117.   // provideEmployeeData
  118.   // This is the implementation from the EmployeeApi interface.
  119.   //
  120.   // We simply run the query, extract the data into a DataSetData structure, and
  121.   // pass this as a result in this remote method call.
  122.   //
  123.   // DataSetData will be serialized using java serialization. Allthough a
  124.   // QueryDataSet is serializable, the data will not be transferred by passing
  125.   // the queryDataSet as the result. That is because only the properties of the 
  126.   // QueryDataSet are serialized not the data.
  127.   //  
  128.   // Also note: that any DataSetException will be passed in the remote method
  129.   // call as well.
  130.   //
  131.   // Last note: This server could perform much better if the connection
  132.   // was kept between the client requests.
  133.   //
  134.   public DataSetData provideEmployeeData() throws RemoteException, DataSetException {
  135.     frame.incrementUsage();
  136.     Database     db   = new Database();
  137.     QueryDataSet qds  = new QueryDataSet();
  138.     try {
  139.       db.setConnection(new ConnectionDescriptor(url, username, password, false, driver));
  140.       qds.setQuery(new QueryDescriptor(db, queryText, null, true, Load.ALL));
  141.       qds.open();
  142.       DataSetData  data = DataSetData.extractDataSet(qds);
  143.       return data;
  144.     }
  145.     finally {
  146.       qds.close();
  147.       db.closeConnection();
  148.     }
  149.   }
  150.   
  151.   // resolveEmployeeChanges
  152.   // This is the implementation from the EmployeeApi interface.
  153.   //
  154.   // First we run the query again. This time however we only want the
  155.   // metadata, so we specify MaxRows to 0. 
  156.   // Next, we populate the QueryDataSet with the data that was passed 'changes'.
  157.   // Then, the changes are saved back to the Interbase database.
  158.   // Last, the errors are returned as another DataSetData instance.
  159.   //
  160.   // Errors are handled by the installed ResolverListener see the ResolverHelp
  161.   // class below in this source file.
  162.   //
  163.   public DataSetData resolveEmployeeChanges(DataSetData changes) throws RemoteException, DataSetException {
  164.     frame.incrementUsage();
  165.     Database      db   = new Database();
  166.     QueryDataSet  qds  = new QueryDataSet();
  167.     QueryResolver qr   = new QueryResolver();
  168.     ResolverHelp  rh   = new ResolverHelp();
  169.     try {
  170.       db.setConnection(new ConnectionDescriptor(url, username, password, false, driver));
  171.       qds.setQuery(new QueryDescriptor(db, queryText, null, true, Load.ALL));
  172.       qr.setDatabase(db);
  173.       qr.addResolverListener(rh);
  174.       qds.setResolver(qr);
  175.       qds.setMaxRows(0);
  176.       qds.open();
  177.       changes.loadDataSet(qds);
  178.       qds.saveChanges();
  179.       return rh.getErrors();
  180.     }
  181.     catch (java.util.TooManyListenersException ex) {
  182.       throw new DataSetException(ex.getMessage());
  183.     }
  184.     finally {
  185.       qds.close();
  186.       db.closeConnection();
  187.     }
  188.   }
  189.  
  190.   private String serviceURL;       // Keep the service URL for the closing method.
  191.   private DataServerFrame frame;   // Keep the frame around for various messages.
  192. }
  193.  
  194. // Errors.
  195. // Errors are handled in the following way in this tutorial. Note that this is
  196. // not the only nor the best way to handle errors, but it might give some good
  197. // ideas for the 'ultimate' implementation.
  198. //
  199. // The Resolver (in resolveEmployeeChanges) is told to ignore all errors. That
  200. // implies that all changes which doesn't cause any problems will be saved and
  201. // committed to the database.
  202. // All the errors will be logged by this class (ResolverHelp) into a DataSet
  203. // and be passed back to the client application via DataSetData. The client 
  204. // application can then decide how to show the errors.
  205.  
  206. class ResolverHelp extends ResolverAdapter {
  207.  
  208.   // insertError
  209.   // This is an implementation of a method in ResolverListener
  210.   //
  211.   public void insertError(DataSet dataSet, ReadWriteRow row, DataSetException ex, ErrorResponse response) throws DataSetException {
  212.     handleError(dataSet, ex, response);
  213.   }
  214.   
  215.   // deleteError
  216.   // This is an implementation of a method in ResolverListener
  217.   //
  218.   public void deleteError(DataSet dataSet, ReadWriteRow row, DataSetException ex, ErrorResponse response) throws  DataSetException {
  219.     handleError(dataSet, ex, response);
  220.   }
  221.   
  222.   // updateError
  223.   // This is an implementation of a method in ResolverListener
  224.   //
  225.   public void updateError(DataSet dataSet, ReadWriteRow row, ReadRow oldRow, ReadWriteRow updRow, DataSetException ex, ErrorResponse response)  throws DataSetException {
  226.     handleError(dataSet, ex, response);
  227.   }
  228.  
  229.   // getErrors
  230.   // This method will return a DataSetData with the accumulated errors.
  231.   //
  232.   DataSetData getErrors() throws DataSetException {
  233.     return errorDataSet == null ? null : DataSetData.extractDataSet(errorDataSet);
  234.   }
  235.  
  236.   // handleError
  237.   // This method will log an error into the errorDataSet.
  238.   // For each error we log 
  239.   //   1) The internalRow of the row in the dataset inside the client 
  240.   //      application, that caused the problem. That information is stored
  241.   //      by the DataSetData.extractDataSetChanges method.
  242.   //   2) The exception object itself.
  243.   //
  244.   private void handleError(DataSet dataSet, DataSetException ex, ErrorResponse response) throws DataSetException {
  245.     createErrorDataSet();
  246.     errorDataSet.insertRow(false);
  247.     errorDataSet.setLong(internalRow,dataSet.getLong(internalRow));
  248.     errorDataSet.setObject(exception,ex);
  249.     errorDataSet.post();     
  250.     response.ignore();   // Force the resolver to ignore the error, and continue.
  251.   }
  252.  
  253.   // createErrorDataSet
  254.   // This method will create a dataSet used to accumulate the errors.
  255.   //
  256.   private void createErrorDataSet() throws DataSetException {
  257.     if (errorDataSet != null)
  258.       return;
  259.     errorDataSet = new TableDataSet();
  260.     errorDataSet.setColumns(new Column[]{new Column(internalRow,internalRow,Variant.LONG), 
  261.                                          new Column(exception,exception,Variant.OBJECT),
  262.                                          });  
  263.     errorDataSet.open();
  264.   }
  265.  
  266.   TableDataSet errorDataSet;
  267.   static final String internalRow = "INTERNALROW";  // This column is included in the DataSetData created by extractDataSetChanges.
  268.   static final String exception   = "EXCEPTION";    // This column is chosen as the error content.
  269. }                      
  270.  
  271.  
  272.