Wednesday, September 24, 2003

Man, it's been a long time since I've updated this. I am still alive, I just haven't had any interesting work related comments to share.

Struts continues to be both helpful and frustrating. I've tweaked my design pattern for form pages now. I still have two action mappings, initEditForm.do and editForm.do . The change I had to make was to the "input" attribute of the editForm.do action. Whereas I used to have it the same as the initEditForm action, I now have created a new dispatch, "error" which does all the same initialization that the "init/unspecified" action does without setting any values in the form bean. I had to make this change because I was setting values in the init action so that the form would be prepopulated with the values to be edited. However, if validation failed when the form was submitted, I was clobbering the user's input by repopulating the form. The "input" still needs to point to the initEditForm action because if we set it to the editForm action, we'd end up in an endless loop where the request would be validated, fail, be sent to editForm, where it would be validated, fail, be sent to editForm....



Friday, August 15, 2003

I have a love-hate relationship with confessional debugging. You know, when you go to someone else for help and, in the process of explaining your problem, find the solution yourself. I love it because it solves the problem, and I hate it because I always feel slightly embarassed in front of the other person. I've found a bit of a compromise though: mailing lists, specifically those related to the problem I'm trying to solve. I don't know how many times the act of writing the details of my problem down in my request for help has forced me to see the problem in a different light and craft a solution. I generally decide to reexamine my problem more thoroughly when I remember that the person "on the other end of the line" is going to scrutinize not only my problem, but the efforts I went to to solve it before I came to them.

Wednesday, August 13, 2003

More quickies:

- A few times now I have struggled with the JSTL tags complaining that they can't find a property I'm trying to access in my Struts ActionForm. The <html:> tags find the property with no trouble, so I know it's there. The key was that I was using a DynaForm, where the properties are dynamically defined in the struts-config.xml file, and I had forgotten the ".map." that you need to access properties via JSTL. E.g.:

<c:out value="${myDynaForm.map.myProperty}" >

If you leave out the .map., you'll get an exception complaining that there is "No such property in bean com.foo.MyDynaForm".


- The second thing I learned, was not to forget the scope attribute on your Struts action mappings. I had two action mappings, an initMyAction and myAction, both of which used the same form. I was submitting some initial values to the init form, but they weren't showing up in the JSP that the init form redirected to. And I could see in the debug logs that the <html:form> was causing a new instance of my form bean to be instatiated, when it should have already existed. I put debugging statements in the Action execute() method and I could see the value there, so I knew it was getting set. The problem was that I had left out the scope="request" from the <action> mapping for the initAction, but not from the myAction. So myAction was looking for the bean in the request scope and not finding it. (I'm assuming the default value for scope is "session").

Thursday, August 07, 2003

Just a quickie. I just learned that when you use a <html:password> tag, unless you set the attribute redisplay="false", the value a user enters in the field will appear in the source of the page if it is redisplayed because of an error. The document says the default is true to be consistent with the other field tags, but that seems dangerous to me.

Thursday, July 31, 2003

I'm trying a new method for initializing a form. I still believe reset() is the best place to initialize form values, but for values that are needed in the JSP, but not for actually processing the form (contents of select boxes and other read only info), I think the Action is the best place to populate them. But how to avoid the problem I had earlier with validation? The answer is multiple mappings. So if I have an Action, EditUserAction, I might have two mappings as such:

<action
    path="/admin/initEditUser"
    type="com.company.action.EditUserAction"
    name="editUserForm"
    scope="request"
    parameter="dispatch"
    validate="false">
        <forward
name="initEditUser" path="/admin/editUser.jsp" redirect="false" />
</action>
   
<action
    path="/admin/editUser"
    type="com.company.action.EditUserAction"
    name="editUserForm"
    scope="request"
    validate="true"
    input="/admin/editUser.jsp"
    parameter="dispatch">
        <forward name="success"
path="/admin/index.html" redirect="false" />
        <forward
name="initEditUser" path="/admin/editUser.jsp" redirect="false" />
</action>

The first mapping has the correct form for the page, but with validate turned off. The second has it turned on. The first action would have a different dispatch than the second and would take care of initializing request attributes.


[BTW, is there a good way to just cut and paste XML into a blog? I.e. without having to escape all the tags?]

Tuesday, July 29, 2003

I'm currently finding it difficult to model complex interfaces and have them maintain state without being tightly coupled. For example, I've got a tabbed panel interface that decides which tab to show you based on a request param (it's stolen straight out of the Struts examples). That works great in that the contents of the tabs don't have to know they are being displayed inside a tab. However, one of these tabs contains a form. The problem is, when the form is submitted, the response doesn't return to that tab because the form doesn't include that "tab select" parameter. I could work around this by storing the selected tab in the session, but then the page wouldn't work if the user had more than one browser open. For the moment, I've bitten the bullet and added "selectedTab" as a parameter submitted by the form. And I guess it's not that bad a solution, since it doesn't affect the behavior of the form (I.e. the page would work fine outside a tabbed layout). Still, it feels wrong. I'll keep looking for a better solution.

Friday, July 25, 2003

I got Maven to send email notifications when tests fail. This should improve the usefulness of our JUnit suite since I doubt any of our developers were checking the build results manually on a daily basis. Getting it work was a bit of a challenge, but I had a lot of help from Brett Porter on the Maven users mailing list. He added the details of his response to the Maven Wiki here:

http://wiki.codehaus.org/maven/EmailTestReports?action=highlight&value=maven.xml

I made a couple of additions as well, to help Maven newbies like myself. I also modified junit-noframes.xsl to only show the failing tests. Have I mentioned how much I hate XSL? I'm sure it's powerful and all, but I always find myself guessing until the transformations work.

Wednesday, July 23, 2003

Here's my first attempt a blog.

I've been learning a lot about Struts lately and thought it would be good to write things down to pass on to my colleagues. It occurred to me that a blog might be the answer, so I'm going to give it a try. I'll jump right in to the things I learned today.

Initializing a form. Because Struts wants you to have an Action to handle every request, I was thinking I had to initialize my ActionForm in an Action in order to prepopulate data in JSP form. This isn't true and in fact it won't work if you have validation turned on (you are validating your forms, right?) . The trouble is, your Action is never reached if the form fails its validation check. Instead, the browser is sent to whatever page you have defined as the "input" for the Action (usually the .jsp with the <html:form>). The answer is to initialize the form by overriding ActionForm.reset(). Do whatever you need to prepopulate the form here. Then, define the actions like this:

<!-- Action to initialize the form -->
<action path="/initializeForm" forward="/myform.jsp" />

<!-- Action to save the data entered in the form -->
<action path="/saveForm"
input="/myform.jsp"
type="com.foo.MyForm"
validate="true" >
<forward name="success" path="/yay.html" />
</action>


The reset() gets called when the Form is instantiated. That happens in your JSP when the <html:form> tag is encountered. Incidentally, if your forms have request scope, doesn't that mean they'll be initialized twice? So the prepopulation data, which may not be needed on the server side, will have to be generated twice? Hmm. There must be a way to avoid that.

I tried to get the struts-el tags working today, and met with very limited success. It appears there is a bug in the Jasper JSP compiler JspC that causes it to choke on the struts-el tags if JspC is run outside of Tomcat. This happens when you either a) precompile your JSPs using Ant or b) try to compile your JSP in Netbeans. I do both of these frequently, so that pretty much rules out the use of these tags until this bug is fixed.