<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html;charset=ISO-8859-15"
 http-equiv="Content-Type">
  <title></title>
</head>
<body bgcolor="#ffffff" text="#000000">
<br>
Hi!<br>
<br>
Here is an implementation of "compound storages" in CPSSkins (this
concerns the CPSSkins AJAX toolkit only so it also applies to Zope3 in
general, or to any other server that can handle JSON requests and
responses).<br>
<br>
First of all, this is a great step towards simplifying the development
of AJAX applications since it provides a complete abstraction between
the model and the storage. The development model gets shifted from
writing code in javascript that moves data around places to defining a
consistent data model. It is not necessarily easier unless one is used
to creating application by first creating a model as opposed to
starting by creating skins.<br>
<br>
Background:<br>
A data model needs some form of storage. There are many types of
storages (persistent, volatile, with synchronous access, with
asynchronous access, fast, slow, with low latency, with high
latency...). <br>
An AJAX application needs different types of storages to manipulate
data locally, to store the results of some user action on a server, to
provide temporary persistence for instance when editing a document, ...
There isn't one type storage that is best suited for everything.<br>
 <br>
In the CPSSkins AJAX toolkit, there are three types of base storages
available: the RAM storage, the local storage (cookie-based), and the
remote storage (that uses accessors to get and set data via a remote
server, e.g. Zope3).<br>
<br>
A problem that occurs in the MVC model when many types of storages are
available is that since a given view (a widget) can only observe a
single model,  all the data will have to be stored in the same place
and in the same way unless there is an indirection between the model
and the storage(s). <br>
<br>
Solution:<br>
The "compound storage" makes it possible to combine several models to
set their respective storages in common. The "compound storage" is
similar to a RAID controller: it uses several storages to create what
looks like a single storage, also it dispatches the I/O to the
different storages.<br>
<br>
In the current implementation, the storages communicate with the
compound storage and the compound storage communicates with the model
using a simple event system (publish-subscribe with a extra message).<br>
<br>
When some data gets stored in a given storage, an event is sent to the
subscribers (e.g. the compound storage). The event then gets propagated
to the model which relays the event to the view(s) which in turn get
updated. This is completely event-driven, so no "user-space" controller
is involved. The advantage is that it can occur asynchronously.<br>
<br>
The compound storage defines a list of partitions. Each partition
corresponds to the storage associated to a given model. The data stored
in a model is accessed according to a schema which means that storages
are protected against data corruption (such as changing the type of a
field, or adding an unknown field).<br>
<br>
There is a lot of complexity in the toolkit implementation, but this is
as much complexity that gets hidden from the application: the
controller simply needs to set data in the model it doesn't have to
know anything about ajax.requests or cookies. I've started writing a
simple live chat application, and all in all the entire application
code consists in about 40 lines of code in zope3 and in a 3Kb page
template.<br>
<br>
The model definition can be created TTW, since the data is represented
in JSON data structures, it involves no javascript. The only part that
is javascript-heavy is the part that renders the widget, but there will
be widget libraries.<br>
<br>
The animation:<br>
<a class="moz-txt-link-freetext" href="http://www.z3lab.org/sections/front-page/design-features/compound-storages">http://www.z3lab.org/sections/front-page/design-features/compound-storages</a><br>
<br>
The toolkit code:<br>
<a class="moz-txt-link-freetext" href="http://svn.z3lab.org/trac/z3lab/file/cpsskins/branches/jmo-perspectives/ui/framework/cpsskins.js">http://svn.z3lab.org/trac/z3lab/file/cpsskins/branches/jmo-perspectives/ui/framework/cpsskins.js</a><br>
<br>
The code in Zope3:<br>
<a class="moz-txt-link-freetext" href="http://svn.z3lab.org/trac/z3lab/file/cpsskins/branches/jmo-perspectives/ui/framework/tests/zope3/functional/quiz/browser.py">http://svn.z3lab.org/trac/z3lab/file/cpsskins/branches/jmo-perspectives/ui/framework/tests/zope3/functional/quiz/browser.py</a><br>
<br>
The page template:<br>
<a class="moz-txt-link-freetext" href="http://svn.z3lab.org/trac/z3lab/file/cpsskins/branches/jmo-perspectives/ui/framework/tests/zope3/functional/quiz/cpsskins_quiz.pt">http://svn.z3lab.org/trac/z3lab/file/cpsskins/branches/jmo-perspectives/ui/framework/tests/zope3/functional/quiz/cpsskins_quiz.pt</a><br>
<br>
    <br>
Here is the text seen in the animation:<br>
<br>
<h1>CPSSkins: storage adapters</h1>
<p>A <strong>storage adapter</strong> can be specified in the model
definition to describe how the model will access the data. </p>
<p>There are 4 types of storages available:</p>
<ul>
  <li>RAM</li>
  <li>Local (stores the data in cookies)</li>
  <li>Remote (accesses a remote server)</li>
  <li>Compound (a combination of several storages)</li>
</ul>
<ins name="controller0" class="controller"><br>
</ins>
<h2>RAM storage</h2>
<p>In a <strong>RAM storage</strong> the data is entirely stored in
the client's memory. The server is never accessed. There is no data
persistence.<br>
<br>
</p>
<h2>Local storage</h2>
<p>In a <strong>local storage</strong> the data is stored in a cookie
on the client. The server is never accessed. There is data persistence
as long as the cookie does not expire.</p>
<h2>Remote storage</h2>
<p>In this example the data is stored <strong>on the server</strong>
inside the session. This provides some persistence which means that the
page can be reloaded or the user can leave and return to the page and
the current data will be restored. </p>
<p>An extra delay has been added when retrieving and when storing data
to simulate network or database latency. Calls are made <strong>asynchronously</strong>
which means that the browser can load the page entirely before the data
is retrieved.</p>
<p>The user input is <strong>validated</strong> before the data is
getting stored. </p>
<p>Finally the view gets refreshed when the model is updated.</p>
<br>
<h2>Compound storage</h2>
<p>A compound storage is created by combining the storages of different
models.</p>
<p>In this example there are two storages:</p>
<ul>
  <li>A RAM storage for setting the status message on the client's side.</li>
  <li>A remote storage for saving the answer and for setting the status
message from the server's side.</li>
</ul>
<p>Both storages are combined into a unique <strong>compound storage</strong>.
</p>
<p>Hence the view (input box widget) still observes a unique model. The
status message can be written to both by the client and by the server
and the view will be automatically updated. </p>
<ins name="model7" class="model"></ins><br>
/JM<br>
</body>
</html>