Database application development is a feature of JBuilder Professional and Enterprise. Distributed application development is a feature of JBuilder Enterprise.
The DataSetData.jpr sample project in the /samples/DataExpress/StreamableDataSets directory of your JBuilder installation
contains a completed distributed database application using Java Remote Method Invocation (RMI) and DataSetData
. It includes a server application that will take data from the sample JDataStore employee table and send the data via RMI in the form of DataSetData
. A DataSetData
is used to pass data as an argument to an RMI method or as an input stream to a Java servlet.
A client application will communicate with the server through a custom Provider and a custom Resolver. The client application displays the data in a table.
Editing performed on the client can be saved using a JdbNavToolBar
's Save button.
For more information on developing distributed applications, see the Distributed Application Developer's Guide.
For more information on writing custom providers, see "Writing a custom data provider". For information on writing or customizing a resolver, see "Customizing the default resolver logic".
See the file DataSetData.html
in the /samples/DataExpress/StreamableDataSets/
directory for updated information on this sample application.
/samples/DataExpress/StreamableDataSets/DataSetData.jpr
, demonstrates the use of the DataExpress DataSetData
class to build a distributed database application. In addition to using DataSetData
objects to pass database data between an RMI server and client, this sample illustrates the use of a custom DataSet
Provider
and Resolver
. The sample application contains the following files:
EmployeeApi.java
is an interface that defines the methods we want to remote.
Server files
DataServerApp.java
is an RMI server. It extends UnicastRemoteObject
.
Provider files
ClientProvider.java
is an implementation of a Provider. The provideData
method is an implementation of a method in com.borland.dx.dataset.Provider
. We look up the "DataServerApp" service on the host specified by the hostName
property, then make the remote method call and load our DataSet
with the contents.
Resolver files
ClientResolver.java
is an implementation of a Resolver. The resolveData
method is an implementation of com.borland.dx.dataset.Resolver
. First, we look up the "DataServerApp" service on the host specified by the hostName
property. Then, we extract the changes into a DataSetData
instance. Next, we make the remote method call, handle any resolution errors, and change the status bits for all changed rows to be resolved.
Client files
ClientApp.java
is an RMI client application. See ClientFrame.java
for details.
Other files
Res.java
is a resource file for internationalizing the application.
ClientFrame.java
is the frame of ClientApp
. Notice that the DataSet
displayed in the table is a TableDataSet
with a custom provider and a custom resolver. See ClientProvider.java
and ClientResolver.java
for details.
DataServerFrame.java
is the frame displayed by DataServerApp
.
Select Project|Project Properties to view the properties of this project. Set the following options;
DataServerApp
in the project pane. Right-click the file, and select Run to start the RMI server.
ClientApp
in the project pane. Right-click the file, and select Run to start the RMI client.
These steps enable the DataServerApp
to register itself as an RMI server.
DataServerApp
will respond to two RMI client requests: provideEmployeeData
and resolveEmployeeChanges
,
as defined in the RMI remote interface EmployeeApi.java
.
The ClientApp
file is a frame with a JdbTable
and a JdbNavToolBar
for displaying data in a DataExpress DataSet
. Data is provided to the DataSet
via a custom Provider, ClientProvider.java
, and data is saved to the source via a custom Resolver, ClientResolver.java
. ClientProvider.java
fills its table data by invoking the DataServerApp
provideEmployeeData()
remote method via RMI.
DataServerApp
subsequently queries data from a table on a JDBC database server into a DataSet
. It then
extracts the data from the DataSet
into a DataSetData
object and sends it back to ClientProvider
via RMI.
ClientProvider then loads the data in the DataSetData
object into the ClientApp
DataSet
, and the data appears in the table.
When it is time to resolve changes made in the table back to the database, the ClientApp
DataSet
"custom Resolver", ClientResolver.java
, extracts (only) the changes that need to be sent to the database server into a DataSetData
object. ClientResolver
then invokes the DataServerApp
resolveEmployeeChanges()
remote method via RMI, passing it the
DataSetData
object containing the necessary updates as the parameter.
DataServerApp
then uses DataExpress
to resolves the changes back to the database server. If an error occurs (due to a business rule or data constraint violation, for example) DataServerApp
packages rows which could not be saved back to the database into a
DataSetData
object and returns it back to ClientResolver
. ClientResolver
then extracts the unresolvable rows in the DataSetData
object
into the ClientApp
table, allowing the problematic rows to be corrected and resolved back to the server again.
Note that DataServerApp
is the "middle-tier" of the application. It can enforce its own business rules and constraints between the database server and the client. And of course, it could provide any number of additional remotely accessibly methods for implementing business logic or application-specific tasks.
DataSetData
object is very limited.
Only the following Column
properties are passed:
columnName
dataType
precision
scale
hidden
rowId
Other column properties that a server needs to pass to a client
application, should be passed as an array of Columns
via RMI. The Column
object itself is serializable, so a client application could be designed to get
these column properties before it needed the data. The columns should be
added as persistent columns before the DataSetData
is loaded.
DataServerApp.java
in the project pane. Modify the database connection URL in the constructor to point to a remote database connection to which you have access. The database is the back end, or third tier.
DataServerApp
.class.
Deploy DataServerApp.class
to a remote machine to which you are connected. DataServerApp runs on the middle, or second, tier.
Start the RMI Registry on the middle tier computer.
Start DataServerApp on the middle tier.
java.security.policy
, passed by way of a command-line argument to the VM of the server.
This is similar to the java.rmi.server.codebase
property which must also be passed to the server's VM.A sample RMI security policy file which will allow an RMI client to connect to the server is included
with this project in the file SampleRMI.policy
.
When starting DataServerApp
on the middle-tier, make sure both the java.security.policy
and java.rmi.server.codebase
properties are set to the proper locations on the middle-tier machine.
Double-click ClientFrame.java
in the project pane of JBuilder to bring it into the content pane. Select the Design tab to invoke the designer. Select clientProvider1
in the component tree and modify the hostName
property to
the hostname of the middle-tier machine.
Select clientResolver1
and modify the hostName
property to
the hostname of the middle-tier machine.
Select Project|Make Project to rebuild ClientApp.
Start ClientApp on the client, or first tier, by right-clicking on the ClientApp.java file in the project pane and selecting Run.
http://www.java.sun.com/products/jdk/1.2/docs/guide/rmi/index.html
.
Learn more about writing custom Providers and Resolvers by viewing the sample data set application /samples/DataExpress/CustomProviderResolver/CustomProviderResolver.jpr.
Learn more about creating distributed applications in the Distributed Applications Developer's Guide.