| Sign In/My Account | View Cart |
In our previous article, we covered the basics of sitemap navigation in Cocoon (the Cocoon XML publishing framework process), creating custom XML generators through the use of XSP, and using the XSP to homogenize the look and feel of sitewide content, specifically forms.
Picking up from where we left off, we had just generated a login form that
submitted a username and password. Typically, all of our forms submit data
back into Cocoon and to a URI that matches code in the sitemap that invokes a
Cocoon Action. Actions are simply Cocoon components that implement
org.apache.cocoon.acting.Action. Specifically,
public java.util.Map act(Redirector redirector,
SourceResolver resolver,
java.util.Map objectModel,
java.lang.String source,
org.apache.avalon.framework.parameters.Parameters par)
throws java.lang.Exception;
must be implemented. From the parameter list, you can see that the
environment objectModel is passed in, from which you can derive
the request object and also any sitemap parameters that are passed in.
Information is passed into the action through the request and the sitemap
parameters. Sitemap parameters are denoted through XML elements in the
sitemap. For example:
<map:act type="login-action">
<map:parameter name="session-timeout" "30"/>
</map:act>
In the code, the Action would receive the parameter as:
try {
String timeoutStr = par.getParameter("session-timeout");
this.timeout = new Integer(timeoutStr);
} catch (ParameterException e) {
log.info("Did not get a parameter for the timeout. Using default");
this.timeout = TIMEOUT_DEFAULT;
}
Sitemap parameters must come directly after the use of the component. Much like
matchers, you can see that the Action returns a Map.
This object is non-null if the Action was successful, and
null if the Action failed in any way. In the same way as the
matcher, the sitemap nesting reflects this if-then-else logic.
The other way we send information to Actions is through the request object.
When a form is submitted, the form inputs are encoded as request parameters.
You can derive the request object through the objectModel:
Request request = ObjectModelHelper.getRequest(objectModel);
From here, you can get request parameters as expected:
String login = request.getParameter("login");
String password = request.getParameter("password");
We use a combination of both sitemap parameters and request parameters in
our Actions. Typically, we will use sitemap parameters to denote functionality,
and the request parameters will contain the actual data with which to work.
Here's what your LoginUserAction act() might look
like:
public Map act
(Redirector redirector, SourceResolver resolver, Map objectModel,
String src, Parameters par) throws Exception {
try {
String timeoutStr = par.getParameter("session-timeout");
this.timeout = new Integer(timeoutStr);
} catch (ParameterException e) {
log.info("Did not get a parameter for the timeout. Using default");
this.timeout = TIMEOUT_DEFAULT;
}
Request req = ObjectModelHelper.getRequest(objectModel);
Session session = req.getSession();
// get user parameters from the request
String name = req.getParameter("name");
String password = req.getParameter("password");
if (name == null || password == null) {
// this should never happen..
return null;
}
Principal myPrincipal = null;
myPrincipal = login(name, password); // our own function.
if (!(myPrincipal == null)) {
session.setAttribute("principal", myPrincipal);
session.setMaxInactiveInterval(this.timeout);
Map sitemapParams = new HashMap();
return sitemapParams;
} else {
return null;
}
}
ActionsEvery web application should give some sort of visual feedback to the user
once something of significance has happened; in our case, the user has logged
in. Let's say our user should then receive a message saying so. We designed
our application such that all important things were accomplished through our
use of Actions (which delegated some tasks to our J2EE back end as well).
Because of this, we decided that it made a lot of sense to enable our Actions
to pass messages back up to our GUI front end.
In order to pass messages, we insert objects into the Cocoon Request
object. You saw earlier how every Action has access to the
Request object through the object model. The great thing about the Request
object is that you may place arbitrary numbers and types of objects into it
as key-value pair attributes of that Request:
request.setAttribute("message","You have just logged in!");
However, just passing a String as a message doesn't really seem
flexible enough for our needs. We need to be able to send multiple messages out
of a Request. For example, what if the user did not fill out three of the form
fields correctly?. To that effect, we created a wrapper class around a
Vector, called Messages, which supported
addMessage() and addError(), as well as a way to
iterate through those messages and errors.
In this scenario, we might send a message like this:
Messages messages = new Messages();
messages.addMessage("You have just logged in!");
request.setAttribute("messages",messages);
This is more flexible, but we still would like an easier way for Actions to
be able to use messaging in our application. Abstraction wins again, resulting
in two classes:
AbstractMessageAction, which inherits from
ActionAbstractErrorAction, which inherits from
AbstractMessageAction All of our messaging actions simply inherit from
AbstractErrorAction, and implement the act() method.
Our two abstract messaging classes define these methods:
error(String error);
commitErrors(Request req);
message(String message);
commitMessages(Request req);
The abstract classes handle the instantiation of the Messages
wrapper and other overhead. Any class that inherits from these could simply
call error() to its heart's content, committing those errors into
the request object with commitErrors() before returning
null. Because the Request object is visible throughout the life
of the request-response lifecycle, the GUI will be able to retrieve the
messages from the Request object and display them accordingly.
Our code above, with messaging implemented, would look like this:
public Map act
(Redirector redirector, SourceResolver resolver, Map objectModel,
String src, Parameters par) throws Exception {
try {
String timeoutStr = par.getParameter("session-timeout");
this.timeout = new Integer(timeoutStr);
} catch (ParameterException e) {
log.info("Did not get a parameter for the timeout. Using default");
this.timeout = TIMEOUT_DEFAULT;
}
Request req = ObjectModelHelper.getRequest(objectModel);
Session session = req.getSession();
// get user parameters from the request
String name = req.getParameter("name");
String password = req.getParameter("password");
if (name == null || password == null) {
// this should never happen..
error("Unexpected error: received null parameters");
commitErrors(req);
return null;
}
Principal myPrincipal = null;
myPrincipal = login(name, password); // our own function.
if (!(myPrincipal == null)) {
session.setAttribute("principal", myPrincipal);
session.setMaxInactiveInterval(this.timeout);
message(name + " successfully logged in");
commitMessages(req);
Map sitemapParams = new HashMap();
return sitemapParams;
} else {
error("Could not log " + name + " in");
commitErrors(req);
return null;
}
}
Pages: 1, 2 |