/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.katari.editablepages.view;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.Errors;
import org.springframework.web.servlet.mvc.SimpleFormController;
import org.springframework.web.servlet.ModelAndView;
import com.globant.katari.core.application.Command;
import com.globant.katari.core.application.Initializable;
import com.globant.katari.editablepages.application.ShowPageCommand;
/** Spring MVC Controller to handle operations on a page.
*
* This controller handles view, preview, create, edit and delete of pages. All
* these operations have a common workflow: select a page from and operate on
* that page. The only difference between these operations is the view to use
* to complete the operation, and the command that effectively performs the
* operation.<br>
*
* The steps are:<br>
*
* 1- Show a form (or html) with the page.<br>
*
* 2- Submit the form to the controller.<br>
*
* 3- Return to the original page.<br>
*
* In step 1, create, edit and view operation only differ in the ftl view they
* use. The delete could use the step one to show a confirmation page (not done
* here yet).<br>
*
* In step 1 and 2, each operation use its own command (preview, create and
* edit reuse the same command). The view operation does not have a step 2.<br>
*
* The command must be of type <code>Command<String></code>, that implies
* that execute must return a string. This controller uses the returned string
* as the name of the page to go after saving or cancelling the operation.
*
* The page view supported by this controller is used only to show an editable
* page from a weblet. Normal page view is done with a different controller
* (PageController).
*/
public abstract class PageEditController extends SimpleFormController {
/** The class logger.
*/
private static Logger log =
LoggerFactory.getLogger(PageEditController.class);
/** The FCKEditor configuration.
*
* Defines the configuration js location, toolbar, width and height.
*/
private FckEditorConfiguration fckEditorConfiguration;
/** Defines what http request method is considered a form submission.
*
* If null, then leave spring default of considering a POST a form
* submission.
*/
private String submitMethod = null;
/** Default initialization for the controller.
*
* @param fckConfiguration The fck configuration object. This is passed to
* the edit page to configure FCKEditor. It cannot be null.
*/
public PageEditController(final FckEditorConfiguration fckConfiguration) {
Validate.notNull(fckConfiguration,
"The FCKEditor configuration cannot be null");
setSuccessView("redirect:pages.do");
setBindOnNewForm(true);
fckEditorConfiguration = fckConfiguration;
}
/** Create a reference data map for the given request.
*
* Initializes the command loading the corresponding page from the
* repository.
*
* This controller is also responisible for rendering weblets. The editable
* pages weblets need an id for some html tags. This controller also provides
* these ids to the weblets. It uses the request object to hold an elementId
* attribute, an integer that is incremented on every use. This element id is
* only meaningful during the rendering of the views. It is exposed to the
* view as elementId.
*
* This controller also puts the FCKEditor configuration in the model map
* under the key fckEditorConfiguration.
*
* @param request The HTTP request we are processing.
*
* @param command The command object with the bound parameters. It cannot be
* null.
*
* @param errors The errors holder. It cannot be null.
*
* @exception Exception if the application logic throws an exception.
*
* @return the Map for the form view.
*/
@SuppressWarnings("unchecked")
@Override
protected Map referenceData(final HttpServletRequest request, final Object
command, final Errors errors) throws Exception {
log.trace("Entering referenceData");
Validate.notNull(request, "The request cannot be null");
Validate.notNull(command, "The command cannot be null");
Validate.notNull(errors, "The errors cannot be null");
if (!(command instanceof Initializable)) {
throw new IllegalArgumentException("The provided command does not"
+ " implement Initializable");
}
Initializable initializable = (Initializable) command;
/* If the controller is rendering a weblet, this initializes the
* ShowPageCommand from the weblet instance.
*
* This instance is the name of the page to show.
*
* This is a nasty hack: spring does not bind request attributes.
*
* TODO See if it is possible to use a binder that binds request attributes.
*/
Object instance = request.getAttribute("instance");
if (instance != null && command instanceof ShowPageCommand) {
((ShowPageCommand) command).setInstance((String) instance);
}
initializable.init();
Map<String, Object> data = new LinkedHashMap<String, Object>();
data.put("fckEditorConfiguration", fckEditorConfiguration);
data.put("request", request);
data.put("baseweb", request.getAttribute("baseweb"));
// Increments the elementId from the request.
Long elementId = (Long) request.getAttribute("elementId");
if (elementId == null) {
elementId = Long.valueOf(1);
} else {
elementId++;
}
request.setAttribute("elementId", elementId);
data.put("elementId", elementId);
log.trace("Leaving referenceData");
return data;
}
/** Performs the operation on the page through the command.
*
* @param command Form object with request parameters bound onto it.
*
* @exception Exception if the application logic throws an exception.
*
* @return Returns the model and view to render the following page. The view
* name is obtained from the command. If null, then the view will be the
* success view of this controller.
*/
@SuppressWarnings("unchecked")
protected ModelAndView onSubmit(final Object command) throws Exception {
log.trace("Entering onSubmit");
String targetPage = ((Command<String>) command).execute();
ModelAndView mav = null;
if (targetPage != null) {
log.debug("Redirecting to {}{}", "../page/", targetPage);
mav = new ModelAndView("redirect:../page/" + targetPage);
}
log.trace("Leaving onSubmit");
return mav;
}
/** Sets the method to perform a form submission.
*
* @param method the http request method (ej: GET, POST). It cannot be null.
*/
public void setSubmitMethod(final String method) {
submitMethod = method;
}
/** Decides if the form is submited based on the request method.
*
* Set the method to consider a submission with setSubmitMethod.
*
* {@inheritDoc}
*
* @return true if the request method matches what was specified with
* setSubmitMethod.
*/
protected boolean isFormSubmission(final HttpServletRequest request) {
if (submitMethod == null) {
return super.isFormSubmission(request);
} else if (submitMethod.equals(request.getMethod())) {
return true;
}
return false;
}
/** Retrieve a backing object for the current form from the given request.
*
* @param request The HTTP request we are processing.
*
* @exception Exception if the application logic throws an exception.
*
* @return The command bean object.
*/
@Override
protected Object formBackingObject(final HttpServletRequest request)
throws Exception {
return createCommandBean();
}
/** Returns the command object to post and save the user.
*
* This method is injected by AOP.
*
* @return Returns the command bean injected.
*/
protected abstract Object createCommandBean();
}