Package cn.bran.play

Source Code of cn.bran.play.JapidController

package cn.bran.play;

import java.util.HashMap;
import java.util.Map;

import play.cache.Cache;
import play.data.Form;
import play.mvc.Controller;
import play.mvc.Http.Context;
import play.mvc.Result;
import play.mvc.Results;
import cn.bran.japid.compiler.NamedArgRuntime;
import cn.bran.japid.template.JapidRenderer;
import cn.bran.japid.template.JapidTemplateBaseWithoutPlay;
import cn.bran.japid.template.RenderResult;
import cn.bran.japid.util.DirUtil;
import cn.bran.japid.util.RenderInvokerUtils;
import cn.bran.japid.util.StackTraceUtils;

/**
* a helper class. for hiding the template API from user eyes. not really needed
* since the template invocation API is simple enough.
*
* @author Bing Ran<bing_ran@hotmail.com>
*/
public class JapidController extends Controller {
  public static ThreadLocal<Map<String, String>> threadData = new ThreadLocal<Map<String, String>>() {
    @Override
    protected Map<String, String> initialValue() {
      return new HashMap<String, String>();
    }
  };
 
  /**
   *
   */
  private static final String CONTROLLERS = "controllers.";
  public static final char DOT = '.';
  /**
   * render an array of objects to a template defined by a Template class.
   *
   * @param <T>
   *            a sub-class type of JapidTemplateBase
   * @param c
   *            a sub-class of JapidTemplateBase
   * @param args
   *            arguments
   */
  public static <T extends JapidTemplateBaseWithoutPlay> JapidResult render(Class<T> c, Object... args) {
    try {
      RenderResult rr = RenderInvokerUtils.invokeRender(c, args);
      JapidResult japidResult = new JapidResult(rr);
      postProcess(japidResult);
      return japidResult;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  private static JapidResult postProcess(JapidResult japidResult) {
    // XXX play2 does not guarantee the response
   
    if (Context.current.get() != null) {
      // apply headers
      try {
        Map<String, String> currentHeaders = response().getHeaders();

        Map<String, String> headers = japidResult.getHeaders();
        for (String k : headers.keySet()) {
          if (!currentHeaders.containsKey(k))
            response().setHeader(k, headers.get(k));
        }
      } catch (RuntimeException e) {
      }
    }

    // eagerly evaluate. The consequence is that there is no cache support
    // in each included part
    // no we need cache support
    return japidResult/* .eval() */;
  }

  /**
   * just hide the result throwing
   *
   * @param rr
   */
  protected static JapidResult render(RenderResult rr) {
    return postProcess(new JapidResult(rr));
  }

  /**
   * pickup the Japid renderer in the conventional location and render it.
   * Positional match is used to assign values to parameters
   *
   * TODO: the signature would be confusing for cases where there is a single
   * argument and the type is an array! In that case the user must cast it to
   * Object: <code>renderJapid((Object)myArray);</code>
   *
   * @param objects
   */
  public static JapidResult renderJapid(Object... objects) {
    String action = template("renderJapid");
    return renderJapidWith(action, objects);
  }

  public static JapidResult renderJapidByName(NamedArgRuntime... namedArgs) {
    String action = template("renderJapidByName");
    return renderJapidWith(action, namedArgs);
  }

  /**
   *
   * @author Bing Ran (bing.ran@hotmail.com)
   * @param templateName the script name or a fully qualified class name under which the renderer class
   * is registered.
   *
   * @param args
   * @return
   */
  public static JapidResult renderJapidWith(String templateName, Object... args) {
      templateName = getFullViewName(templateName);
      JapidResult japidResult = new JapidResult(JapidRenderer.renderWith(templateName, args));
      postProcess(japidResult);
      return japidResult;
  }

  private static JapidResult generateErrorResult(Exception e) {
    JapidResult result = new JapidResult(JapidRenderer.handleException(e));
    postProcess(result);
    return result;
  }

  /**
   * render data to a template string, which is parsed and compiled to Java bytecode before use.
   *
   * @author Bing Ran (bing.ran@hotmail.com)
   * @param template the content of the template
   * @param args the arguments
   * @return
   */
  public static JapidResult renderDynamic(String template, Object... args) {
    try {
      RenderResult rr = JapidRenderer.renderDynamic(template, args);
      return new JapidResult(rr);
    } catch (Throwable e) {
      return new JapidResult(JapidRenderer.handleException(e));
    }
  }
 
  public static JapidResult renderDynamicByKey(String key, Object... args) {
    try {
      RenderResult rr = JapidRenderer.renderDynamicByKey(key, args);
      return new JapidResult(rr);
    } catch (Throwable e) {
      return new JapidResult(JapidRenderer.handleException(e));
    }
  }
 
 
  private static String getFullViewName(String template) {
    if (template.startsWith("@")) {
      template = template.substring(1);
      // get parent path
      String defaultView = template("renderJapidWith");
      String parent = defaultView.substring(0, defaultView.lastIndexOf('.'));
      template = parent + "." + template;
    }
    return template;
  }

  public static JapidResult renderJapidWith(String template, NamedArgRuntime[] namedArgs) {
    template = getFullViewName(template);
    JapidResult japidResult = new JapidResult(JapidRenderer.getRenderResultWith(template, namedArgs));
    return postProcess(japidResult);
  }

  public static String template(String method) {
    // first check if there is a method hint in the session
    String japidControllerInvoker = threadData.get().remove(GlobalSettingsWithJapid.ACTION_METHOD);
    // use the thread local is not reliable nor correct if the action forwards to another action.
    // disable it
    if (true || japidControllerInvoker == null) {
      // return StackTraceUtils.getJapidRenderInvoker();
      japidControllerInvoker = StackTraceUtils.getJapidControllerInvoker(method);
    }

    if (japidControllerInvoker.startsWith(CONTROLLERS))
      japidControllerInvoker = japidControllerInvoker.substring(CONTROLLERS.length());

    String expr = japidControllerInvoker;

    // some content negotiation
    // TODO: shall we set the response content type accordingly?
    String format = resolveFormat(Context.current.get());
    if ("html".equals(format)) {
      return expr;
    } else {
      String expr_format = expr + "_" + format;
      try {
        Class<?> appClass = JapidRenderer.getClass(JapidRenderer.getTemplateClassName(expr_format));
        if (appClass != null)
          return expr_format;
        else {
          return expr;
        }
      } catch (RuntimeException e) {
        return expr;
      }
    }
  }

  public static String resolveFormat(Context context) {
    if (context == null)
      return "html";

    Map<String, String[]> headers = context.request().headers();
    String format = "html";

    if (headers.get("accept") == null && headers.get("Accept") == null && headers.get("ACCEPT") == null) {
      return format;
    }

    String accept = "";
    if (headers.get("accept") != null)
      accept = headers.get("accept")[0];
    else if (headers.get("Accept") != null)
      accept = headers.get("Accept")[0];
    else if (headers.get("ACCEPT") != null)
      accept = headers.get("ACCEPT")[0];

    if (accept.indexOf("application/xhtml") != -1 || accept.indexOf("text/html") != -1 || accept.startsWith("*/*")) {
      format = "html";
    } else if (accept.indexOf("application/xml") != -1 || accept.indexOf("text/xml") != -1) {
      format = "xml";
    } else if (accept.indexOf("text/plain") != -1) {
      format = "txt";
    } else if (accept.indexOf("application/json") != -1 || accept.indexOf("text/javascript") != -1) {
      format = "json";
    } else if (accept.endsWith("*/*")) {
      format = "html";
    }
    return format;
  }

  /**
   * mind the cost associated with this and the key building issues, as stated
   * in the cache() method
   *
   * @param objs
   * @return
   */

  protected static RenderResult getFromCache(Object... objs) {
    // the key building with caller info and the arguments
    if (RenderResultCache.shouldIgnoreCache())
      return null;
    String caller = buildKey(null, objs);
    Object object = Cache.get(caller);
    if (object instanceof RenderResult) {
      return (RenderResult) object;
    } else {
      return null;
    }
  }

  /**
   *
   * @param keyBase
   *            usually the fully qualified method name of the controller
   *            action
   * @param objs
   * @return
   */
  protected static RenderResult getFromCache(String keyBase, Object... objs) {
    // the key building with caller info and the arguments
    if (RenderResultCache.shouldIgnoreCache())
      return null;
    String caller = buildKey(keyBase, objs);
    Object object = Cache.get(caller);
    if (object instanceof RenderResult) {
      return (RenderResult) object;
    } else {
      return null;
    }
  }

  /**
   * @param objs
   * @return
   */
  private static String buildKey(String base, Object... objs) {
    // the getCaller thing is relatively expensive, as it might take
    // hundreds of us to complete.

    String caller = base;
    if (base == null)
      caller = StackTraceUtils.getCaller2(); // tricky and expensive
    for (Object o : objs) {
      caller += "-" + String.valueOf(o);
    }
    return caller;
  }

  /**
   * render a text in a RenderResult so it can work with invoke tag in
   * templates.
   *
   * @param s
   */
  protected static JapidResult renderText(String s) {
    Map<String, String> headers = new HashMap<String, String>();
    headers.put("Content-Type", "text/plain; charset=utf-8");
    return render(new RenderResult(headers, new StringBuilder(s), -1L));
  }

  protected static Result renderText(Object o) {
    String str = o == null ? "" : o.toString();
    return renderText(str);
  }

  protected static Result renderText(int o) {
    return renderText(new Integer(o));
  }

  protected static Result renderText(long o) {
    return renderText(new Long(o));
  }

  protected static Result renderText(float o) {
    return renderText(new Float(o));
  }

  protected static Result renderText(double o) {
    return renderText(new Double(o));
  }

  protected static Result renderText(boolean o) {
    return renderText(new Boolean(o));
  }

  protected static Result renderText(char o) {
    return renderText(new String(new char[] { o }));
  }

  protected static NamedArgRuntime named(String name, Object val) {
    return new NamedArgRuntime(name, val);
  }

  static String runnerName = CacheablePlayActionRunner.class.getName();

  /**
   * determine if the current stack frame is a descendant of
   * CacheablePlayActionRunner which is used when invoking actions from Japid
   * views
   *
   * @return
   */
  public static boolean isInvokedfromJapidView() {
    Throwable t = new Throwable();
    t.printStackTrace();
    final StackTraceElement[] ste = t.getStackTrace();
    for (int i = 0; i < ste.length; i++) {
      StackTraceElement st = ste[i];
      String className = st.getClassName();
      if (className.equals(runnerName)) {
        return true;
      }
    }
    return false;
  }

  /**
     * Instantiates a new authenticity checking form that wraps the specified class.
     */
    public static <T> Form<T> form(Class<T> clazz) {
        return new AuthenticForm<T>(clazz);
    }
   
    /**
     * Instantiates a new form that wraps the specified class.
     */
    public static <T> Form<T> form(String name, Class<T> clazz) {
        return new AuthenticForm<T>(name, clazz);
    }

    /**
     * wrap a RenderResult in an OK result.
     *
     * @author Bing Ran (bing.ran@gmail.com)
     * @param rr
     * @return
     */
    public static Result ok(RenderResult rr) {
      try {
      return new JapidResult(rr);
    } catch (Exception e) {
      return generateErrorResult(e);
    }
    }

  /**
   * find out if a Japid class denoted by the template name is available
   *
   * @author Bing Ran (bing.ran@gmail.com)
   * @param templateName
   * @return
   */
  public static boolean hasTemplate(String templateName) {
    return JapidRenderer.hasTemplate(templateName);
  }
 
  public static   Class<? extends JapidTemplateBaseWithoutPlay> getTemplateClass(String templateName) {
    return JapidRenderer.getTemplateClass(templateName);
  }
}
TOP

Related Classes of cn.bran.play.JapidController

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.