package org.toobs.framework.pres.spring.controller;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.view.AbstractUrlBasedView;
import org.springframework.web.servlet.view.InternalResourceView;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.util.WebUtils;
import org.toobs.framework.exception.BaseException;
import org.toobs.framework.exception.ParameterException;
import org.toobs.framework.exception.PermissionException;
import org.toobs.framework.exception.ValidationException;
import org.toobs.framework.pres.doit.IDoItManager;
import org.toobs.framework.pres.doit.IDoItRunner;
import org.toobs.framework.pres.doit.config.Action;
import org.toobs.framework.pres.doit.config.DoIt;
import org.toobs.framework.pres.doit.config.Forward;
import org.toobs.framework.pres.doit.config.Forwards;
import org.toobs.framework.pres.util.ComponentRequestManager;
import org.toobs.framework.pres.util.ParameterUtil;
import org.toobs.framework.pres.util.PresConstants;
/**
* Controller that transforms the virtual filename at the end of a URL into a
* component request. It then renders that component and dumps the result into
* the response.
*
* <p>
* Example: "/index" -> "index" Example: "/index.comp" -> "index"
*
* @author pudney
*/
@SuppressWarnings("unchecked")
public class DoItController extends AbstractController {
private UrlPathHelper urlPathHelper = new UrlPathHelper();
private IDoItRunner doItRunner;
private IDoItManager doItManager;
private ComponentRequestManager componentRequestManager = null;
private Log log = LogFactory.getLog(DoItController.class);
public DoItController() throws Exception {
}
private Forward getForward(DoIt doIt, String name) {
if (doIt == null) return null;
Forward forward = null;
Forwards forwards = doIt.getForwards();
if (forwards != null) {
Forward[] allFwds = forwards.getForward();
for (int f = 0; f<allFwds.length; f++) {
if (allFwds[f].getName().equals(name)) {
forward = allFwds[f];
break;
}
}
}
return forward;
}
/**
*
* Retrieves the URL path to use for lookup and delegates to
* <code>getViewNameForUrlPath</code>.
*
* @throws Exception
* Exception fetching or rendering component.
* @see #getViewNameForUrlPath
*
*/
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
String forwardTo = null;
HashMap responseParams = new HashMap();
HashMap forwardParams = new HashMap();
String urlPath = this.urlPathHelper.getLookupPathForRequest(request);
String doItId = extractViewNameFromUrlPath(urlPath);
if (logger.isDebugEnabled()) {
logger.debug("Staring to do it with doit '" + doItId + "' for lookup path: " + urlPath);
}
DoIt doIt = null;
AbstractUrlBasedView forwardView = null;
Action thisAction = null;
Forward forwardDef = null;
Map params = null;
try {
// Get DoIt
doIt = doItManager.getDoIt(doItId);
if(doIt == null) {
throw new BaseException("Can not find config for doit: " + doItId);
}
params = ParameterUtil.buildParameterMap(request);
componentRequestManager.set(request, response, params);
doItRunner.runDoIt(doIt, params, responseParams);
Iterator iter = responseParams.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
request.setAttribute((String)key, responseParams.get(key));
}
// Everything ran successfully. Forward to forward, if there
// is one defined.
String forwardName = getForward("forwardName", params);
if (forwardName == null) {
forwardName = "success";
}
forwardDef = getForward(doIt, forwardName);
if (forwardDef != null) {
forwardTo = ParameterUtil.resoveForwardPath(forwardDef, request.getParameterMap(), urlPath);
forwardView = new RedirectView(forwardTo, true);
}
//forwardParams.put("TToken", componentRequestManager.get().getParams().get(PlatformConstants.REQUEST_GUID));
} catch (Exception e) {
boolean validationError = false;
String forwardName = null;
if (e.getCause() instanceof ValidationException) {
validationError = true;
forwardParams.put(PresConstants.VALIDATION_ERROR_MESSAGES, responseParams.get(PresConstants.VALIDATION_ERROR_MESSAGES));
forwardParams.put(PresConstants.VALIDATION_ERROR_OBJECTS, responseParams.get(PresConstants.VALIDATION_ERROR_OBJECTS));
addErrorForwardParams(thisAction, forwardParams, forwardParams);
response.setHeader("toobs.error.validation", "true");
} else if (e.getCause() instanceof PermissionException) {
PermissionException pe = (PermissionException)e.getCause();
forwardName = pe.getReason() + "PermForward";
} else if(e instanceof BaseException){
request.setAttribute("userErrorMessages",((BaseException) e).getUserMessages());
}
request.setAttribute("org.toobs.exception", e);
log.error("Error running Action:", e);
if (forwardName == null) {
forwardName = getForward("errorForwardName", params);
if (forwardName == null) {
forwardName = getForward("errorForwardName", responseParams);
if (forwardName == null) {
forwardName = "error";
}
}
}
forwardDef = getForward(doIt, forwardName);
boolean forward = false;
if (forwardDef != null) {
forwardTo = ParameterUtil.resoveForwardPath(forwardDef, request.getParameterMap(), urlPath);
forward = forwardDef.getForward();
} else if (validationError) {
forwardTo = (String)request.getSession().getAttribute(PresConstants.SESSION_LAST_VIEW);
}
if (forwardTo == null || forwardTo.length() == 0) {
forwardTo = PresConstants.ERROR_FORWARD;
}
if (forward || validationError) {
forwardView = new InternalResourceView(forwardTo);
} else {
forwardView = new InternalResourceView(forwardTo);
//forwardView = new RedirectView(forwardTo, true);
}
} finally {
this.componentRequestManager.unset();
}
params = ParameterUtil.buildParameterMap(request);
if (forwardDef != null && forwardDef.getQueryParameterMapping() != null) {
try {
ParameterUtil.mapParameters("Forward:" + forwardDef.getUri(),forwardDef.getQueryParameterMapping().getParameter(), params, forwardParams, doIt.getName());
} catch (ParameterException e) {
log.error("Forward Parameter Mapping error " + e.getMessage(), e);
forwardView = new RedirectView(PresConstants.ERROR_FORWARD, true);
}
}
// Forward out.
if (forwardView != null) {
if (log.isDebugEnabled()) {
log.debug("Forward To: " + (forwardDef != null ? forwardDef.getName() : "null") + " URI: " + (forwardView != null ? forwardView.getUrl() : "null"));
Iterator iter = forwardParams.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
log.debug(" Forward Param - name: " + entry.getKey() + " value: " + entry.getValue());
}
}
return new ModelAndView(forwardView, forwardParams);
} else {
return null;
}
}
private void addErrorForwardParams(Action actionDef, Map params, Map forwardParams) {
Map errorParams = (Map)params.get("ErrorForwardParams");
if (errorParams != null) {
String guid = (String)errorParams.get("guid");
if (guid != null && actionDef != null) {
forwardParams.put(
((String[])ParameterUtil.resolveParam(actionDef.getGuidParam(), params))[0],
guid);
}
Iterator iter = errorParams.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
Object value = errorParams.get(key);
forwardParams.put(key, value);
}
}
}
/**
* Extract the URL filename from the given request URI. Delegates to
* <code>WebUtils.extractViewNameFromUrlPath(String)</code>.
*
* @param uri
* the request URI (e.g. "/index.html")
* @return the extracted URI filename (e.g. "index")
* @see org.springframework.web.util.WebUtils#extractFilenameFromUrlPath
*/
protected String extractViewNameFromUrlPath(String uri) {
return WebUtils.extractFilenameFromUrlPath(uri);
}
private String getForward(String name, Map params) {
if (name == null || params == null) {
return null;
}
Object forward = params.get(name);
if (forward != null && forward.getClass().isArray()) {
return ((String[])forward)[0];
} else {
return (String)forward;
}
}
public IDoItRunner getDoItRunner() {
return doItRunner;
}
public void setDoItRunner(IDoItRunner doItRunner) {
this.doItRunner = doItRunner;
}
public ComponentRequestManager getComponentRequestManager() {
return componentRequestManager;
}
public void setComponentRequestManager(
ComponentRequestManager componentRequestManager) {
this.componentRequestManager = componentRequestManager;
}
public IDoItManager getDoItManager() {
return doItManager;
}
public void setDoItManager(IDoItManager doItManager) {
this.doItManager = doItManager;
}
}