Package cn.bran.play

Source Code of cn.bran.play.JapidPlayRenderer

package cn.bran.play;

import japidviews.error500ForPlay;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import play.Play;
import play.Play.Mode;
import play.classloading.ApplicationClassloader;
import play.classloading.ApplicationClassloaderState;
import play.data.validation.Validation;
import play.exceptions.CompilationException;
import play.templates.JavaExtensions;
import play.vfs.VirtualFile;
import cn.bran.japid.compiler.JapidCompilationException;
import cn.bran.japid.compiler.TranslateTemplateTask;
import cn.bran.japid.exceptions.JapidTemplateException;
import cn.bran.japid.rendererloader.RendererClass;
import cn.bran.japid.rendererloader.RendererCompiler;
import cn.bran.japid.rendererloader.TemplateClassLoader;
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.JapidFlags;
import cn.bran.japid.util.RenderInvokerUtils;
import cn.bran.japid.util.StackTraceUtils;
import cn.bran.play.rendererloader.TemplateClassLoaderWithPlay;
import cn.bran.play.util.PlayDirUtil;

/**
*
* @author bran
*
*/
public class JapidPlayRenderer {

  public static JapidTemplateBaseWithoutPlay getRenderer(String name) {
    Class<? extends JapidTemplateBaseWithoutPlay> c = getTemplateClass(name);
    try {
      return c.newInstance();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  private static ApplicationClassloader playClassloader;
  private static boolean classesInited = false;
  private static ApplicationClassloaderState lastPlayClassLoaderState;

  /**
   * Get a newly loaded class for the template renderer
   *
   * @param name
   * @return
   */
  public static Class<? extends JapidTemplateBaseWithoutPlay> getTemplateClass(String name) {
    refreshClasses(/* name */);

    RendererClass rc = japidClasses.get(name);
    if (rc == null)
      throw new RuntimeException("Japid template class not found: " + name);
    else {
      if (isDevMode() && playClassloaderChanged()) {
        // always clear the mark to redefine all
        for (String c : japidClasses.keySet()) {
          japidClasses.get(c).setLastUpdated(0);
        }
        initJapidClassLoader();
      } else {
        if (rc.getLastUpdated() > 0 && rc.getClz() != null) {
          return rc.getClz();
        }
      }
    }

    // do I need to new instance of TemplateClassLoader for each invocation?
    // likely...
    // XXX why new instance each time?
//    TemplateClassLoaderWithPlay classReloader = new TemplateClassLoaderWithPlay(Play.classloader);

    try {
      return (Class<? extends JapidTemplateBaseWithoutPlay>) japidClassLoader.loadClass(name);
    } catch (ClassNotFoundException e) {
      throw new RuntimeException(e);
    }

  }

  private static void resetAllRenderClassUpdatedTime() {
    // always clear the mark to reload all
//    japidClasses.forEach((k, v )-> v.setLastUpdated(0));
    for (String c : japidClasses.keySet()) {
      japidClasses.get(c).setLastUpdated(0);
    }
  }

  /**
   * @author Bing Ran (bing.ran@hotmail.com)
   * @return
   */
  private static boolean playClassloaderChanged() {
    if (play.Play.classloader != playClassloader || lastPlayClassLoaderState == null
        || lastPlayClassLoaderState != play.Play.classloader.currentState) {
      playClassloader = play.Play.classloader;
      lastPlayClassLoaderState = play.Play.classloader.currentState;
      return true;
    } else
      return false;
  }

  static boolean timeToRefresh() {
    if (!isDevMode())
      return false;

    long now = System.currentTimeMillis();
    if (now - lastRefreshed > refreshInterval) {
      lastRefreshed = now;
      return true;
    } else
      return false;

  }

  static synchronized void refreshClasses() {
    if (classesInited) {
      if (!timeToRefresh())
        return;
    } else {
      JapidFlags.info("Japid scripts not loaded yet. Initializing them...");
    }

    try {
      // PlayDirUtil.mkdir(templateRoot);
      // find out all removed classes
      List<String> allTemps = isDevMode() ? DirUtil.getAllTemplateFiles(new File(defaultTemplateRoot)) : DirUtil
          .getAllTemplateFilesJavaFiles(new File(defaultTemplateRoot));
      Set<String> currentClassesOnDir = createNameSet(allTemps);
      Set<String> allNames = new HashSet<String>(currentClassesOnDir);

      Set<String> keySet = japidClasses.keySet();
      allNames.removeAll(keySet); // got new templates

      removeRemoved(currentClassesOnDir, keySet);

      for (String c : allNames) {
        RendererClass rc = newRendererClass(c);
        japidClasses.put(c, rc);
      }
      // now all the class set size is up to date

      // now update any Java source code
      List<File> gen = gen(defaultTemplateRoot);

      // this would include both new and updated java
      Set<String> updatedClasses = new HashSet<String>();
      if (gen.size() > 0) {
        for (File f : gen) {
          String className = getClassName(f);
          updatedClasses.add(className);
          RendererClass rendererClass = japidClasses.get(className);
          if (rendererClass == null) {
            // this should not happen, since
            throw new RuntimeException("any new class names should have been in the classes container: "
                + className);
            // rendererClass = newRendererClass(className);
            // classes.put(className, rendererClass);
          }

          JapidRenderer.setSources(rendererClass, f);
          removeInnerClasses(className);
          cleanClassHolder(rendererClass);
        }
      }

      // find all render class without bytecode
      for (Iterator<String> i = japidClasses.keySet().iterator(); i.hasNext();) {
        String k = i.next();
        RendererClass rc = japidClasses.get(k);
        if (rc.getSourceCode() == null) {
          if (!rc.getClassName().contains("$")) {
            String pathname = defaultTemplateRoot + sep + k.replace(".", sep);
            File f = new File(pathname + ".java");
            JapidRenderer.setSources(rc, f);
            cleanClassHolder(rc);
            updatedClasses.add(k);
          } else {
            rc.setLastUpdated(0);
          }
        } else {
          if (rc.getBytecode() == null) {
            cleanClassHolder(rc);
            updatedClasses.add(k);
          }
        }
      }

      // compile all
      if (updatedClasses.size() > 0) {
        String[] names = new String[updatedClasses.size()];
        int i = 0;
        for (String s : updatedClasses) {
          names[i++] = s;
        }
        long t = System.currentTimeMillis();
        // newly compiled class bytecode bodies are set in the global
        // classes set ready for defining
        compiler.compile(names);
       
        initJapidClassLoader();
        for (RendererClass rc :  japidClasses.values()) {
          try {
            if (isDevMode())
              rc.setClz(null); // to enable JIT loading in DEV mode
            else
              rc.setClz((Class<JapidTemplateBaseWithoutPlay>) japidClassLoader.loadClass(rc.getClassName()));
          } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
          }
        }
       
        howlong("compile/load time for " + names.length + " classe(s)", t);

        classesInited = true;
      }
    } catch (JapidCompilationException e) {
      if (presentErrorInHtml)
        throw e;

      String tempName = e.getTemplateName();
      if (tempName.startsWith(defaultTemplateRoot)) {
      } else {
        tempName = defaultTemplateRoot + File.separator + tempName;
      }
      VirtualFile vf = VirtualFile.fromRelativePath(tempName);
      CompilationException ce = new CompilationException(vf, "\"" + e.getMessage() + "\"", e.getLineNumber(), 0,
          0);
      throw ce;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  private static void initJapidClassLoader() {
    japidClassLoader = new TemplateClassLoaderWithPlay(Play.classloader);
  }

  public static void removeInnerClasses(String className) {
    for (Iterator<String> i = japidClasses.keySet().iterator(); i.hasNext();) {
      String k = i.next();
      if (k.startsWith(className + "$")) {
        i.remove();
      }
    }
  }

  /**
   * @param currentClassesOnDir
   * @param keySet
   */
  public static void removeRemoved(Set<String> currentClassesOnDir, Set<String> keySet) {
    // need to consider inner classes
    // keySet.retainAll(currentClassesOnDir);

    for (Iterator<String> i = keySet.iterator(); i.hasNext();) {
      String k = i.next();
      int q = k.indexOf('$');
      if (q > 0) {
        k = k.substring(0, q);
      }
      if (!currentClassesOnDir.contains(k)) {
        i.remove();
      }
    }
  }

  // <classname RendererClass>
  public final static Map<String, RendererClass> japidClasses = new ConcurrentHashMap<String, RendererClass>();
  public static TemplateClassLoaderWithPlay japidClassLoader;

  public static TemplateClassLoaderWithPlay getCrlr() {
    return japidClassLoader;
  }

  public static RendererCompiler compiler;
  public static String defaultTemplateRoot = "japidroot";
  public static final String JAPIDVIEWS = "japidviews";
  public static String sep = File.separator;
  public static String japidviews = defaultTemplateRoot + sep + JAPIDVIEWS + sep;
  // such as java.utils.*
  public static List<String> importlines = new ArrayList<String>();
  public static int refreshInterval;
  public static long lastRefreshed = 0;
  // private static boolean inited;

  private static boolean usePlay = true;

  // to override Play's mode when set
  private static Mode mode;
  private static boolean presentErrorInHtml = true;

  public static Mode getMode() {
    if (mode == null)
      return play.Play.mode;
    else
      return mode;
  }

  static void howlong(String string, long t) {
    JapidFlags.debug(string + ":" + (System.currentTimeMillis() - t) + "ms");
  }

  /**
   * @param rendererClass
   */
  static void cleanClassHolder(RendererClass rendererClass) {
    rendererClass.setBytecode(null);
    rendererClass.setClz(null);
    rendererClass.setLastUpdated(0);
  }

  static Set<String> createNameSet(List<String> allHtml) {
    // the names start with template root
    Set<String> names = new HashSet<String>();
    for (String f : allHtml) {
      names.add(getClassName(new File(f)));
    }
    return names;
  }

  static String getSourceCode(String k) {
    String pathname = defaultTemplateRoot + sep + k.replace(".", sep);
    File f = new File(pathname + ".java");
    return readSource(f);
  }

  /**
   * @param c
   * @return
   */
  static RendererClass newRendererClass(String c) {
    RendererClass rc = new RendererClass();
    rc.setClassName(c);
    // the source code of the Java file might not be available yet
    // rc.setSourceCode(getSouceCode(c));
    rc.setLastUpdated(0);
    return rc;
  }

  public static String readSource(File f) {
    try {
      FileInputStream fis = new FileInputStream(f);
      BufferedInputStream bis = new BufferedInputStream(fis);
      BufferedReader br = new BufferedReader(new InputStreamReader(bis, "UTF-8"));
      StringBuilder b = new StringBuilder();
      String line = null;
      while ((line = br.readLine()) != null) {
        b.append(line + "\n");
      }
      br.close();
      return b.toString();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  static String getClassName(File f) {
    String path = f.getPath();
    String substring = path.substring(path.indexOf(JAPIDVIEWS));
    substring = substring.replace('/', '.').replace('\\', '.');
    substring = DirUtil.mapSrcToJava(substring);
    if (substring.endsWith(".java")) {
      substring = substring.substring(0, substring.length() - 5);
    } else {
      substring = DirUtil.mapSrcToJava(substring);
    }
    return substring;
  }

  /**
   * set the interval to check template changes.
   *
   * @param i
   *            the interval in seconds. Set it to {@link Integer.MAX_VALUE}
   *            to effectively disable refreshing
   */
  static void setRefreshInterval(int i) {
    refreshInterval = i * 1000;
  }

  static public void setTemplateRoot(String root) {
    if (new File(root).isAbsolute())
      defaultTemplateRoot = root;
    else
      defaultTemplateRoot = Play.applicationPath + sep + root;
    japidviews = defaultTemplateRoot + sep + JAPIDVIEWS + sep;
    JapidFlags.info("japid root is set to: " + defaultTemplateRoot);
  }

  /**
   * The entry point for the command line tool japid.bat and japid.sh
   *
   * The "gen" and "regen" are probably the most useful ones.
   *
   * @param args
   * @throws IOException
   */
  public static void main(String[] args) throws IOException {
    if (args.length > 0) {
      String arg0 = args[0];

      setTemplateRoot(".");
      if ("gen".equals(arg0)) {
        gen(defaultTemplateRoot);
      } else if ("regen".equals(arg0)) {
        regen(defaultTemplateRoot);
      } else if ("clean".equals(arg0)) {
        delAllGeneratedJava(getJapidviewsDir(defaultTemplateRoot));
      } else if ("mkdir".equals(arg0)) {
        mkdir(defaultTemplateRoot);
      } else if ("changed".equals(arg0)) {
        changed(japidviews);
      } else {
        System.err.println("help:  optionas are: gen, regen, mkdir and clean");
      }
    } else {
      System.err.println("help:  optionas are: gen, regen, mkdir and clean");
    }
  }

  private static void changed(String root) {
    List<File> changedFiles = DirUtil.findChangedSrcFiles(new File(root));
    for (File f : changedFiles) {
      System.out.println("changed: " + f.getPath());
    }

  }

  /**
   * create the basic layout: app/japidviews/_javatags app/japidviews/_layouts
   * app/japidviews/_tags
   *
   * then create a dir for each controller. //TODO
   *
   * @throws IOException
   *
   */
  static List<File> mkdir(String root) throws IOException {
    return PlayDirUtil.mkdir(root);
  }

  /**
   * @param root
   * @return
   */
  private static String getJapidviewsDir(String root) {
    return root + sep + JAPIDVIEWS + sep;
  }

  static void regen() throws IOException {
    regen(defaultTemplateRoot);
  }

  public static void regen(String root) throws IOException {
    delAllGeneratedJava(getJapidviewsDir(root));
    gen(root);
  }

  static void delAllGeneratedJava(String pathname) {
    String[] javas = DirUtil.getAllFileNames(new File(pathname), new String[] { "java" });

    for (String j : javas) {
      log("removed: " + pathname + j);
      boolean delete = new File(pathname + File.separatorChar + j).delete();
      if (!delete)
        throw new RuntimeException("file was not deleted: " + j);
    }
    // log("removed: all none java tag java files in " +
    // JapidPlugin.JAPIDVIEWS_ROOT);
  }

  /**
   * update the java files from the html files, for the changed only
   *
   * @throws IOException
   */
  static List<File> gen(String packageRoot) throws IOException {
    List<File> changedFiles = reloadChanged(packageRoot);
    if (changedFiles.size() > 0) {
      // for (File f : changedFiles) {
      // // log("updated: " + f.getName().replace("html", "java"));
      // }
    } else {
      // log("All Japid template files are synchronized.");
      if (JapidFlags.verbose)
        System.out.print(":");
    }

    if (isDevMode())
      rmOrphanJava(packageRoot);
    return changedFiles;
  }

  /**
   * @param root
   *            the package root "/"
   * @return the updated Java files.
   */
  static List<File> reloadChanged(String root) {
    try {
      mkdir(root);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    TranslateTemplateTask t = new TranslateTemplateTask();
    t.setUsePlay(usePlay);
    File rootDir = new File(root);
    t.setPackageRoot(rootDir);
    t.setInclude(new File(japidviews));
    if (DirUtil.hasLayouts(root))
      t.addImport("japidviews._layouts.*");
    if (DirUtil.hasJavaTags(root))
      t.addImport("japidviews._javatags.*");
    if (DirUtil.hasTags(root))
      t.addImport("japidviews._tags.*");

    for (String imp : importlines) {
      t.addImport(imp);
    }

    // since we're bound together with play:
    t.importStatic(JapidPlayAdapter.class);
    t.importStatic(Validation.class);
    t.importStatic(JavaExtensions.class);
    t.addImport("models.*");
    t.addImport("controllers.*");
    t.addImport(play.mvc.Scope.class.getName() + ".*");
    t.addImport(play.i18n.Messages.class);
    t.addImport(play.i18n.Lang.class);
    t.addImport(play.mvc.Http.class.getName() + ".*");
    t.addImport(Validation.class.getName());
    t.addImport(play.data.validation.Error.class.getName());
    List<String> javatags = DirUtil.scanJavaTags(root);
    for (String f : javatags) {
      t.addImport("static " + f + ".*");
    }

    t.execute();
    // List<File> changedFiles = t.getChangedFiles();
    return t.getChangedTargetFiles();
    // return changedFiles;
  }

  /**
   * get all the java files in a dir with the "java" removed
   *
   * @return
   */
  static File[] getAllJavaFilesInDir(String root) {
    // from source files only
    String[] allFiles = DirUtil.getAllFileNames(new File(root), new String[] { ".java" });
    File[] fs = new File[allFiles.length];
    int i = 0;
    for (String f : allFiles) {
      String path = f.replace(".java", "");
      fs[i++] = new File(path);
    }
    return fs;
  }

  /**
   * delete orphaned java artifacts from the japidviews directory
   *
   * @param packageRoot
   *
   * @return
   */
  static boolean rmOrphanJava(String packageRoot) {

    boolean hasRealOrphan = false;
    try {
      String pathname = getJapidviewsDir(packageRoot);
      File src = new File(pathname);
      if (!src.exists()) {
        log("Could not find required Japid root directory: " + pathname);
        return hasRealOrphan;
      }

      Set<File> oj = DirUtil.findOrphanJava(src, null);
      for (File j : oj) {
        String path = j.getPath();
        // JapidFlags.log("found: " + path);
        if (path.contains(DirUtil.JAVATAGS)) {
          JapidFlags
              .warn("using util classes in _javatags folder is deprecated and will not take effect in post-controller Japid mode. "
                  + "Please use Play app's standard app/utils folder and import the classes accordingly");
          // java tags, don't touch
        } else {
          hasRealOrphan = true;
          String realfile = pathname + File.separator + path;
          File file = new File(realfile);
          boolean r = file.delete();
          if (r)
            JapidFlags.debug("deleted orphan " + realfile);
          else
            JapidFlags.error("failed to delete: " + realfile);
        }
      }

    } catch (Exception e) {
      e.printStackTrace();
    }
    return hasRealOrphan;
  }

  static List<File> reloadChanged() {
    return reloadChanged(defaultTemplateRoot);
  }

  static void log(String m) {
    JapidFlags.error("[JapidPlayRenderer]: " + m);
  }

  static void gen() {
    if (defaultTemplateRoot == null) {
      throw new RuntimeException("the template root directory must be set");
    } else {
      try {
        gen(defaultTemplateRoot);
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

  // /**
  // * set to development mode
  // */
  // public static void setDevMode() {
  // devMode = true;
  // }

  // /**
  // * set to production mode
  // */
  // public static void setProdMode() {
  // devMode = false;
  // }
  //

  public static boolean isDevMode() {
    return getMode().isDev();
  }

  static String removeSemi(String imp) {
    imp = imp.trim();
    if (imp.endsWith(";")) {
      imp = imp.substring(0, imp.length() - 1);
    }
    return imp;
  }

  //
  // public <T extends JapidTemplateBaseWithoutPlay> String render(Class<T> c,
  // Object... args) {
  // int modifiers = c.getModifiers();
  // if (Modifier.isAbstract(modifiers)) {
  // throw new
  // RuntimeException("Cannot init the template class since it's an abstract class: "
  // + c.getName());
  // }
  // try {
  // Constructor<T> ctor = c.getConstructor(StringBuilder.class);
  // StringBuilder sb = new StringBuilder(8000);
  // T t = ctor.newInstance(sb);
  // RenderResult rr = RenderInvokerUtils.render(t, args);
  // return rr.getContent().toString();
  // } catch (NoSuchMethodException e) {
  // throw new
  // RuntimeException("Could not match the arguments with the template args.");
  // } catch (InstantiationException e) {
  // throw new
  // RuntimeException("Could not instantiate the template object. Abstract?");
  // } catch (Exception e) {
  // if (e instanceof RuntimeException)
  // throw (RuntimeException) e;
  // else
  // throw new RuntimeException("Could not invoke the template object: " + e);
  // }
  // }

  public static void addStaticImportLine(String imp) {
    importlines.add(" static " + removeSemi(imp));
  }

  /**
   *
   * @param imp
   *            the part after import, no ";"
   */
  public static void addImportLine(String imp) {
    importlines.add(removeSemi(imp));
  }

  /**
   * one of the ways to invoke a renderer
   *
   * @param cls
   * @param args
   * @return
   */
  public static String render(Class<? extends JapidTemplateBaseWithoutPlay> cls, Object... args) {
    RenderResult r = RenderInvokerUtils.invokeRender(cls, args);
    return r.getText();
  }

  /**
   * The <em>optional</em> initialization step in using the JapidRender.
   *
   * Users do not need to call this method to initialize this class. It takes
   * "japidroot" as the default template root, which is relative to the
   * application root.
   *
   * @param opMode
   *            the operational mode of Japid. When set to OpMode.prod, it's
   *            assumed that all Java derivatives are already been generated
   *            and used directly. When set to OpMode.dev, and using
   *            none-static linking to using the renderer, file system changes
   *            are detected for every rendering request given the refresh
   *            interval is respected. New Java files are generated and
   *            compiled and new classes are loaded to serve the request.
   * @param templateRoot
   *            the root directory to contain the "japidviews" directory tree.
   *            It must be out of the "app" directory, or it will interfere
   *            with Play's class loading.
   * @param refreshInterval
   *            the minimal time, in second, that must elapse before trying to
   *            detect any changes in the file system.
   */
  public static void init(Mode opMode, String templateRoot, int refreshInterval) {
    JapidFlags.info("JapidPlayRenderer initializing");
    mode = opMode;
    setTemplateRoot(templateRoot);
    setRefreshInterval(refreshInterval);
    initJapidClassLoader();
    compiler = new RendererCompiler(japidClasses, japidClassLoader);
    try {
      refreshClasses();
    } catch (Exception e) {
      JapidFlags
          .warn("There was an error in refreshing the japid classes. Will show the error in detail in processing a request: "
              + e);
    }
    JapidFlags.info("JapidPlayRenderer inited");
  }

  public static void init() {
    init(null, defaultTemplateRoot, 2);
  }

  static {
    init();
  }

  /**
   * a facet method to wrap implicit template binding. The default template is
   * named as the class and method that immediately invoke this method. e.g.
   * for an invocation scenario like this
   *
   * <pre>
   * package pack;
   *
   * public class Foo {
   *   public String bar() {
   *     return JapidRender.render(p);
   *   }
   * }
   * </pre>
   *
   * The template to use is "{templateRoot}/japidviews/pack/Foo/bar.html".
   *
   * @param p
   * @return
   */
  public static String render(Object... args) {
    String templateName = findTemplate();
    RenderResult r = JapidController.getRenderResultWith(templateName, args);
    return r.getText();
  }

  /**
   * render with the specified template.
   *
   * @param templateName
   *            The template must be rooted in the {templateRoot/}/japidviews
   *            tree. The template name starts with or without "japidviews".
   *            The naming pattern is the same as in
   *            ClassLoader.getResource().
   * @param args
   * @return the result string
   */
  public static String renderWith(String templateName, Object... args) {
    RenderResult r = JapidController.getRenderResultWith(templateName, args);
    return r.getText();
  }

  private static String findTemplate() {
    String japidRenderInvoker = StackTraceUtils.getJapidRenderInvoker();
    return japidRenderInvoker;
  }

  public static RenderResult handleException(Throwable e) throws RuntimeException {
    if (!presentErrorInHtml)
      if (e instanceof RuntimeException)
        throw (RuntimeException) e;
      else
        throw new RuntimeException(e);

    // if (Play.mode == Mode.PROD)
    // throw new RuntimeException(e);
    //
    Class<? extends JapidTemplateBaseWithoutPlay> rendererClass = getErrorRendererClass();

    if (e instanceof JapidTemplateException) {
      RenderResult rr = RenderInvokerUtils.invokeRender(rendererClass, (JapidTemplateException) e);
      return (rr);
    }

    if (e instanceof RuntimeException && e.getCause() != null)
      e = e.getCause();

    if (e instanceof JapidCompilationException) {
      JapidCompilationException jce = (JapidCompilationException) e;
      JapidTemplateException te = JapidTemplateException.from(jce);
      RenderResult rr = RenderInvokerUtils.invokeRender(rendererClass, te);
      return (rr);
    }

    e.printStackTrace();

    // find the latest japidviews exception or the controller that caused
    // the exception
    StackTraceElement[] stackTrace = e.getStackTrace();
    for (StackTraceElement ele : stackTrace) {
      String className = ele.getClassName();
      if (className.startsWith("japidviews")) {
        int lineNumber = ele.getLineNumber();
        RendererClass applicationClass = japidClasses.get(className);
        if (applicationClass != null) {
          // let's get the line of problem
          int oriLineNumber = applicationClass.mapJavaLineToJapidScriptLine(lineNumber);
          if (oriLineNumber > 0) {
            if (rendererClass != null) {
              String path = applicationClass.getOriSourceCode();
              JapidTemplateException te = new JapidTemplateException("Japid Error", path + "("
                  + oriLineNumber + "): " + e.getClass().getName() + ": " + e.getMessage(),
                  oriLineNumber, path, applicationClass.getOriSourceCode());
              RenderResult rr = RenderInvokerUtils.invokeRender(rendererClass, te);
              return (rr);
            }
          }
        }
      } else if (className.startsWith("controllers.")) {
        if (e instanceof RuntimeException)
          throw (RuntimeException) e;
        else
          throw new RuntimeException(e);
      }
    }

    JapidTemplateException te = new JapidTemplateException(e);
    RenderResult rr = RenderInvokerUtils.invokeRender(rendererClass, te);
    return rr;
    // if (e instanceof RuntimeException)
    // throw (RuntimeException) e;
    // else
    // throw new RuntimeException(e);
  }

  /**
   * @author Bing Ran (bing.ran@gmail.com)
   * @return
   */
  public static Class<? extends JapidTemplateBaseWithoutPlay> getErrorRendererClass() {
    // return devErrorClass;
    return japidviews.devError.class;
  }

  public static String renderPlayException(Exception e) {
    Exception exp = cn.bran.play.util.PlayExceptionUtils.mapJapidJavaCodeError(e);
    RenderResult rr = error500ForPlay.apply(exp);
    return rr.toString();
  }
}
TOP

Related Classes of cn.bran.play.JapidPlayRenderer

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.