cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jonas Ekstedt <ekst...@ibg.uu.se>
Subject Re: A widget framework (long)
Date Thu, 28 Oct 2004 10:16:36 GMT
Hello

Thanks for the comments, they are much appreciated. I've inlined some
comments myself below.

On Wed, 2004-10-27 at 23:02, Antonio Gallardo wrote:
> > 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.

I don't understand why you think this is similar to XSP.

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

The main point I'm trying to make is that I think this is an abstraction
that harms more than helps. For example, we have to use bindings to map
data between the view model and the model. If we let the view talk
directly to the model the need for bindings completely disappears. The
abstraction of the view into a view model increases the complexity both
of the framework itself as well as the applications you write against
it.

> > 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.

This is true for bean attributes, but if I have a bean containing a list
of other beans, then adding a new bean to that list will require
invoking the binding to update the view model.
  
> > 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.

Using client-side JS is of course a solution but it is error-prone and a
hassle.

> > 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

The problem isn't so much hiding the widgets. The problem is in the
subsequent population of the view model. If I choose to use JXTemplate
to hide certain widgets then the view model has no way of knowing that
those widgets should be ignored during population. Thus the recent
discussions about widget states where you inform the view model which
widgets are visible, active etc.
 
> > 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.

I have no experience in device independant web programming so I
shouldn't really comment on the virtues of the view model in regards to
that. However my gut feeling is that if I would want to make my forms
accessible on other devices, the physical limitations of those devices
would necessitate using separate view models anyway. Eg a gigantic form
suitable for web viewing has to be split up as a wizard style form on a
cellular phone. In this case the abstraction of the form has gained me
nothing.

> > <?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.

Again, I don't understand why you think this is similar to XSP. Also, I
don't think there is any business logic included in this page (I might
have misunderstood what you mean by business logic). It simply displays
the current wizard page (a view concern) that has been set in the
controller.

> ....
> 
> > 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.

The problem with the binding framework, as I've said above, is that the
binding has to be invoked everytime I change the model. This is not
problematic for simple forms. Consider, however, the usecase of derived
values. Suppose I have a bean that contains two values and a getter that
returns the sum of them. When I change one of the terms in the form I
will have to use the bindings to save then reload the view model in case
I want the updated sum.

> 
> > 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.

This is pretty much what your average CForms template look like. With
the added bonus that you decide at render time what form element should
be used to display the data. I don't understand why you think this is a
mixing of concerns. There is nothing here that isn't explicitly related
to how to render the view.

> 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.

It is easy to change how widgets are rendered using jxtemplate or xslt
but the problem comes when the view model is populated. The view model
doesn't know that in a particular view rendering the widget was rendered
as a non-editable field and thus shouldn't be populated. The view model
always has to know the state of the widgets.

> > 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.

This was only an example of how validation can be done. Of course there
should be more user friedly ways of creating validation specifications.
Currently I'm working on a XMLSchemaValidator to use against a DOMModel.
Another alternative is RelaxNG. For BeanModel one could use
commons-validator.

Cheers Jonas


-- 
---------------------------------------------------------------
Address  :   Rackarbergsg 74, 752 32 UPPSALA
Phone    :   018-50 69 28, 0768-767 747



Mime
View raw message