Using Drools in Your Enterprise Java Application
Pages: 1, 2, 3, 4
Integrating the Rule Engine with the Database Layer
So far, our application has a web presentation layer and a rules engine for the business layer, but no means of getting data to and from a database. This section gives an example of how to do this. We base our example on the Data Access Object (DAO) pattern, where we encapsulate all code that "talks" to the database (or back-end data source) in one pluggable, configurable class. As such, the example is applicable to other persistence frameworks, such as Hibernate and Cayenne.
Some important points about the way we want to organize the data layer are:
- Only the business layer should talk to the data layer; if a class in the presentation layer (front end) wants some data, it should pass through the business layer first. This helps makes our code easier to organize and read.
- As far as possible, we should keep our data layer stateless--we should hold client data elsewhere (e.g., in the server session at the web front end, as per the previous example). This is distinct from caching of data, which we can do at this level. The difference between the two is state information is often user-specific, while data we cache at the data access layer is mainly sharable across the application. Organizing our layer in this way increases performance.
- We should allow the business logic to decide if data is needed or not--if not needed, the call to get the data should not be made.
To implement our simple Data Access Object, we create three new
objects: StockNameDao, DaoImplementation,
and DaoFactory.
StockNameDao is an interface that defines two
methods: getStockNames() returns a list of the stock
names that we deal with, and isOnStockList() checks
that a given stock is on the list of stocks that we deal with. Our
business layer will call these methods as and when it needs the
information.
DaoImplementation is an actual implementation of
StockNameDao. In this case the values are hard-coded,
but we could have queried a database or accessed an information
system like Bloomberg via a web service.
DaoFactory is what we use to create an appropriate
instance of StockNameDao. The advantage this approach
has over creating the class directly is that it allows us to
configure what DAO implementation we use at runtime (frameworks
like Spring are especially good at this). One factory can return
many types of DAOs (e.g., StockNameDao,
StockPriceDao, StockHistoryDao), which
means we can pass in our DaoFactory, and let the individual rules
decide on the data and DAOs that they require.
Here's what the StockNameDao interface looks
like:
/**
* Defines a Data Access Object - a non data
* source specific way of obtaining data.
*/
public interface StockNameDao {
/**
* Get a list of stock names for the application
* @return String[] array of stock names
*/
public String [] getStockNames();
/**
* Check if our stock is on the list
* @param stockName
* @return
*/
public boolean isOnStockList(String stockName);
}
And here's the DaoImplementation:
/**
* Concrete Definition of a Data Access Object
*/
public class DaoImplementation
implements StockNameDao {
/**
* Constructor with package level access only
* to encourage use of factory method
*
*/
DaoImplementation(){}
/**
* Get a list of stock names for the app.
* This is a hard coded sample
* normally we would get this from
* a database or other datasource.
* @return String[] array of stock names
*/
public String[] getStockNames() {
String[] stockNames=
{"XYZ","ABC","MEGACORP","SOMEOTHERCOMPANY"};
return stockNames;
}
/**
* Check if our stock is on the list
* @param stockName
* @return true / false as appropriate
*/
public boolean isOnStockList(String stockName){
//Get our list of stocks
String stockList[] = getStockNames();
//Loop and see if our stock is on it
// done this way for clarity . not speed!
for (int a=0; a<stockList.length;a++){
if(stockList[a].equals(stockName)){
return true;
}
}
//Default return value
return false;
}
}
The simple DaoFactory just returns a
DaoImplementation:
package net.firstpartners.rp;
/**
* Factory Method to get the Data Access Object.
* Normally we could replace this with a
* framework like Spring or Hibernate
*/
public class DaoFactory {
/**
* Get the stock name Dao
* This sample is hardcoded - in reality
* we would make this configurable / cache
* instances of the Dao as appropriate
* @return an instance of StockNameDao
*/
public static StockNameDao getStockDao(){
return new DaoImplementation();
}
}