However, I can't get the action to trigger when I go to the form initially.
I am a bit lost on this one even though I'm trying to understand these
tutorials.
One of the solutions I've implemented is to create an intermediate action that loads data from a database, populates de ActionForm, and directs the user to the apropiate JSP.
One way to achive almost "automagically" ActionForm population (and to obtain DTO's from ActionForm data) is through Jakarta Commons Beanutils. I'm supposed to add a mini-how-to to Commons Wiki but day-time job keeps me busy even @ night :^P So here's an extract:
"* Since I'm using Struts in my current J2EE project one of my concerns was to find a way to transfer data between the presentation layer and the data layer. From the Struts part I have ActionForms and from the data persistence part I have Value Objects and CMP Entity Beans.
* According to Ted Husted's "Struts in Action" (2003, Manning) there are several strategies to transfer values between tiers. I was using one that relies on "factory methods" ("A helper method encapsulates, instantiates, and populates a business tier bean."), but including such methods in my ActionForms to instantiate, populate, and return a specific value object brought along (at least to me) messy code to handle data type conversions and validations, moreover, as Ted points it "This strategy binds the ActionForm to the business-tier type". Of course there are advantages to this approach, but the use of reflection -as I hope you'll see- is a cleaner and safer path, and introduces very little overhead.
* For the sake of simplicity in my ActionForms I only have string properties -even though users "see" and save String, Date, Integer, Boolean, Timestamp, and Float values. Considering that the BeanUtils methods can convert data between Strings and native types this seemed like a good decision. If you have "exotic" data types,s you'll have to implement "bridge methods" to keep data type conversion transparent (I'll show a rather simple example later)
Having described some of my scenario, here's what I did:
1. Following commons-beanutils JavaDocs' two-step recipe, I wrote a class that implemented the Converter interface. Within this class the convert() method should accept theclass that you want to convert to, and a String representing the incoming value to be converted. I had to go through this first step because from the user perspective dates are handled in dd-mm-yyyy format but they go into the database as an SQL DATE value, using yyyy-mm-dd format. To implement the Converter interface I kind of cheated because I grabbed commons-beanutils source code and peek into the default SqlDateConverter class code (written by Mr. Craig R. McClanahan) What I did next was re-implement the convert() method to add code within the try to "reverse" the date format, like this:
int year,month,day; String userDate = (String) value;
year = Integer.parseInt(userDate.substring(6)); month = Integer.parseInt(userDate.substring(3,5)); day = Integer.parseInt(userDate.substring(0,2));
GregorianCalendar dbDate = new GregorianCalendar(year, month-1, day);
Date correctDate = new Date(dbDate.getTimeInMillis());
return (correctDate);
NOTE: there are default converters that use Locale objects, if you need something more refined (you can "load" them during App startup an define -depending on the constructor you use- the default values to be returned)
2. The next step in the recipe is to "register an instance of your converter class by calling the ConvertUtils.register() method". It is suggested that this be done at application startup time, and since I already had a ServletContext Listener I just added the following lines in the contextInitialized method:
appContext.log("Registering MyOwnSqlDateConverter..."); ConvertUtils.register(new MyOwnSqlDateConverter(),java.sql.Date.class); appContext.log("MyOwnSqlDateConverter registered...");
As you can imagine, for every String to java.sql.Date conversion that takes place in the application the converter to use will be the one I'm providing in step 1 and registering in step 2.
3. Finally, to populate ActionForms and create Value Objects you should add some simple methods:
public void populateFormFromValueObjectData(Object vo) throws Exception { try { BeanUtils.copyProperties(this, vo); } catch (Throwable t) { throw new PopulateSolicitudDataException(t); } }
and
public SomeValueObject getSomeValueObjectFromFormData() throws Exception { SomeValueObject svo = new SomeValueObject();
try { BeanUtils.copyProperties(svo, this); } catch (Throwable t) { throw new PopulateSolicitudVOException(t); }
return svo; }
In both cases, "this" references the ActionForm. In the first method, BeanUtils.copyProperties(this, vo) copy property values from the origin bean (vo) to the destination bean (this=ActionForm) for all cases where the property names are the same, doing all the necessary data type conversions under the hood; and the same applies for BeanUtils.copyProperties(svo, this).
Doing things this ways allows you to transfer data between tiers without binding your form to the business tier, in fact, you don't even have to know the details of the data transfer objects (value objects) to get data from them and send data through them. Mr. Husted refers to this kind of felxibility as "round-tripping ActionForms and business beans".
One of my actual ActionForms has to gather a lot of data (or is it datum? sorry, not very good in english grammar) using wizard like screens, but this information doesn't go to the same places in the database. I create three different types of Value Objects and obtain information from those three types with just a few lines of code and without caring about any data type conversions. This is one step closer to heaven for me! :^)
I hope this serves you as a good and practical introduction to part of the commons-beanutils power ;^) If any questions arise or you come up with better examples and/or corrections, please share them!"
Regards and good luck!
Carlos
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]