package hirondelle.web4j.action;
import java.util.logging.*;
import java.util.regex.Pattern;
import hirondelle.web4j.request.RequestParameter;
import hirondelle.web4j.request.RequestParser;
import hirondelle.web4j.util.Util;
import hirondelle.web4j.model.AppException;
/**
<b>Template</b> for "first show, then validate and apply" groups of operations.
<P>A good example is a page allowing the user to change their preferences : from the
point of view of each user, there is only one set of user preferences. Often, a single form can be used
to allow editing of preferences. Here, there is no listing of multiple items.
<P>There are two operations in such cases :
<ul>
<li>show me the form with the current data (if any)
<li>allow me to post my (validated) changes
</ul>
*/
public abstract class ActionTemplateShowAndApply extends ActionImpl {
/**
Constructor.
@param aForward used for {@link Operation#Show} operations, and also for <em>failed</em>
{@link Operation#Apply} operations. This is the default response.
@param aRedirect used for <em>successful</em> {@link Operation#Apply} operations.
@param aRequestParser passed to the superclass constructor.
*/
protected ActionTemplateShowAndApply(ResponsePage aForward, ResponsePage aRedirect, RequestParser aRequestParser){
super(aForward, aRequestParser);
fRedirect = aRedirect;
}
/**
The operations supported by this template.
<P>The supported operations are :
<ul>
<li> {@link Operation#Show}
<li> {@link Operation#Apply}
</ul>
The source of the <tt>Operation</tt> is described by {@link ActionImpl#getOperation()}.
*/
public static final RequestParameter SUPPORTED_OPERATION = RequestParameter.withRegexCheck(
"Operation", Pattern.compile("(" + Operation.Show + "|" + Operation.Apply + ")")
);
/**
<b>Template</b> method.
<P>In order to clearly understand the operation of this method, here is the
core of its implementation, with all abstract methods in <em>italics</em> :
<PRE>
if ( Operation.Show == getOperation() ){
<em>show();</em>
}
else if ( Operation.Apply == getOperation() ){
<em>validateUserInput();</em>
if( ! hasErrors() ){
<em>apply();</em>
if ( ! hasErrors() ){
setResponsePage(fRedirect);
}
}
}
</PRE>
*/
@Override public ResponsePage execute() throws AppException {
if ( Operation.Show == getOperation() ){
fLogger.fine("'Show' Operation.");
show();
}
else if ( Operation.Apply == getOperation() ){
fLogger.fine("'Apply' Operation.");
validateUserInput();
if( ! hasErrors() ){
fLogger.fine("Passes validation.");
apply();
if ( ! hasErrors() ){
fLogger.fine("Applied successfully.");
setResponsePage(fRedirect);
}
}
}
else {
throw new AssertionError("Unexpected value for Operation : " + getOperation());
}
return getResponsePage();
}
/**
Show the input form.
<P>The form may or may not be populated.
*/
protected abstract void show() throws AppException;
/**
Validate items input by the user into a form.
<P>Applied to {@link Operation#Apply}.
If an error occurs, then <tt>addError</tt> must be called.
*/
protected abstract void validateUserInput() throws AppException;
/**
Validate the user input, and then apply an edit to the database.
If an error occurs, then <tt>addError</tt> must be called.
*/
protected abstract void apply() throws AppException;
// PRIVATE //
private ResponsePage fRedirect;
private static final Logger fLogger = Util.getLogger(ActionTemplateShowAndApply.class);
}