First, I'd suggest studying the JPetstore3 application.

http://www.ibatis.com/jpetstore/jpetstore.html

It demonstrates a clean separate of concerns between the logical layers of an application.

It also uses a DAO framework and shows how you can you easily switch between data persistence implementations. JP3 shows switching between a "simple" (JDBC) and "remote" (EJB) implementations, but you could also be switching between a memory-based model (like the Struts Mailreader Example) and OJB, or anything else. Quite neat.

In my own current work, I use iBATIS DAO to switch between memory-based persistence (a hashmap) and a JBDC database. It works quite well, all I do is change a comment in a properties file.

I'm using Commons Chain

http://cvs.apache.org/viewcvs/jakarta-commons-sandbox/chain/

to manage access to the business logic. The controller action calls a Command/Chain from the catalog using a logical name. I use the form name and the Command name, since the form name is also tied to validation, and validation is tied to what Command you are going to call. So the same token is used for all three constructs (Form, Validation, Command).

Often, the Command is just a wrapper around a call to the DAO. Here's one for selecting a record by an id number:

public boolean execute(Context context) throws Exception {

CpuPermitDao dao = DaoConfig.getInstance().getCpuPermitDao();

CpuPermitContext ctx = dao.findByPermitNo(((CpuPermitContext) context).getPermitNo1());

if (null == ctx) return false; // couldn't find it

    context.putAll(ctx);
    return true;

}

The first line is the DAO discovery bit. DaoConfig is a singleton that uses a XML configuration to instantiate itself. Here's the bit that selects the DAO implementation:

    <dao-factory>
       <dao name="CpuPermitDao" implementation="${cpu-permit.impl}" />
         <!-- other factories here -->
      </dao-factory>

The XML configuration in turn can read in properties from a file, which is where the ${cpu-permit.impl} comes from them. This makes it quite easy to switch between implementations just by changing one line a properties file.

The DAO class, "findByPermitNo" is responsible for fulfilling the "findByPermitNo":

public CpuPermitContext findByPermitNo(String permitNo) throws DaoException {

return find(Tokens.CN_PERMIT_NO, permitNo, true);

}

Here, it just calls a more generic member of the DAO class, filling in the attribute name for permitNo. The find method does the actually persistence work:

public CpuPermitContext find(String column, String equals, boolean sensitive) throws DaoException {

return (CpuPermitContext) executeQueryForObject(Tokens.CPU_PERMIT_SELECT_COLUMN, select(column, equals));

}

The "executeQueryForObject" method is where the rubber meets the road. This is a call to the iBATIs SqlMaps framework. It looks up the SQL query for CPU_PERMIT_SELECT_COLUMN, and fills in the replacement parameters using the value of the column parameter.

In the Mock implementation, I can reuse the findByPermitNo method and just replace the find method:

public CpuPermitContext find(String property, String equals, boolean sensitive) {

        List list = search(property, equals, sensitive);
        if (0 == list.size()) return null;
        return (CpuPermitContext) list.get(0);
    }

public search(String property, String equals, boolean sensitive) {

        MockDatabase db = MockDatabase.getInstance();
        Iterator i = db.keySet().iterator();
        String match = Utils.conform(equals, sensitive);
        List list = new ArrayList();

while (i.hasNext()) {
CpuPermitContext ctx = (CpuPermitContext) db.get(i.next());
if (match.equals(Utils.conform(ctx.get(property), sensitive))) list.add(ctx);
}


        return list;
    }

The key is to create a sensible, high-level API for your application, like this:

public interface CpuPermitDao extends Dao {

public CpuPermitContext findByPermitNo(String permitNo) throws DaoException;

public CpuPermitContext findBySystemId(String systemId) throws DaoException;

void insert(CpuPermitContext context) throws DaoException;

public List listApplicants() throws DaoException;

public List listByApplicantName(String applicantName) throws DaoException;

public List listPermitNo() throws DaoException;

void update(CpuPermitContext context) throws DaoException;

}

that you can instantiate for different persistance strategies. If some methods can be reused between strategies, you can isolate those in a base class. Each strategy can then implement whatever abstract methods are left.

Essentially, this API interface *is* your application. The Actions are just adapters that ferry data between HTTP and your business layer. We're calling them DAOs, since that's the most common use. But, they are really API objects that may also access the persistence layer. Don't think of it as just DAO, think of it as API with DAO.

The current Struts MailReader example also demonstrates this same DAO pattern, but without a formal framework. Makes for a nice comparison.

Without something like Commons Chain, you end up having to make a few API calls from within your Action. The Command code shown would either be in a little class of it's own (e.g. ProcessBean) or embedded in the Action.

The neat part about Chain, is it gives us a place to put that stuff where it can be accessed by a logical name. This severely limits the coupling between your Actions and the business layer.

I'm in the middle of an iteration that uses Chain and iBATIS DAO in a working application. Once that's done, I'll start abstracting things into a toolkit, like the Scaffold stuff.

HTH, Ted.


Sasha Borodin wrote:
Ted, Matt, Joe, and all the other helpful folks that chimed in earlier on
persistence mechanisms:

In trying to keep with best practices, I've managed to remove all "model"
related code (business logic, and persistence) out of the Actions' execute()
method.  Now I'd like to take it one step further and decouple the business
model classes from the implementing persistence technology (btw, settled on
OJB for now :).  From Joe's post, it seems like the DAO pattern is called
for to accomplish this.

My (slightly off topic) question is this:  who develops their own DAO
framework (like the dao and dao factory interfaces), and who uses a 3rd
party framework (like iBATIS's Database Layer) and why?  There was something
mentioned about the discovery of the persistence mechanism as well...

Any references to webpages/books would be appreciated.

BTW, I've been shamelessly posting to this list questions that are probably
better directed elsewhere.  What would be a more appropriate list?

Thank you,

-Sasha


--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]



-- Ted Husted, Junit in Action - <http://www.manning.com/massol/>, Struts in Action - <http://husted.com/struts/book.html>, JSP Site Design - <http://www.amazon.com/exec/obidos/ISBN=1861005512>.




--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to