Jonas Ekstedt wrote:
On Wed, 2004-11-03 at 21:46 +0100, Daniel Fagerstrom wrote:
<snip/>
In some cases like when you can build lists or trees in the user interface, a more traversal based interface is needed.

I agree that I haven't really thought this issue through thoroughly. In the widget framework there is a "public int size(String path)" method that returns the size of whatever object is present at that path. But there could certainly be more stuff thrown in such as support for pointers similar to JXPath that can run around in your model data.

Yes, a tree traversal inteface is needed maybe something like:

  String getValue(String path);
  Pointer getPointer(String path);
  Iterator getIterator(String path);

Also, like everyone else that has commented your proposal, I think that it often is a bad idea to write directly to your model. Even if you are able to solve the security problems, the model will still need to be able to store partially invalid input data and missing data. IMO it is better SoC to have a form model in front of the real model. This decreases the complexity of the model as it always can get data in a more transactinal way in complete chunks.

Protecting the application object is partly what the Model interface is
all about. In the getValue/setValue functions you can implement any
measures to protect the application object you'd like. The point is that
the user should decide what type of shielding should be used.


Eg. the project I'm working on is dependant on letting the view access
derived values from the bean model. That means I need to populate the
beans directly. I do not really care if the beans are inconsistent as I
won't hibernate them if they are (in a sense the database is my
"application object" that I need to shield). So in my case it makes
sense to operate directly on the application object.

However, as a different example, should I start using beans with
properties like ints or Dates then I would choose some other strategy as
I need to be able to save values even when they are not convertible. In
this case the wrapping model could store illegal values in a separate
map. getValue() would then return values from the map if they exist or
from the bean otherwise.

The second approach is similar to how CForm widgets works. What I think
is the benefit of the Model interface is that it is up to the user to
decide what type of shielding should take place.

I agree that CForms is a little bit monolitic and that it would be god if we could find a strict decomposition of the different involved concern areas. Then we could have well defined and hopefully small interfaces between the parts and make it possible for webapp developers to reuse parts of it.


My curent view of the involved concern areas is something like:

+------------------+    +-----------+    +-------+    +----------+
| RequestProcessor |--->| Convertor |    | Form  |    | Business |
+------------------+    +-----------+<-->|       |<-->|          |
| Template Engine  |<---| Renderer  |    | Model |    | Model    |
+------------------+    +-----------+    +-------+    +----------+

Of course there is a controller as well, but that is not the subject for this discussion. Compared to the usuall MVC pattern we can see that the model is split in a form model and a business model. The binding step between the form and business model should maybe also have an own box, but then the image didn't fit within the 71 charachters ;). We also have a convertor/renderer step. Compared to CForms curent state the request processor, and convertor/renderer has different positions.

We folow the data from request to respons. The request processor parses the request object or the xml input or what you have. And write this to something like the model interface you proposed:

  void setValue(String path, String value) {
    Datatype type = formModel.getDatatype(path);
    Object obj = convertor.convert(value, type, locale);
    formModel.setValue(path, obj);
  }

We could maybe call this part a view adapter. It doesn't contain any data and is only an adapter that perform the conversion/rendering before writing to/reading from the form model.

For the form model <-> business model communication everything is like it use to be. With the adition that for some kinds of business model implementations, like DOM-trees, XML DBs and RDBs, it might be usefull with a convertor/renderer step also. So that you don't have to use the same data type conversions in the binding each time you use a certain data type.

In the last step the template engine reads from the view adapter thru a tree based interface, like the one I proposed in the begining.

So in this model the view adapter gives read and write access to an untyped tree and the form model is a typed tree that also contain validation and event handling.

                            ---o0o---

Given that we can find good interfaces between the different steps. You and other Cocoon webap developers can resuse parts of the form framework to your own liking. If you don't want the split in business and form model in a certain application you can still use the rest of the framework.

I prefer the request processor idea to the current form population where each widget reads it data from the request object. The current scheme makes CForms unecesarily bound to the request parameter model of input data. With a request processor that is reponsible to write input data into the form model, it would be easy to plug in a different request processor if one gets xml input from a browser that implements XForms, e.g.
I think it would be quite easy to make this change to CForm.

So do I, although I havn't studied the details in CForms for a while. I guess it can be done in a completely back compatible way. A request processor, a convertor/renderer and a view adapter needs to be written. Then one just don't use the readFromRequest and generateSaxfragment any more. There might be subtilities in the state sequence within widgets that complicates thins though.


WD[Y|O]T

/Daniel

Reply via email to