cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Antonio Gallardo" <agalla...@agssa.net>
Subject Re: A widget framework (long)
Date Wed, 27 Oct 2004 21:02:51 GMT
Hi Jonas:

I found the lecture interesting. Showed me that we need to put more effort
in documenting the CForms framework. You are making some assertions about
the CForms framework that are no exactly true....

Please don't take bad the comments between lines, because we are
learning..... ;-)

> ------------------------------------------------------------------------
>
> WIDGETS
>
> "Widgets" is a widget framework for Cocoon based on the taglib block.

It remains me XSP. We are moving out of that because the mixing of concerns.

> THE PROBLEM WITH COCOON FORMS
>
> The problem (as I see it) with Cocoon Forms is its concept of a
> ViewModel (the widget tree) that sits in between the model and the view:
>     Model (eg. bean) <-> ViewModel <-> View (eg. JXTemplate)

AFAIK, in the above statement, we tend to saw the form definition just as
a "mapping" between the model and the view. That is not true:

The so called ViewModel in CForms is the "form definition" the idea of
that is very similar to "XForms":

http://w3.org/MarkUp/Forms/arch1.png

<snip from="XForms specs" src="http://w3.org/MarkUp/Forms/">
a specification of Web forms that can be used with a wide variety of
platforms including desktop computers, hand helds, information appliances,
and even paper.
</snip>

Knowing that is clear the form definition is an abstract definition of the
form without taking care of the redering view.

> Having a ViewModel as a buffer between the Model and the View
> introduces a number of problems: First of all any changes made to the
> model has to be synhronized with changes to the ViewModel (eg if a list
> containg beans is expanded with one more bean then the ViewModel has to
> create widgets for the added bean).

Not exactly, you can have a bean with 10 attributes and a given CForm can
only use 5 of them. Of ourse you can build other CForms that can use 1 to
10 of them. You don't need to map everything in a 1-1 relation.

>From my experience, we have some Beans that need to be transformed before
passing it to a given CForm. To load the bean into de CForm we use
form.load(...).


> Another problem is if I have several
> widgets mapped to the same bean value. Then a change of value in one
> widget won't update the values of the other widgets.

Do you know the CForms binding framework? We also used of some JS client
side to manage that.

> Another set of problems has to do with the View. I can't use viewlogic
> (eg. JXTemplate) to alter which widgets are rendered.

You can use JXTemplate with CForms. Also there is a very interesting
presentation that Sylvain did in GT2004:

http://wiki.apache.org/cocoon/GT2004Sylvain

> It would be a
> piece of cake to make a wizard using JXTemplate but because the
> ViewModel has to know which widgets are rendered any changes to the
> visibility of the widgets has to go through the ViewModel. This means
> that to make a wizard (or tab-layout etc) I have to create them as
> Cocoon Form widgets using Java which is cumbersome.

As above, the point is to have a clear Separation Of Concerns. We can
easily render the same for to diferent devices in diferent formats.

> THE FRAMEWORK

...
>
> THE PAGE OBJECT
>
> <?xml version="1.0"?>
>
> <html xmlns:jx="http://apache.org/cocoon/templates/jx/1.0"
>   xmlns:wt="urn:widgets"
>   xmlns:wi="http://widget/instance"
>   >
>
>   <body>
>     <h1>Calculator wizard</h1>
>     <jx:if test="${wizard == 'term1'}">
>       Page term1
>       <a href="${continuation.id}.kont?cocoon-event=action:next">Next</a>
>     </jx:if>
>
>     <jx:if test="${wizard == 'term2'}">
>       Page term2
>       <a
> href="${continuation.id}.kont?cocoon-event=action:previous">Previous</a>
>       <a href="${continuation.id}.kont?cocoon-event=action:next">Next</a>
>     </jx:if>
>
>     <jx:if test="${wizard == 'sum'}">
>       Page sum
>       <a
> href="${continuation.id}.kont?cocoon-event=action:previous">Previous</a>
>     </jx:if>
>     <a href="${continuation.id}.kont?cocoon-event=action:exit">Exit</a>
>   </body>
> </html>
> ---------------------------------------------------
>
> The JXTemplate is nothing out of the ordinary. It will simply hide the
> pages of the wizard that are not active (as set in ${wizard}).

AFAIK, the above is a mixing of concerns between the businness logic and
the view in the same file. Much the same style of XSP. Is more clear if
you have 3 diferent forms and let the controller decide wich of them will
use in a particular case.

....

> ADDING THE MODEL
>
> The widget framework introduces the concept of Models. A Model is a
> wrapper around your data so that the View can access it in a uniform
> way. Currently there are four different type of Models:
>
> * BeanModel: wraps a POJO
> * DOMModel: wraps a DOM
> * MapModel: wraps a java.util.Map
> * ResultSetModel: wraps a database query
>
> As we decided to represent the calculator as a bean we will choose to
> wrap it in a BeanModel.

The binding framework is used in CForms for doing that.

> In order to show the model in the view we change the JXTemplate:
>
> ---------------------------------------------------
> <?xml version="1.0"?>
>
> <html xmlns:jx="http://apache.org/cocoon/templates/jx/1.0"
>   xmlns:wt="urn:widgets"
>   xmlns:wi="http://widget/instance"
>   >
>
>   <body>
>     <h1>Calculator wizard</h1>
>     <form action="${continuation.id}.kont" method="post">
>       <wt:model id="calculator">
> 	<jx:if test="${wizard == 'term1'}">
> 	  <p>
> 	    <b>Term 1:</b>
> 	    <wt:field type="text" attribute="term1"/>
> 	  </p>
> 	  <p>
> 	    <wt:form-button action="next">Next</wt:form-button>
> 	  </p>
> 	</jx:if>
>
> 	<jx:if test="${wizard == 'term2'}">
> 	  <p>
> 	    <b>Term 2:</b>
> 	    <wt:field type="text" attribute="term2"/>
> 	  </p>
> 	  <p>
> 	    <wt:form-button action="previous">Previous</wt:form-button>
> 	    <wt:form-button action="next">Next</wt:form-button>
> 	  </p>
> 	</jx:if>
>
> 	<jx:if test="${wizard == 'sum'}">
> 	  <p>
> 	    <b>Sum:</b>
> 	    <wt:out attribute="sum"/>
> 	  </p>
> 	  <p>
> 	    <wt:form-button action="previous">Previous</wt:form-button>
> 	  </p>
> 	</jx:if>
>       </wt:model>
>       <a href="${continuation.id}.kont?cocoon-event=action:exit">Exit</a>
>     </form>
>   </body>
> </html>
> ---------------------------------------------------

More mixing of concerns. It is going very similar to XSP.

> The wt:model tag is used to setup the context that subsequent widget
> tags will operate on. In this case we identify the model as "calculator"
> (which is the key we used in the page.show() method call. This means
> that any descendant tags will look up their values in our calculator
> bean. It is possible to supply the view with several models.
>
> When the wt:field tag is executed (during taglib transformation) it will
> fetch the value of attribute "term1" from the containing model (in this
> case the calculator bean). Subsequent xslt transformation will turn it
> into a html input text tag.
>
> The wt:form-button will translate into a html button element. The name
> of the buttons will be "cocoon-event" and its value will be set to eg.
> "action:next" so that a button press will trigger the event handling in
> the Page object.
>
> Contrary to Cocoon Forms we can choose at render time the type of widget
> used to show model values. In Cocoon Forms it is very difficult to
> change how we represent data, eg. once you have decided that term1
> should be rendered as a text field you cannot change that very easy.

Hmm.. See Sylvain GT2004 presentation. The problem is that most people
think that the cform rendering stylesheets in cocoon samples are the only
way to render the CForms. This is not true.

BTW, the are some RFE to build new samples for cform using XUL and another
using WML as the target format....

> Here we can use a text field, a select box or whatever to render term1,
> we can even render the value of term1 several times using different
> types of widgets.

Same in CForms.

>
> VALIDATION
>
> A very simple calculator validator can look like this:
>
> ---------------------------------------------------
> package widgets.samples;
>
> import org.apache.commons.validator.GenericValidator;
> import widgets.model.BeanModel;
>
> public class CalculatorValidator {
>
>     public boolean validatePhase1(BeanModel model) {
>
> 	Calculator calculator = (Calculator) model.getBean();
>
> 	if (! GenericValidator.isInt(calculator.getTerm1())) {
> 	    model.setError("term1", "Value must be an integer");
> 	    return false;
> 	}
> 	return true;
>     }
>
>     public boolean validatePhase2(BeanModel model) {
>
> 	Calculator calculator = (Calculator) model.getBean();
>
> 	if (! GenericValidator.isInt(calculator.getTerm2())) {
> 	    model.setError("term2", "Value must be an integer");
> 	    return false;
> 	}
> 	return true;
>     }
> }
> ---------------------------------------------------

CForms validation is more elegant to me.

Best Regards,

Antonio Gallardo

Mime
View raw message