Package org.zkoss.zest.sys

Source Code of org.zkoss.zest.sys.ZestManager

/* ZestManager.java

  Purpose:
   
  Description:
   
  History:
    Thu Mar  3 12:12:24 TST 2011, Created by tomyeh

Copyright (C) 2011 Potix Corporation. All Rights Reserved.

*/
package org.zkoss.zest.sys;

import java.util.Map;
import java.util.Iterator;
import java.net.URL;
import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.zkoss.lang.reflect.Fields;
import org.zkoss.util.logging.Log;
import org.zkoss.web.servlet.http.Https;
import org.zkoss.web.util.resource.ServletContextLocator;

import org.zkoss.zest.ActionContext;
import org.zkoss.zest.ZestException;
import org.zkoss.zest.ParameterIgnored;
import org.zkoss.zest.annotation.ActionType;
import org.zkoss.zest.sys.impl.ActionContextImpl;

/**
* The core of ZEST that matches URL, instantiates actions, invokes actions and
* forwards to a view.
*
* <p>By default, the manager ignores a path if its extension does not
* match any of the allowed extensions. If you'd like more complex
* algorithm to decide which to ignore, you could override {@link #pathIgnored}.
*
* @author tomyeh
*/
public class ZestManager {
  private static final Log log = Log.lookup(ZestManager.class);
  private static final String ATTR_MANAGER = "org.zkoss.zest.sys.manager";

  private ServletContext _ctx;
  private Configuration _config;
  private String[] _exts;

  /** Returns the manager associated with the context, or null
   * if not initialized yet.
   */
  public static ZestManager getManager(ServletContext ctx) {
    return (ZestManager)ctx.getAttribute(ATTR_MANAGER);
  }

  /** Constructor.
   */
  public ZestManager() {
  }
  /** Initializes the manager.
   *
   * @param parser the parser used to parse the configuration file (/WEB-INF/zest.xml)
   */
  public void init(ServletContext ctx, Parser parser) {
    _ctx = ctx;
    loadConfiguration(parser, "/WEB-INF/zest.xml");
    ctx.setAttribute(ATTR_MANAGER, this);
    log.info("ZEST initialized");
  }
  /** Destroyes the manager.
   */
  public void destroy() {
  }
  /** Returns the servlet context that this manager is associated with
   * @since 1.1.0
   */
  public ServletContext getServletContext() {
    return _ctx;
  }
  /** Loads the configuration.
   * This method is usually called automatically.
   * However, you could invoke it if you'd like to reload the configuration
   * (such as when you modify <code>/WEB-INF/zest.xml</code>)
   * @param configURI the URI of the configuration file, such as
   * (<code>/WEB-INF/zest.xml</code>).
   */
  public void loadConfiguration(Parser parser, String configURI) {
    try {
      final URL url = _ctx.getResource(configURI);
      if (url == null) {
        _config = null;
        log.info("File not found: "+ configURI);
      } else {
        _config = parser.parse(url, new ServletContextLocator(_ctx));
      }
    } catch (Throwable ex) {
      throw ZestException.Aide.wrap(ex, "Unable to load " + configURI);
    }
  }
  /** Handles the action.
   * It first identifies any action that matches the request, and then
   * instantiates/invoke the matched action and forward to the view.
   * @return whether it is mapped to an action (and then handled).
   */
  public boolean action(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {
    if (_config == null)
      return false;

    String s = request.getPathInfo();
    if (s == null || s.length() == 0)
      s = request.getServletPath();
    if (pathIgnored(s, _config.getExtensions()))
      return false;

    final ActionContext ac = new ActionContextImpl(request, response,
      _config.getVariableResolver(), _config.getFunctionMapper());
    final ActionDefinition[] defs = _config.getActionDefinitions();
    for (int j = 0; j < defs.length; ++j) {
      final ActionDefinition def = defs[j];
      Object action = null;
      try {
        action = def.getAction(ac);
        if (action != null) {
          request.setAttribute("action", action);
          if (!parameterIgnored(action))
            coerceParameters(ac, action);
          final String result = def.execute(ac, action);
          request.setAttribute("result", result);
          final ViewInfo viewInfo = def.getViewInfo(ac, result);
          if (viewInfo == null)
            throw new ZestException("No information specified for "+action+" under result is "+result+", when handling "+ac.getRequestPath());
          switch (viewInfo.getViewType()) {
          case REDIRECT:
            Https.sendRedirect(_ctx, request, response, viewInfo.getURI(), null, 0);
            break;
          case ERROR:
            final String msg = viewInfo.getErrorMessage();
            if (msg != null)
              response.sendError(viewInfo.getErrorCode(), msg);
            else
              response.sendError(viewInfo.getErrorCode());
          case DONE:
            break;
          default:
            Https.forward(_ctx, request, response, viewInfo.getURI());
            break;
          }
          return true;
        }
      } catch (Throwable ex) {
        try {
          _config.getErrorHandler().onError(ac, action, ex);
        } catch (ServletException t) {
          throw (ServletException)t;
        } catch (IOException t) {
          throw (IOException)t;
        } catch (Throwable t) {
          throw ZestException.Aide.wrap(t, "Failed to handle "+ac.getRequestPath());
        }
      }
    }
    return false;
  }
  private static boolean parameterIgnored(Object action) {
    if (action instanceof ParameterIgnored)
      return true;
    ActionType annot = action.getClass().getAnnotation(ActionType.class);
    return annot != null && annot.parameterIgnored();
  }
  /** Coerces the request's parameters to action's corresponding fields.
   */
  protected void coerceParameters(ActionContext ac, Object action)
  throws Throwable {
    for (Iterator it = ac.getServletRequest().getParameterMap().entrySet().iterator();
    it.hasNext();) {
      final Map.Entry me = (Map.Entry)it.next();
      final String nm = (String)me.getKey();
      final String[] vals = (String[])me.getValue();
      for (int j = 0; j < vals.length; ++j) {
        try {
          Fields.setByCompound(action, nm, vals[j], true);
        } catch (Throwable ex) {
          _config.getErrorHandler()
            .onParamError(ac, action, nm, vals[j], ex);
        }
      }
    }
  }
  private boolean pathIgnored(String path, String[] allowedExts) {
    String ext = "";
    for (int j = path.length(); --j >= 0;) {
      final char cc = path.charAt(j);
      if (cc == '.') {
        ext = path.substring(j);
        break;
      }
      if (cc == '/')
        break; //no extension
    }
    return pathIgnored(path, ext, allowedExts);
 
  /** Returns whether the given path shall be ignored.
   * <p>Default: the path is ignored if the extension does not match one of
   * the given allowed extensions.
   * @param path the given path to test
   * @param extension the extension of the path (it is part of path).
   * It is an empty string if there is no extension.
   * @param allowedExts the allowed extension. If null or zero-length,
   * it means all paths are allowed.
   * @since 1.1.0
   */
  protected
  boolean pathIgnored(String path, String extension, String[] allowedExts) {
    if (allowedExts != null)
      for (int j = 0; j < allowedExts.length; ++j)
        if (extension.equals(allowedExts[j]))
          return false; //matached
    return true;
  }
}
TOP

Related Classes of org.zkoss.zest.sys.ZestManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.