Package com.subgraph.vega.impl.scanner.modules.scripting

Source Code of com.subgraph.vega.impl.scanner.modules.scripting.ScriptLoader

/*******************************************************************************
* Copyright (c) 2011 Subgraph.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Subgraph - initial API and implementation
******************************************************************************/
package com.subgraph.vega.impl.scanner.modules.scripting;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;

import com.subgraph.vega.api.scanner.modules.ModuleScriptType;
import com.subgraph.vega.impl.scanner.modules.scripting.ModuleValidator.ModuleValidationException;
import com.subgraph.vega.impl.scanner.modules.scripting.ScriptFile.CompileStatus;

public class ScriptLoader {
  private final Logger logger = Logger.getLogger("script-loader");
  private final Scriptable globalScope;
  private final File moduleRoot;
  private final PreludeLoader preludeLoader;
  private final ScriptCompiler moduleCompiler;
  private final boolean preludeLoadFailed;
 
  private final Map<File, ScriptedModule> modulePathMap = new HashMap<File, ScriptedModule>();
 
  /* Script files are tracked separately from modules mainly so that we can track files have failed to compile. */
  private final Map<File, ScriptFile> scriptPathMap = new HashMap<File, ScriptFile>();
 
  private final FileFilter scriptFilter = new FileFilter() {
    public boolean accept(File pathname) {
      return pathname.isFile() && pathname.getName().endsWith(".js");
    }
  };
 
  private final FileFilter directoryFilter = new FileFilter() {
    public boolean accept(File pathname) {
      return pathname.isDirectory();
    }
  };
 
  public ScriptLoader(File moduleRoot) {
    logger.info("Loading scripts from "+ moduleRoot.getAbsolutePath());
    this.moduleRoot = moduleRoot;
    enableDynamicScope();
    globalScope = createGlobalScope();
    preludeLoader = new PreludeLoader(new File(moduleRoot, "prelude"), globalScope);
    preludeLoadFailed = (preludeLoader.load() == false);
    if(preludeLoadFailed)
      moduleCompiler = null;
    else
      moduleCompiler = new ScriptCompiler(preludeLoader.getPreludeScope());
  }
 
  private void enableDynamicScope() {
    ContextFactory.initGlobal(new ContextFactory() {
      @Override
      protected boolean hasFeature(Context cx, int featureIndex) {
        if(featureIndex == Context.FEATURE_DYNAMIC_SCOPE)
          return true;
        else
          return super.hasFeature(cx, featureIndex);
      }
    });
  }
 
  private Scriptable createGlobalScope() {
    try {
      final Context cx = Context.enter();
      final ScriptableObject importer = new ImporterTopLevel(cx, true);
      return cx.initStandardObjects(importer, true);
    } finally {
      Context.exit();
    }
  }
 
  public List<ScriptedModule> getAllModulesByType(ModuleScriptType type) {
    final List<ScriptedModule> result = new ArrayList<ScriptedModule>();
    synchronized(modulePathMap) {
      for(ScriptedModule m: modulePathMap.values()) {
        if(!m.isDisabled() && (type == null || type == m.getModuleType())) {
          result.add(m);
        }
      }
    }
    return result;
  }

  public List<ScriptedModule> getAllModules() {
    return getAllModulesByType(null);
  }
 
  public Scriptable getPreludeScope() {
    return preludeLoader.getPreludeScope();
  }

  private ScriptedModule compileModuleScript(ScriptFile scriptFile) {
    final ModuleValidator validator = compileAndValidate(scriptFile);
    if(validator == null) {
      return null;
    }
    return new ScriptedModule(scriptFile, validator);
  }
 
  private boolean recompileModule(ScriptedModule module) {
    final ModuleValidator validator = compileAndValidate(module.getScriptFile());
    if(validator == null)
      return false;
    module.updateFromValidator(validator);
    return true;
  }
 
  private ModuleValidator compileAndValidate(ScriptFile scriptFile) {
    if(!moduleCompiler.compile(scriptFile) || scriptFile.getCompileStatus() != CompileStatus.COMPILE_SUCCEEDED) {
      logger.warning(scriptFile.getCompileFailureMessage());
      return null;
    }
    return validateModule(scriptFile.getCompiledScript(), scriptFile.getPath());
  }

  private ModuleValidator validateModule(Scriptable module, String modulePath) {
    final ModuleValidator validator = new ModuleValidator(module);
    try {
      validator.validate();
      return validator;
    } catch (ModuleValidationException e) {
      logger.warning("Failed to validate module script "+ modulePath +" :"+ e.getMessage());
      return null;
    }
  }
 
  private List<File> allScriptPaths() {
    final File scriptRoot = new File(moduleRoot, "modules");
    final List<File> scriptFiles = new ArrayList<File>();
    crawlDirectory(scriptRoot, scriptFiles);
    return scriptFiles;
  }
 
  private void crawlDirectory(File dir, List<File> files) {
    for(File f: dir.listFiles(scriptFilter)) {
      files.add(f);
    }
   
    for(File d: dir.listFiles(directoryFilter)) {
      crawlDirectory(d, files);
    }
  }
 
  public boolean reloadModules() {
    boolean somethingChanged = false;
    if(preludeLoadFailed) {
      return false;
    }

    synchronized(modulePathMap) {
      synchronizeScriptPaths();
      for(Map.Entry<File, ScriptFile> entry: scriptPathMap.entrySet()) {
        if(compileScriptFileIfNeeded(entry.getKey(), entry.getValue())) {
          somethingChanged = true;
        }
      }
    }
    return somethingChanged;
  }

  private void synchronizeScriptPaths() {
    final Set<File> pathSet = new HashSet<File>();

    for(File path: allScriptPaths()) {
      pathSet.add(path);
      if(!scriptPathMap.containsKey(path)) {
        scriptPathMap.put(path, new ScriptFile(path));
      }
    }

    final List<File> keys = new ArrayList<File>(scriptPathMap.keySet());
    for(File path: keys) {
      if(!pathSet.contains(path)) {
        modulePathMap.remove(path);
        scriptPathMap.remove(path);
      }
    }
  }

  private boolean compileScriptFileIfNeeded(File path, ScriptFile scriptFile) {
    if(!isCompileNeeded(scriptFile)) {
      return false;
    }

    if(modulePathMap.containsKey(path)) {
      if(!recompileModule(modulePathMap.get(path))) {
        modulePathMap.remove(path);
      }
    } else {
      final ScriptedModule module = compileModuleScript(scriptFile);
      if(module != null) {
        modulePathMap.put(path, module);
      }
    }
    return true;
  }

  private boolean isCompileNeeded(ScriptFile scriptFile) {
    return ((scriptFile.getCompileStatus() == CompileStatus.NOT_COMPILED) || scriptFile.hasFileChanged());
  }
}
TOP

Related Classes of com.subgraph.vega.impl.scanner.modules.scripting.ScriptLoader

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.