Separating database access logic and business rules from the user interface
Data modules simplify data access development in your applications. Data modules offer you a centralized design-time container for all your data access components. This enables you to modularize your code and separate the database access logic and business rules in your applications from the user interface logic in the application.
You can also maintain control over the use of the data module by delivering only the .class files to application developers.
A data module is a specialized container for data access components. Once you define your DataSet components and their corresponding Column components in a data module, all frames that use the module have consistent access to the data sets and columns without requiring you to recreate them on every frame each time you need them. Data modules do not need to reside in the same directory or package as your project. They can be stored in a location for shared use among developers and applications.
The DataModule is an interface which declares the basic behavior of a data module. To work with this interface programmatically, implement it in your data module class and extend it by adding your data components.
When you create a data module and add any component that would automatically appear under the Data Access section of the Component tree (Database, DataSet, DataStore), a getter is created. This means that any of these components will be available in a choice list for the project that references the data module. This means, for example, that you can
- Add a Database component to a data module.
- Compile the data module.
- Add a QueryDataSet component to the application that contains the data module or to the data module itself.
- In the query property dialog, select "DataModule1.database1" (or something similar) from the Database choice box.
Creating a data module
To create a data module,
- Select File|Close All to close any existing project (unless you want to add the data module to an existing project. In that case, skip this step).
- Create a new project by selecting File|New Project. The Project Wizard displays.
- Select the Browse button. You can create a data module in a separate project and once defined, refer to the data module class in your application. You can also create a data module in the same project as your application.
- Choose a location and a name for the project. Choose Save.
- Select File|New and double-click the Data Module icon.
- Specify the package and class name for your data module class. JBuilder automatically fills in the Java file name and path based on your input.
- Click the OK button to close the dialog. The data module class is created and added to the project.
You'll notice that the code generated by the wizard for the data module class is slightly different than the code generated by other wizards. The getDataModule() method is defined as public static. The purpose of this method is to allow a single instance of this data module to be shared by multiple frames. The code generated for this method is:
public static DataModule1 getDataModule() {
if (myDM == null)
myDM = new DataModule1();
return myDM;
}
The code for this method
- Declares this method as static. This means that you are able to call this method without a current instantiation of a DataModule class object.
- Returns an instance of the DataModule class.
- Checks to see if there is a current instantiation of a DataModule.
- Creates and returns a new DataModule if one doesn't already exist.
- Returns a DataModule object if one has been instantiated.
The data module class now contains all the necessary methods for your custom data module class, and a method stub for the jbInit() to which you add your data components and custom business logic.
Adding data components to the data module
To customize your data module using the UI Designer,
- Select the data module file in the Navigation pane.
- Select the Design tab of the Content pane to activate the UI Designer.
- Add your data components to your data module class. For example,
- Select a Database component from the Data Express tab of the Component palette.
- Click in the Component tree to add the Database component to the DataModule.
- In the Inspector, set the connection property (via the database connectionDescriptor).
The data components are added to a data module just as they are added to a Frame file. For more information on adding data components, see Accessing data.
Note: JBuilder automatically creates the code for a public method that "gets" each DataSet component you place in the data module. This allows the DataSet components to appear as (read-only) properties of the DataModule. This also allows DataSet components to be visible to the dataSet property of data-aware components in the Inspector when data-aware component and data modules are used in the same container.
After you have completed this section and the next, your data module file will look like this:
package untitled7;
import java.awt.*;
import java.awt.event.*;
import borland.jbcl.layout.*;
import borland.jbcl.control.*;
import borland.jbcl.dataset.*;
import borland.sql.dataset.*;
import java.lang.*;
public class DataModule1 implements DataModule{
private static DataModule1 myDM;
Database database1 = new Database();
QueryDataSet queryDataSet1 = new QueryDataSet();
public DataModule1() {
try {
jbInit();
}
catch (Exception e) {
e.printStackTrace();
}
}
private void jbInit() throws Exception{
database1.setConnection(new borland.sql.dataset.ConnectionDescriptor("jdbc:odbc:dataset tutorial",
"SYSDBA", "masterkey", false, "sun.jdbc.odbc.JdbcOdbcDriver"));
queryDataSet1.setQuery(new borland.sql.dataset.QueryDescriptor(database1,
"select FIRST_NAME, PHONE_EXT from employee", null, true, Load.ALL));
queryDataSet1.addEditListener(new borland.jbcl.dataset.EditAdapter() {
public void deleting(DataSet dataSet) throws Exception{
queryDataSet1_deleting(dataSet);
}
);
}
public static DataModule1 getDataModule() {
if (myDM == null)
myDM = new DataModule1();
return myDM;
}
public borland.sql.dataset.QueryDataSet getQueryDataSet1() {
return queryDataSet1;
}
void queryDataSet1_deleting(DataSet dataSet) throws Exception{
//for example, business logic goes here
}
}
Adding business logic to the data module
Once the data components are added to the data module and corresponding properties set, you can add your custom business logic to the data model. For example, you may want to give some users the rights to delete records and others do not have these rights. To enforce this logic, you add code to various events of the DataSet components in the data module.
Note: The property settings and business logic code you add to the components in the data model cannot be overridden in the application that uses the data model. If you have behavior that you do not want to enforce across all applications that use this data model, consider creating multiple data models that are appropriate for groups of applications or users.
To add code to the events of a component,
- Select the data module file in the Navigation pane.
- Select the Design tab of the Content pane to activate the UI Designer.
- Select the component in the Component tree to which you want to add business logic.
- Select the Events page in the Inspector.
- Double-click the event where you want the business logic to reside. JBuilder creates a stub in the .java source file for you to add your custom business logic code.
Using a data module
To use a data module in your application, it must first be saved and compiled. In your data module,
- Select File|Save All. Note the name of the project and the data module.
- Compile the data module class by selecting Run|Run. This creates the data module class files in the directory specified in File|Project Properties, Output Root Directory.
- Select File|Close All.
To reference the data module in your application,
- Select File|New Application. Accept all defaults. (Optionally, open an existing project using File|Open/Create)
- Select the application's Frame file.
- Import the package that the data module class belongs to (if it is outside your package) by selecting Wizards|Use Data Module.
- Click the Browse For Class button to open the Package Browser. A tree of all known packages and classes is displayed. Browse to the location of the class files generated when the data module was saved and compiled. Select the data module class. If you do not see the data module class here, check to make sure the the project compiled without errors.
- Click OK.
Click the Design tab to open the UI Designer; the instance of the data module appears in the Component Tree. Clicking the entry for the data module does not display its DataSet components nor its Column components. This is intentional to avoid modification of the business logic contained in the data module from outside.
When designing your application, you'll notice that the dataSet property of a UI Control includes all the DataSetView and StorageDataSet components that are included in your data module. You have access to them even though they are not listed separately in the Component Tree.
If you have a complex data model and/or business logic that you don't want another developer or user to manipulate, encapsulating it in a reusable component is an ideal way to provide access to the data but still enforce and control the business logic.
Understanding the Use Data Module dialog
When you select Wizards|Use Data Module, you will see the following dialog:
- You can select a data module in two ways:
- Select a data module from the drop-down list of data modules currently associated with the current project.
- Click the Browse for Class button to open the Package Browser. A tree of all known packages and classes is displayed. If you do not see your DataModule class in this list, use File|Project Properties to add the package or archive to your libraries. Browse to the location of the class files generated when the data module was saved and compiled. Select the data module class.
- In the Java Field Declaration box, the default field name is the name of the data module, followed by a "1". It is the name which will be used for the member variable to generate in code. The data module will be referred to by the name given here in the Structure pane and in the Component tree. Select a name that describes the data in the data module.
- You can choose to Create New Instance Of DataModule or Share (Static) Instance of DataModule. If you plan to reference the data module in multiple frames of your application, and want to share a single instance of the custom DataModule class, select Share (Static) Instance of Data Module. If you only have a single Frame subclass in your application, select Create New Instance Of DataModule.
- Click OK to add the data module to the package and inject the appropriate code into the current source file to create an instance of the data module.
Based on the choices shown in the dialog above, the following code will be added to the jbInit() method of the Frame file. Note that Share (Static) Instance of Data Module is selected:
employeeDataModule = untitled1.DataModule1.getDataModule();
If Create New Instance Of DataModule is selected, the following code will be added to the jbInit() method of the Frame file:
employeeDataModule = untitled1.DataModule1();