Re: Keeping Actions clean - separating actions from business model from persistence

2003-10-11 Thread Ted Husted
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:


   
 
  
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

Re: Keeping Actions clean - separating actions from business model from persistence

2003-10-10 Thread Sasha Borodin
What I'm trying to grasp is where it it best for the business object <--->
dao interaction to take place.  OK, let's make an example, cause I'm having
trouble thinking abstractly tonight...

An online store customer selects several products, clicks "check out", which
calls a CheckOutAction.  From there:

1.  The CheckOutAction retrieves a Customer and a List of Product's from the
session; it creates an Order out of those components; it then calls
placeOrder(Order) on a Store business class.

2.  Store.placeOrder(Order) saves the Order to persistent storage; then uses
an Emailer business class to emailOrderConfirmation(Order).

--now the question:

1.  Which component is responsible for discovering the DaoManager,
retrieving the OrderDao from that manager, and telling the dao to save()?
Is it:
a. the Store.placeOrder() method?
-or-
b. the Order business object itself?

Is it the business entity object's responsibility to discover and use its
dao's, or that object's *user's* responsibility?

Matt, you seem to forgo business entity classes and create DAO's right in
your action, passing those to business "use case" classes...

Mahesh, your business "use case" components seem to be the ones responsible
for discovering the right DaoManager implementation, and retrieving the
needed DAO classes...

Anyone make the business entity classes themselves responsible for finding
and using their respective dao's (say, when an Order is issued a save()
command)?

Thanks for all your input!

-Sasha


On 10/10/03 20:25, "Sgarlata Matt" <[EMAIL PROTECTED]> wrote:

> I have a 4 tier architecture.
> 
> PRESENTATION TIER
> - Struts
> - Action classes
> 
> BUSINESS TIER
> - Business Objects
> 
> INTEGRATION & PERSISTENCE TIER
> - DAO Manager
> - DAOs
> - Other database access mechanisms (I do some JDBC using a fancy home-grown
> SQL building mechanism when dealing with particularly complex queries)
> 
> RESOURCE TIER
> - Databases


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



Re: Keeping Actions clean - separating actions from business model from persistence

2003-10-10 Thread Sasha Borodin
Matt, thanks for your quick feedback.

> I use my own framework because I don't know any better.
> 
> public abstract class DaoManager {
> public abstract IRecordDao createDao(Connection conn, String daoClassName)
> throws DaoException;

Which tier calls your DaoManager?  It seems from your code that the caller
of DaoManager is responsible to knowing the database configuration
information, as well as the implementing DAO class.  Is it the Action?

In other words, who orchestrates the interaction of business and dao
classes?  Does the action instantiate a business class and populate it from
your ActionForm, then get a dao instance from a factory, and pass it the
business class?  Or is there another pattern to this?

Thanks.

> Matt

-Sasha

> - Original Message -
> From: "Sasha Borodin" <[EMAIL PROTECTED]>
> To: "Struts Users Mailing List" <[EMAIL PROTECTED]>
> Sent: Friday, October 10, 2003 6:44 PM
> Subject: Keeping Actions clean - separating actions from business modelfrom
> persistence
> 
> 
>> 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]
>> 
> 
> 
> -
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]


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



Keeping Actions clean - separating actions from business model from persistence

2003-10-10 Thread Sasha Borodin
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]