|
From: Keith D. <kd...@cs...> - 2004-06-13 17:35:23
|
Rich client gang:
I've refactored and substantially enhanced our rich client form data binding
and validation framework over the last several days to meet the
objectives/requirements outlined below. Thanks to Ben, Ronald, Francois,
and Andy for offering their suggestions & helping evolve the design. I'm
quite liking it now, and I'd probably still be arguing with myself still had
it not been for your help.
Specifically:
- There is a "FormModel" mediator layer that sits between the GUI controls
and the domain model layer, which provides a model for buffering form edits
and performing form validation and results reporting. This layer makes
heavy use of the ValueModel pattern, pointed to me by Ben as an elegant
solution to this problem.
This means the following happens when you edit a form:
- GUI Control edits are captured by the form model. Validation is applied
on each form model update, with results reported to validation listeners in
real-time (for example, one listener might be a message pane attached to an
application dialog title area). What validation to perform is determined by
the declarative rules associated with the properties of the form-backing
domain object. These rules are centrally configured and accessed by our
RulesSource interface (part of the declarative validation system.)
- The text-field edit commit policy is now configurable. You may choose to
have the form model updated on each character event (as-you-type), on a
focus lost event, or only on form submission. The as-you-type
"ValueCommitPolicy" is the default.
- A Guard (ValidationListener) enables the form for submission when there
are no errors, and disables it when there are errors. Thus we only allow
submission when the form has no errors, protecting domain model invariants.
Note also the guard triggers on the result of the evaluation of
business-tier rules associated with domain object properties that are
presentation independent; thus the same rules could be applied in a web-app
environment, for example. In a rich client, a guard implementation
typically has the responsibility of enabling/disabling the "OK", "Finish",
or "Apply" button on a form's dialog.
- A submit event (what we call a "finish" event) commits changes to the
backing domain layer, a cancel event triggers no action.
The API has changed a bit (to be expected); however, some of this change is
mitigated by existing framework superclasses.
Checkout the rc-petclinic sample for illustration of the new API. Here is a
quick peek:
The AbstractCommandEditor (framework class) - illustrated below is code to
set the backing form object.
// initialize the backing form object (domain object)
public void setCommand(Object command) {
if (commandHolder == null) {
// wrapping the command in a value holder allows clients to
subscribe to notifications when the value changes....this allows us to reuse
the same form model for different instances of the command object.
this.commandHolder = new ValueHolder(command);
} else {
this.commandHolder.set(command);
}
}
// OwnerGeneralPanel form subclass - illustrated below is code to create the
Form model for the backing domain object with an attached
ValidationListener. In this example, the listener implementation maintains
a message area pane to report errors messages, and acts as a guard for
controlling the enabled/disabled state of the dialog submit button.) Below
that is code to build the form controls against the form model, using a
FormBuilder:
protected JComponent createControl() {
FormLayout layout = new FormLayout("left:pref, 5dlu, pref:grow");
setFormModel(SwingFormModel.newForm(getCommandHolder(),
validationReporter));
BeanFormBuilder formBuilder = new
JGoodiesBeanFormBuilder(getFormModel(), layout);
formBuilder.add("firstName");
formBuilder.add("lastName");
return formBuilder.getForm();
}
The output is a basic form with two labels and two textfields, with
as-you-type validation enforcing the declarative rules associated with those
properties. The reporter automatically displays validation error messages
with zero code required (there is quite an sophisticated bit of logic going
on to generate error messages for you from the rule structures.) The
reporter also automatically enables the guarded control at the appropriate
times, again with zero coding required.
This design is a million times better than before, but we're not done yet!
As always, we very much value your feedback - from code / design review
critique to help flushing out new features that meet your requirements.
Keith
-----Original Message-----
From: spr...@li...
[mailto:spr...@li...] On Behalf Of
Keith Donald
Sent: Wednesday, June 09, 2004 6:50 PM
To: spr...@li...
Subject: RE: [Springframework-rcp-dev] Change request for
InputApplicationDialog
Ben,
Great email, thanks. I think we're in agreement then! We want:
- As you type validation with real-time results reporting. Currently our
forms support rendering as-you-type results with configurable severity
levels on message panes (generally located in the title area of a dialog,
similar to eclipse-style dialogs). Obviously decorated JTextField
components would be a very nice enhancement.
- On validation, appropriate enforcement of "guards" that control the
enabled/disabled state of a form based on validation results. We support
this now through our Guarded interface, which the Guards interact with to
control state (see the Petclinic sample for an illustration.))
- A mediator for taking proposed property values and validating them against
a set of declarative (and potentially externalized) validation rules BEFORE
COMMITTING THEM TO THE UNDERLYING BEAN. These rules may need additional
context (for example, rules may vary based on use-case, some rules may
require validation against another property on the form.)
I completely agree we want a framework that makes it easy to write a domain
model that is rich in behavior and not one that consists of dumb-downed data
holders. It's nice to see that well articulated, thank you for that!
Keith
-----Original Message-----
From: spr...@li...
[mailto:spr...@li...] On Behalf Of
Ben Alex
Sent: Wednesday, June 09, 2004 6:24 PM
To: spr...@li...
Subject: RE: [Springframework-rcp-dev] Change request for
InputApplicationDialog
> So with that said, the modes I think we need are:
>
> 1 - as you type validation with a real-time results reporting
> pane on the dialog, and binding occurring on submit only.
> The validation framework has to be able to handle proposed
> property changes and validate them against some context (at a
> minimum existing property of the bean, but we probably need
> to support other variables as well.)
>
> 2 - validation / binding occur together on submit only
>
> 3 - is as you type binding + validation (what we have now) an
> option we want? Or does the copy issue just rule it out completely?
>
> - anything else I missed?
On the as-you-type validation issue, why are we building rich GUIs? In my
case it's to provide end users with an extremely positive experience by
being as easy-to-use as possible, highly responsive and flexible enough to
support advanced features. As-you-type validation fits in very well with
this goal. When done right you can also decorate JTextFields etc with small
icons to indicate errors, warnings etc. If people would like to see an
excellent repository of validation styles for rich clients, visit
http://www.jgoodies.com/downloads/index.html and run the validation demo.
Whilst on the subject of bindings, JGoodies use a ValueModel approach. If
you speak German, check out http://www.jgoodies.com/articles/. If you would
an English overview, check out http://c2.com/ppr/vmodels.html for instance.
A few extra requirements we've found helpful in our Swing app:
- As-you-type validation should disable the OK and/or apply buttons until
the form is correct.
- OK and apply hook to a doApply() method. For our login use case we have a
SessionDetails JavaBean, which is fronted by a SessionDetailsModule. The
latter performs validation and provides ValueModels for the LoginDialog.
LoginDialog updates SessionDetailsModule. Upon clicking OK, the action
delegates to doApply(). If login is successful, the SessionDetailsModule has
its trigger channel fired. This writes the changes through to the
SessionDetails bean. If login failed, an appropriate error is displayed but
the trigger channel not fired. As such the user can chose to refine their
entry details, or click cancel. Note that an invalid object state never gets
to SessionDetails unless login is correct. This is especially desirable
because we have PropertyChangeListeners listening for updates to
SessionDetails properties so they can modify the displayed toolbar buttons,
pull down menus and views.
I think this whole acceptance of invalid object states stems from entity
bean days. Anemic domain objects (or any object that by design allows
invalid property states) breaks OO design principles. Use a ValueModel or
some mediator to prevent invalid objects from being created in the first
place. Thus you can take advantage of OO features, such as property
listeners.
Best regards
Ben
-------------------------------------------------------
This SF.Net email is sponsored by: GNOME Foundation
Hackers Unite! GUADEC: The world's #1 Open Source Desktop Event.
GNOME Users and Developers European Conference, 28-30th June in Norway
http://2004/guadec.org
_______________________________________________
Springframework-rcp-dev mailing list
Spr...@li...
https://lists.sourceforge.net/lists/listinfo/springframework-rcp-dev
-------------------------------------------------------
This SF.Net email is sponsored by: GNOME Foundation
Hackers Unite! GUADEC: The world's #1 Open Source Desktop Event.
GNOME Users and Developers European Conference, 28-30th June in Norway
http://2004/guadec.org
_______________________________________________
Springframework-rcp-dev mailing list
Spr...@li...
https://lists.sourceforge.net/lists/listinfo/springframework-rcp-dev
|