I regret that this information was posted before it was finalized. I will continue research and repost in about a week or so.
My goal was to get input from five to ten people and come to a consensus for best practices (this should clear up some of the major disagreements and not waste a great deal of time within the group). There really isn't an architectural blueprint on the Struts site and the BluePrints on the Sun site do not apply specifically to Struts. I think a Struts BluePrint and clear reference implementation is needed. Mike --- Struts Newsgroup <[EMAIL PROTECTED]> wrote: > Subject: Re: Struts Architecture > From: Vic C <[EMAIL PROTECTED]> > === > I would call Pet Cemetery "Complexia very BAD Practices for > suckers". > This was designed to make your application need lots of HW and a > new Sun > server for each multiple of 50 users. See > http://www.softwarereality.com for 101 reasons why this is bad. > This is > not something that a production or operational system does, this > would > only work in a lab environment with lots of overhead. Companies > that do > this find Java expensive to develop and operate. > Java is just fine, blame your software engineer/architect who would > > think of picking this. The best solution is always low tech. > > This would be a good practice IMO: > 1. Dispatch a "new" parm to action. > 2. Action asks frmBean.new(); > 3. New in frmBean does DAO.new() to create a row that will hold a > new > row. (It might go to db to get MetaData). Also this same action > does all > CRUD, not just new. Same with DAO and frmBean, they do all the > CRUD, not > just new. (so action has new(); update(); delete(); save(); that > get > dispatched to it; as does the DAO, etc.) Look at my code. > 4. With the empty rowholder with matching meta data in scope, it > goes to > page. > 5. Use inputs some date, and submits a save. (Struts auto populates > setters) > 6. Action gets a "save" parm. > 6.a You call frmBean.validate(); and redirecte if any messages. > 7. Action asks frmBeansave(). > 8. Bean asks DAO to update. > 9. Update enumerates rows; and columns, construction an insert > statement. > > Anyway, I have taken above to production just fine. > > Simple MVC, not Complexia. Again new people over engineer. KISS is > much > more powerful and doable in Production. > I suggest you always unit test a bean to be able to insert to db, > before > placing it in Struts. Write a console app to insert into a bean. If > it > works in console app, it will work in Struts. Oddly, if it does not > work > in a console unit test; it will not work in Struts, and it is not > Struts > fault. Sun only makes money on J2EE license, and ... news flash, > sales > people lie, a lot. > My db sample does exactly above. > > Mike Duffy wrote: > > Vic, > > > > Please take a few moments to review the following, I would value > your > > opinion before I send it to the Struts user group. > > > > Thanks in advance for your time and insight. > > > > Mike > > > > > ##################################################################### > > 1. User enters information in an HTML form to create an account. > > > > 2. Struts Controller creates and populates a new AccountForm with > > user input. > > > > 3. Controller invokes AccountForm.validate() (assume validation > > passes). > > > > 4. Controller invokes AccountAction.perform(). > > > > 5. From within the method AccountAction.perform(), the form > argument > > is cast to an AccountForm object. > > > > 6. From within the method AccountAction.perform(), the method > > AccountForm.createAccount() is called to create an Account > object. > > > > The Account object is one of several "ComponentObjects" that > > represent the data model of the system and contain getters and > > setters for primitive values and other ComponentObjects (in this > > example the Account ComponentObject contains an "Address" > > ComponentObject and a "User" ComponentObject). The terms > > "ValueObject" and "DataTransferObject" have been used in this > thread, > > but they seem to have conflicting definitions and they seem to be > > used for transferring data across a network, not for > communicating > > between classes. If you examine the "PetStore" reference > > implementation you will see that the classes in the "Model" > > subpackages are named with common names (Category, Page, Item, > > Product). > > > > As a comment to my initial question that started this thread, the > > FormBean never leaves the Action object. The FormBean is > decomposed > > into one or more ComponentObjects that represent the data model > of > > the system. > > > > 7. From within the method AccountForm.getAccount() a utility > method > > in a mapping class could be called to perform the mapping. > > > > If you coordinate the property names between your FormBeans and > your > > ComponentObjects you can use a very handy method, > copyProperties(), > > in org.apache.commons.beanutils.PropertyUtils. In this case you > can > > probably do the mapping right in your AccountForm .getAccount() > > method. > > > > 8. From within the method AccountAction.perform() an instance of > > AccountDelegate is created. > > > > No business logic processing takes place in AccountAction; this > class > > is considered to be in the web layer. AccountDelegate is located > in > > the business logic layer. The AccountDelegate class does not do > any > > "heavy" business logic processing. This class simply helps > things > > along by coordinating the business logic functions at a central > > point. > > > > If you examine the "PetStore" reference implementation you will > see > > that these types of classes are called "Helper" classes (e.g., > > "AccountHelper"). I have also seen the term "Worker" used for > these > > types of classes. In my opinion, the term "Delegate" seems more > > appropriate because the action from AccountAction is delegated to > > AccountDelegate. > > > > 9. From within the method AccountAction.perform() the method > > AccountDelegate.createAccount(Account account) is called to > create an > > account in the data store. > > > > If "heavy weight" business logic processing was required the > method > > AccountDelegate.createAccount() might call worker methods in > other > > classes. For example, if income information was entered in the > > original HTML form a method in a UserWorker class could be called > to > > evaluate status based on income and zip code. This status value > > would then be set in the User object and eventually entered into > the > > data store. > > > > 10. From within the method AccountDelegate.createAccount() the > method > > AccountDAOImpl.getInstance() is called. > > > > AccountDAOImpl is a singleton which reduces the creation of > objects. > > The strings for the SQL prepared statements are declared as > "public > > static final". > > > > AccountDAOImpl implements the interface AccountDAO. This > interface > > allows for alternate possibilities in retrieving data. > > AccountDelegate will be able to use any object that implements > > AccountDAO. At some future time there might be an > AccountDAOSoapImpl > > or a AccountDAOFutureImpl. > > > > AccountDAOImpl and its helper classes completely encapsulate the > data > > access layer for CRUDing accounts (create, retrieve, update, and > > delete). The methods in AccountDAOImpl take ComponentObjects as > > arguments and return ComponentObjects or void. Connections and > > transactions are managed in the data access layer not the > business > > logic layer. The data access layer will have helper classes to > > manage connections and transactions (any system that has a > > significant number of transactions should probably use an EJB > > implementation). > > > > In essence, when a class in the business logic layer calls a > method > > in the data access layer, a ComponentObject is sent in and a > > ComponentObject is returned; the business logic layer does not > affect > > any functionality in the data access layer and the data access > layer > > does not affect any functionality in the business logic layer. > > FormBeans and ComponentObjects should not contain data access > calls > > to "create themselves"; they should be created by methods in the > data > > access layer. > > > > From the Java BluePrints website: > > > > "A clear separation of concern between access objects and > components > > will enable a component to be adapted to different enterprise > > information system resources. For example, a component can use an > > access object to adapt its persistent state management to a > different > > database schema or to a different type of database." > > > http://java.sun.com/blueprints/guidelines/designing_enterprise_applications/eis_tier/programming_access/index.html > > > > 11. From within the method AccountDelegate.createAccount() the > method > > AccountDAOImpl.createAccount(Account account) is called. > > > > 12. From within the method AccountDAOImpl.createAccount() a > method is > > called to get a connection from the connection pool. > > > > 13. From within the method AccountDAOImpl.createAccount() the > method > > Connection.setAutoCommit(false) is called (we do not want our > > transaction to commit unless every part of the transaction > succeeds). > > > > When updating multiple tables in the same transaction the updates > > must be done through the same connection. In this example, we > will > > assume three tables need to be updated: tblAccount, tblUser, and > > tblAddress. > > > > 14. From within the method AccountDAOImpl.createAccount() the > method > > account.getUser() is called (the Account object contains a User > > object). > > > > 15. From within the method AccountDAOImpl.createAccount() the > method > > UserDAOImpl.getInstance() is called. > > > > 16. From within the method AccountDAOImpl.createAccount() the > method > > UserDAOImpl.createUser(Connection connection, User user) is > called. > > > > Any exceptions that occur in UserDAOImpl.createUser() are thrown > to > > the calling method: AccountDAOImpl.createAccount(). If an > exception > > is caught by AccountDAOImpl.createAccount() the method > > connection.rollback() is called. > > > > The class UserDAOImpl may also have a method createUser(User > user) > > that independently gets a connection and creates a user. > > > > 17. From within the method AccountDAOImpl.createAccount() the > method > > account.getAddress() is called (the Account object contains a > Address > > object). > > > > 18. From within the method AccountDAOImpl.createAccount() the > method > > AddressDAOImpl.getInstance() is called. > > > > 19. From within the method AccountDAOImpl.createAccount() the > method > > AddressDAOImpl.createAddress(Connection connection, Address > address) > > is called. > > > > Any exceptions that occur in AddressDAOImpl.createAddress() are > > thrown to the calling method: AccountDAOImpl.createAccount(). If > an > > exception is caught by AccountDAOImpl.createAccount() the method > > connection.rollback() is called. > > > > The class AddressDAOImpl may also have a method > createAddress(Address > > address) that independently gets a connection and creates an > address. > > > > 20. If no exceptions are caught from the methods > > UserDAOImpl.createUser() or AddressDAOImpl.createAddress() the > method > > AccountDAOImpl.createAccount() creates an entry in tblAccount. > If no > > exception is generate when updating tblAccount the method > > connection.commit() is called and the connection is released in > the > > "Finally" block of AccountDAOImpl.createAccount(). If exceptions > > occur, the method connection.rollback() is called. > > > > When I catch an SQL exception, I usually wrap it as a RunTime > > exception and rethrow it. I'll have my error.jsp display an > > appropriate message. As a general rule, when the only thing you > are > > going to do is display a message there is no need to create a > > specific exception. > > > > 21. Assuming nothing has gone wrong, we are now back in our > > AccountAction.perform() method and Struts will redirect to the > > appropriate forward page. > > > > When necessary, objects that need to be placed in the session or > > request are placed from within the perform() method in the Action > > class, not by methods from classes in the business logic layer; > the > > business logic layer does not affect any functionality in the web > > presentation/management layer and the web presentation/management > > layer does not affect any functionality in the business logic > layer. > > > > The general idea is to keep the layers of an application > separate. > > > #################################################################### > > > > __________________________________________________ > > Do You Yahoo!? > > Yahoo! Health - your guide to health and wellness > > http://health.yahoo.com > > > > -- > To unsubscribe, e-mail: > <mailto:[EMAIL PROTECTED]> > For additional commands, e-mail: > <mailto:[EMAIL PROTECTED]> > __________________________________________________ Do You Yahoo!? Yahoo! Health - your guide to health and wellness http://health.yahoo.com -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

