The type converter and database access issue is interesting and does definitely deserve attention. However, my biggest concern was somewhat missed so I'll try to elaborate some of my thoughts (after reviewing and trimming, this post is still quite long - sorry).

* Extremely common use-case *
Let's say we have a simple online shopping (no, not a pet store, this time it's a toy store ;). The domain model maps personal information, orders, products etc to a database with Hibernate. We're building the "View personalia" and "Edit personalia" pages.


The "View personalia" action/view is easy to build due to the excellent features of WebWork. Our action has two properties. An Integer property set by the ParametersInterceptor denoting the customer's id and a Person property which is set by the action from the execute method. Creating the view is just a question of spitting out a few Label tags.

The "Edit personalia" action/view is a different matter. The most basic and, I guess, common approach would be to add some xwork validation configuration, instanciate an empty Person instance for the Person property when the action is constructed and change the view's Labels to Textfield. Then, when the action is executed, we load our real Person instance from the persistence layer, manually copy the properties set from the dummy Person property and persist. This seems to be fine, but there are a few issues (brain dump follows).

Manually copying values from one instance to another is time consuming to code and inflexible to change. Add a new editable field to the view and you need to recompile the action class. Remove a field and you're in the same situation (unless you like checking for nulls and nulls are invalid). Automatically copying properties with a beanutil package will destroy properties that are not set on the dummy instance, so it's not an option either.

Letting the user work direcly on the "real" Person instance might seem alluring (it did to me) since all this manual work disappears (and nulls will behave nicely). I achieved this using type converters to load the instance from the persistence layer before the ParametersAction interceptor was executed (as explained in a previous post), but after a closer look I changed my mind. :) Problem number one was security. Any not-so-nice user could easliy inject almost anything almost anywhere in the database by forging the POST/GET parameters (not only System.exit(0) is a dangerous parameter value when OGNL is involved). So, I thought I'd patch this up with a new ParameterFilterInterceptor with a similar configuration as ValidationInterceptor. Basically, I wanted to create a simple xml-configuration for different action contexts that would only allow or deny certain patterns of paramteres to be set (e.g <allow>person.*</allow><deny>person.orders</deny>).

A couple of hours later it was done and worked as it was supposed to, but then a real blocker appeared. Let's say a users edits his personalia and enters some data that the validators won't accept. Fine, the user is sent back to the input view and given the appropriate error messages and then decides to stop his session for some unnamed reason. If the Hibernate session is automatically comitted, the invalid data is already persisted to the database. If you roll it back, all the user's inputs are cleared and the form is back to it's original state (of course not acceptable). This can be solved with more sophisticated transaction management, but should not really be necessary for this simple use case.

There are a bunch of other ways to do this that I've been thinking about, but this post is already getting too long and none of them fits the bill anyway. Some key points of what a GOOD solution should have / not have / be are however:

- Simple for the developer (no manual copying of properties, no complex transaction management)
- Compatible with the xwork validation framework
- No recompilation needed when view is changed


So, how about something like this?

An xml document is created for the action / action context. This includes a allow / deny structure like the one discussed above for security reasons. A new interface somewhat like Preparable and ModelDriven is created. Then a new interceptor stack does the following:

1.
Calls the prepare method on the action so it can load it's model from the persistence layer. The identifier(s) could either be fetched from the context map or set via a setIdentifier(Object o) in the interface. The second option woule be possible by setting a identifier parameter name in the xml document.


2.
Replaces the model with a dynamic proxy which return the real models values when getters are called on properties which haven't been set by the ParametersInterceptor. I.e if the request wants to set the social security number on the Person property, it is just cached in the proxy and not really set on the Person instance. If the number is invalid the workflow interceptor will return the input view and the input view will retrieve the (invalid) value from the proxy. If the input view also wants to get (not set) e.g the user's "orders" property, the request is proxied to the real instance (which probably lazy-loads and caches :)).


3.
If the action has no errors, the values in the proxy will be set on the real instance if the allow / deny configuration allows it.


This might seem a bit complex, but in the end, I think it would be very easy for end-developers to use it (the ultimate form bean?). I might be way off though. Give me some feedback and if this seems like a reasonable idea I'll have a go at it. Shouldn't be very hard to implement. :)

Cheers,

Dag Liodden




Jason Carreira wrote:


This is a difficult issue... Maybe we can get the Atlassian guys to talk about what they've been doing in Confluence?

The reason doing database lookups in type converters is bad is because you're not in control of when it happens... It could be that it happens 1000's of times.

Jason



-----Original Message-----
From: Dag Liodden [mailto:[EMAIL PROTECTED]

Even if this example had only been about editing primitive (or primitive
wrappers) properties of the Employee instance there would have been trouble. The simplest approach is to instanciate a


temporary instance

of the Employee class in the action and let the interceptors set
the values
to that instance, but then you'll have to copy the properties
manually
when the action executed later. (a beanutils library will
help in some
cases, but what about nulls and transient instances?).

The PetSoar example does not provide any pointers - it does manual copying and avoids this issue. Some debate on this subject would be very welcome! If we get a good and simple pattern for this,

it would

be a killer feature.

One last point BTW. The type conversion doco states that it's a bad idea to do database lookups. Can someone elaborate, please? :)

Cheers,

Dag



-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration See the breadth of Eclipse activity. February 3-5 in Anaheim, CA. http://www.eclipsecon.org/osdn _______________________________________________
Opensymphony-webwork mailing list [EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/opensymphony-webwork




-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration See the breadth of Eclipse activity. February 3-5 in Anaheim, CA. http://www.eclipsecon.org/osdn _______________________________________________
Opensymphony-webwork mailing list [EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/opensymphony-webwork






-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Opensymphony-webwork mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/opensymphony-webwork




-------------------------------------------------------
The SF.Net email is sponsored by EclipseCon 2004
Premiere Conference on Open Tools Development and Integration
See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
http://www.eclipsecon.org/osdn
_______________________________________________
Opensymphony-webwork mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/opensymphony-webwork

Reply via email to