State management in moto allows for
persistence of information in the
Context,
Sessions and
States.
The Context and the Session store <Object>s. The Context stores objects
that are global, may be set, updated and retrieved from any page, and never expire unless
explicitly removed from the Context and deleted. The Session
stores objects that are needed only for one user's Session and expire when
that user's Session expires. The State stores variables passed in
the URL or submitted via HTML form submissions (HTTP Post operations).
Before you can make use of moto's state management facilities however, you
must $use("codex.http")
State variables, also called CGI variables, are created by following a URL,
submitting a HTML form, or HTTP redirection. Following the URL
http://www.webcodex.com/index.moto?foo=bar&maka=shlaka
| |
Will add two variables to the state when the index.moto page is executed.
The state variable 'foo' will have the value 'bar' and the state variable 'maka' will
have the value 'shlaka'.
<form action="index.moto">
<input type="hidden" name="foo" value="bar">
<input type="hidden" name="maka" value="shlaka">
<input type="submit" value="click me">
</form>
| |
Clicking the 'click me' button on this form will make the same two state variables
with the same two values available to index.moto when it is executing.
$do(sendRedirect("index.moto?foo=bar&maka=shlaka"))
| |
Executing a moto page that redirects to another moto page via the above redirect will
also result in our two state variable being added.
The values of state variables can be retrieved within the code for index.moto in
one of three ways. First, the current state can be retrieved and a method can be
called on it to get the value of the state variable
$(getState().getValue("foo"))
| |
Second, if you want the value of a state variable for the current state (as you
usually do) than you can call the convenience function getValue() directly
Third, you can use the two argument version of getValue() to provide a default value
if the state variable is not defined in the current state.
There are usually multiple means of getting to a moto page some of which pass a
certain state variable and some of which don't. If someone got to index.moto
by typing
http://www.webcodex.com/index.moto
| |
directly into their browser for instance the
variable 'foo' would not be defined. In this case the getValue function (or method)
would return the value null. There are two ways in which to handle this case
In web application programming, state variables (URL or form variables) are
often looked at as arguments to the dynamic web page. If the argument is a
required argument then you would want it's non-existence to be treated as an error
$if(getValue("foo") == null)
$(sendRedirect(some error page)
$endif
| |
But if it was an optional argument than you will likely have some default value in
mind. In this case the third method of retrieving state variables is useful
In this case if the state variable foo was not passed than the default value 'bar'
will be used in it's place.
The characters =, &, and ? separate variable names from variable values,
variable name value pairs from each other, and the query string from the hostname
and path. In the case a variable name or value contains these special characters
(or spaces, or another special character '%') that name or value must first be URL
encoded before it may used in a URL.
<a href="index.moto?foo=$(urlEncode(foovalue))">
| |
The function urlEncode() will replace the special characters with their hexadecimal
counterparts %hex value which will be understood by the web server and
decoded on the next page view. Thus there is no need to URL decode explicitly in
your source code.
State variable values may also be set through user input in HTML forms
<form name="login form" method="post" action="do_login.moto">
User: <input type="input" name="user">
Password: <input type="password" name="password">
<input type="submit" name="_action" value="login">
</form>
| |
Clicking the login button on this form will actually submit three variables.
The state variable 'user' will contain whatever the user entered for the user prompt.
The state variable 'password' will contain whatever the user entered for his or her
password. There will also be a state variable '_action' which contains the value
'login'. Now let's suppose that the page do_login is coded as follows
$switch(getValue('_action',"login"))
$case(login)
$if(getValue("user","") eq "bob" && getValue("password","") eq "bobpw")
$do(redirect("index.moto?sid="+getState().getSID()))
$else
$do(redirect("login.moto?sid="+getState().getSID()+"&_err=Password+rejected"))
$endif
$endswitch
| |
Here we see that if the user attempted to log in with user name 'bob' and password
'bobpw' then he will be forwarded on to index.moto, otherwise he will be redirected
back to the login page.
For applications that make use of Sessions, the current Session is retrieved from the state
by calling the method getSession()
$declare(State s = getState())
$declare(Session session = s.getSession())
| |
Once you have the Session, you may retrieve named Session variables from it by calling the
get() method
$declare(Integer idUser = <Integer>session.get("idUser"))
$declare(String username = <String>session.get("uname"))
| |
Before you may get any objects out of the Session however, you must put objects into it. This
is done by calling two methods on the Session object: put() and promote().
$do(session.put("idUser",session.promote(new Integer(rset.getInt(0)))))
$do(session.put("uname",session.promote(rset.getString(1))))
| |
The put method does nothing more than associate a String valued key with the object you want to
store in the Session. The action of the promote method is less obvious.
All objects allocated in moto have an implicitly specified lifetime after which the storage
for the object will be recovered by the memory manager. By default the lifetime of an object ends
when the page that it was constructed on is done executing. These objects are said to have a page
lifetime. Objects that we want to make available on subsequent page views (without reconstructing
them) need to stick around longer than that. This is what the promote method does
When you call Session.promote() on an object you change its lifetime to the lifetime of the Session
you are storing it in. In the following section you will find that there is a Context.promote()
function as well. If promote() were not called on an object before it was put in the Session or
Context then the reference stored in the Session or Context would be invalid since the object may
have already been deleted.
Methods such as Session.put() do not implicitly call promote because there would be many cases it
could not catch. For instance suppose a SymbolTable was allocated and stored in the Session. Then
objects were put into the SymbolTable. In this case the reference for the SymbolTable may be valid
on subsequent page views, but the references for objects in the SymbolTable would not be. The bottom
line is anything that is put into anything that is put into anything that is put into the Session
or Context must be promoted.
The Context is the appropriate place to store
singletons, that is Objects that you only need
one of for your application. This is because there is only one Context and every page can get
objects out of or store objects in the Context. Perhaps the most common type of object to store in
the Context are caches.
To store an object in the Context, the Context must first be retrieved by calling the function
getContext(), the object to be stored should then be promoted by calling Context.promote(), and
finally the object must be associated with a name in the Context by calling Context.put().
$do(getContext().promote(cardData))
$do(getContext().put("CardList",cardData))
| |
To retrieve an object from the Context use the method Context.get()
cardData =<TabularData>getContext().get("CardList")
| |
Copyright © 2000 - 2003 David Hakim