Package org.persvr.javascript

Source Code of org.persvr.javascript.ModuleLoader

package org.persvr.javascript;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
import java.util.regex.Pattern;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.persvr.data.DataSourceManager;
import org.persvr.data.GlobalData;
import org.persvr.data.PersistableClass;
import org.persvr.data.Transaction;

public class ModuleLoader extends PersevereNativeFunction {
  String currentJslibPath = "";
  // create the require function so dependencies can be done in proper order
  Map<File,ScriptableObject> exports = new HashMap<File,ScriptableObject>();
  ScriptableObject global = GlobalData.getGlobalScope();
  Log log = LogFactory.getLog(ModuleLoader.class);
  Map<File, Long> lastTimeStamps = new HashMap<File, Long>();
  NativeArray pathsArray;
  NativeArray autoLoadArray;
  public ModuleLoader(){
    global.put("require", global, this);
    global.setAttributes("require", ScriptableObject.PERMANENT);
  }
  public void providePaths(Object[] paths){
    pathsArray = new NativeArray(paths);
    ScriptRuntime.setObjectProtoAndParent((ScriptableObject) pathsArray, global);
    autoLoadArray = new NativeArray(paths.length == 1 ? new Object[]{true} : new Object[]{true, true});
    ScriptRuntime.setObjectProtoAndParent((ScriptableObject) autoLoadArray, global);
    this.put("paths", this, pathsArray);
    this.setAttributes("paths", ScriptableObject.PERMANENT);
    this.put("autoLoad", this, autoLoadArray);
    this.setAttributes("autoLoad", ScriptableObject.PERMANENT);
  }
  public void scanForFiles(){
    PersistableClass.persistClass.set(false);
    for(int i = 0; i < pathsArray.getLength(); i++){
      String path = pathsArray.get(i, pathsArray).toString();
      if(Boolean.TRUE.equals(autoLoadArray.get(i, autoLoadArray))){
        for(File file : DataSourceManager.getConfigFiles(new File(path))){
          try {
            call(PersevereContextFactory.getContext(), global, global, new Object[]{file});
          } catch (RhinoException e) {
            log.error(e.details() + " on line " + e.lineNumber() + " in " + e.sourceName() + '\n'+ e.getScriptStackTrace());
          } catch (Throwable e) {
            throw new RuntimeException("Trying to load " + file.getAbsolutePath(), e);
          }
        }
      }
    }
  }
  @Override
  synchronized public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
    Transaction previousTransaction = Transaction.currentTransaction();
    int pathsCount = (int) pathsArray.getLength();
    File jslibFile = null;
    String filename;
    String oldJsLibPath = currentJslibPath;
    ScriptableObject exportObject;
    try {
      if(args[0] instanceof File){
        jslibFile = (File) args[0];
        filename = jslibFile.getCanonicalPath();
        filename = filename.replace(File.separatorChar, '/');
        for(int i = 0; i < pathsCount; i++){
          String path = pathsArray.get(i, pathsArray).toString();
          path = new File(path).getCanonicalPath().replace(File.separatorChar, '/');
          if(path.length() > 0 && !(path.endsWith("/") || path.endsWith(File.separator)))
            path += '/';
          if(filename.indexOf(path) > -1){
            filename = filename.substring(filename.indexOf(path) + path.length());
            break;
          }
        }
      }
      else {
        filename = args[0].toString();
        if(filename.startsWith("."))
          filename = currentJslibPath + filename;
        filename = Pattern.compile("[^\\/]*\\/\\.\\.\\/").matcher(filename).replaceAll("");
        filename = filename.replace("./", "");
        for(int i = 0; i < pathsCount; i++){
          String path = pathsArray.get(i, pathsArray).toString();
          if(path.length() > 0 && !(path.endsWith("/") || path.endsWith(File.separator)))
            path += '/';
          jslibFile = new File(path + filename);
          if(jslibFile.isFile())
            break;
          if(!filename.endsWith(".js")){
            filename += ".js";
            jslibFile = new File(path + filename);
            if(jslibFile.isFile())
              break;
          }
        }
      }
      String id = filename;
      if (filename.endsWith(".js"))
        id = filename.substring(0, filename.length() - 3);
      if(jslibFile == null || !jslibFile.isFile())
        throw ScriptRuntime.constructError("Error", "File not found " + filename);
      exportObject = exports.get(jslibFile);
      Long lastTimeStamp = lastTimeStamps.get(jslibFile);
      if(lastTimeStamp == null || lastTimeStamp < jslibFile.lastModified()){
        Transaction.startTransaction();
        lastTimeStamps.put(jslibFile, jslibFile.lastModified());
        FileInputStream inStream = new FileInputStream(jslibFile);
        exportObject = new NativeObject();
        ScriptRuntime.setObjectProtoAndParent((ScriptableObject) exportObject, global);
        ScriptableObject moduleObject = new NativeObject();
        ScriptRuntime.setObjectProtoAndParent((ScriptableObject) moduleObject, global);
        moduleObject.put("id", moduleObject, id);
        // setup the module scope
        ScriptableObject moduleScope = new NativeObject();
        moduleScope.setParentScope(global);
        int lastSlash = filename.lastIndexOf('/');
        currentJslibPath = lastSlash == -1 ? "" : filename.substring(0,lastSlash + 1);
        moduleScope.put("exports", moduleScope, exportObject);
        moduleScope.put("module", moduleScope, moduleObject);
        // memoize
        exports.put(jslibFile, exportObject);
        // evaluate the script
        try {
          cx.evaluateString(moduleScope, IOUtils.toString(inStream, "UTF-8"), filename, 1, null);
        } catch (RuntimeException e) {
          // revert
          exports.remove(jslibFile);
          throw e;
        }
        // re-retrieve it in case the library changed it
        exportObject = (ScriptableObject) moduleScope.get("exports", moduleScope);
        exports.put(jslibFile, exportObject);

        if("jsgi-app.js".equals(filename)){
          // handle jackconfig.js, setting up the app if it is there
          global.put("app", global, exportObject.get("app", exportObject));
        }
        // freeze it
        //exportObject.sealObject();
        Transaction.currentTransaction().commit();
      }
    } catch (IOException e) {
      throw ScriptRuntime.constructError("Error",e.getMessage());
    }
    finally{
      currentJslibPath = oldJsLibPath;
      previousTransaction.enterTransaction();
    }
    return exportObject;
  }
  public void freezeExports(){
    throw new RuntimeException("not implemented");
    /*
    for(String filename : new HashSet<String>(jslibFiles.keySet())){
      try {
        ScriptableObject exportObject = (ScriptableObject) call(PersevereContextFactory.getContext(), global, global, new Object[]{filename});
        exportObject.sealObject();
      } catch (RhinoException e) {
        log.error(e.details() + " on line " + e.lineNumber() + " in " + e.sourceName() + '\n'+ e.getScriptStackTrace());
      }
    }
*/
  }
  public void startTimer(){
    GlobalData.jsTimer.schedule(new TimerTask(){

      @Override
      public void run() {
        try{
          scanForFiles();
        } catch (Throwable e){
          log.error(e);
        }
      }
     
    }, 1000, 500);
  }
}
TOP

Related Classes of org.persvr.javascript.ModuleLoader

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.