Package com.l2jfrozen.gameserver.scripting

Source Code of com.l2jfrozen.gameserver.scripting.L2ScriptEngineManager$CleaneCache

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* http://www.gnu.org/copyleft/gpl.html
*/
package com.l2jfrozen.gameserver.scripting;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InvalidClassException;
import java.io.LineNumberReader;
import java.io.ObjectInputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;

import javolution.util.FastMap;

import com.l2jfrozen.Config;
import com.l2jfrozen.gameserver.thread.ThreadPoolManager;
import com.l2jserver.script.jython.JythonScriptEngine;

/**
* Caches script engines and provides functionality for executing and managing scripts.<BR>
*
* @author KenM
*/
public final class L2ScriptEngineManager
{
  private static final Logger _log = Logger.getLogger(L2ScriptEngineManager.class.getName());

  public final static File SCRIPT_FOLDER = new File(Config.DATAPACK_ROOT.getAbsolutePath(), "data/scripts");

  public static L2ScriptEngineManager getInstance()
  {
    return SingletonHolder._instance;
  }

  private final Map<String, ScriptEngine> _nameEngines = new FastMap<String, ScriptEngine>();
  private final Map<String, ScriptEngine> _extEngines = new FastMap<String, ScriptEngine>();
  private final List<ScriptManager<?>> _scriptManagers = new LinkedList<ScriptManager<?>>();

  private final CompiledScriptCache _cache;

  private File _currentLoadingScript;

  private L2ScriptEngineManager()
  {
    ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
    List<ScriptEngineFactory> factories = scriptEngineManager.getEngineFactories();
    if(Config.SCRIPT_CACHE)
    {
      _cache = loadCompiledScriptCache();
    }
    else
    {
      _cache = null;
    }
    ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new CleaneCache(), 43200000, 43200000);
    _log.info("Initializing Script Engine Manager");

    for(ScriptEngineFactory factory : factories)
    {
      try
      {
        ScriptEngine engine = factory.getScriptEngine();
        boolean reg = false;
        for(String name : factory.getNames())
        {
          ScriptEngine existentEngine = _nameEngines.get(name);

          if(existentEngine != null)
          {
            double engineVer = Double.parseDouble(factory.getEngineVersion());
            double existentEngVer = Double.parseDouble(existentEngine.getFactory().getEngineVersion());

            if(engineVer <= existentEngVer)
            {
              continue;
            }
          }

          reg = true;
          _nameEngines.put(name, engine);
        }

        if(reg)
        {
          _log.info("Script Engine: " + factory.getEngineName() + " " + factory.getEngineVersion() + " - Language: " + factory.getLanguageName() + " - Language Version: " + factory.getLanguageVersion());
        }

        for(String ext : factory.getExtensions())
        {
          if(!ext.equals("java") || factory.getLanguageName().equals("java"))
          {
            _extEngines.put(ext, engine);
          }
        }
      }
      catch(Exception e)
      {
        _log.warning("Failed initializing factory. ");
        e.printStackTrace();
      }
    }

    preConfigure();
  }

  private void preConfigure()
  {
    // Jython sys.path
    String dataPackDirForwardSlashes = SCRIPT_FOLDER.getPath().replaceAll("\\\\", "/");
    String configScript = "import sys;sys.path.insert(0,'" + dataPackDirForwardSlashes + "');";
    try
    {
      this.eval("jython", configScript);
    }
    catch(ScriptException e)
    {
      if(Config.ENABLE_ALL_EXCEPTIONS)
        e.printStackTrace();
     
      _log.severe("Failed preconfiguring jython: " + e.getMessage());
    }
  }

  private ScriptEngine getEngineByName(String name)
  {
    return _nameEngines.get(name);
  }

  private ScriptEngine getEngineByExtension(String ext)
  {
    return _extEngines.get(ext);
  }

  public void executeScriptsList(File list) throws IllegalArgumentException
  {
    if(list.isFile())
    {
      FileInputStream reader = null;
      InputStreamReader buff = null;
      LineNumberReader lnr = null;
     
      try
      {
        reader = new FileInputStream(list);
        buff = new InputStreamReader(reader);
        lnr = new LineNumberReader(buff);

        String line;
        File file;

        while((line = lnr.readLine()) != null)
        {
          String[] parts = line.trim().split("#");

          if(parts.length > 0 && !parts[0].startsWith("#") && parts[0].length() > 0)
          {
            line = parts[0];

            if(line.endsWith("/**"))
            {
              line = line.substring(0, line.length() - 3);
            }
            else if(line.endsWith("/*"))
            {
              line = line.substring(0, line.length() - 2);
            }

            file = new File(SCRIPT_FOLDER, line);

            if(file.isDirectory() && parts[0].endsWith("/**"))
            {
              this.executeAllScriptsInDirectory(file, true, 32);
            }
            else if(file.isDirectory() && parts[0].endsWith("/*"))
            {
              this.executeAllScriptsInDirectory(file);
            }
            else if(file.isFile())
            {
              try
              {
                this.executeScript(file);
              }
              catch(ScriptException e)
              {
                if(Config.ENABLE_ALL_EXCEPTIONS)
                  e.printStackTrace();
               
                reportScriptFileError(file, e);
              }
            }
            else
            {
              _log.warning("Failed loading: (" + file.getCanonicalPath() + ") @ " + list.getName() + ":" + lnr.getLineNumber() + " - Reason: doesnt exists or is not a file.");
            }
          }
        }
       
      }
      catch(FileNotFoundException e1)
      {
        e1.printStackTrace();
     
      }
      catch(IOException e)
      {
        e.printStackTrace();
       
      }finally
      {
        if(lnr != null)
          try
          {
            lnr.close();
          }
          catch(Exception e1)
          {
            e1.printStackTrace();
          }
       
        if(buff != null)
          try
          {
            buff.close();
          }
          catch(Exception e1)
          {
            e1.printStackTrace();
          }
       
        if(reader != null)
          try
          {
            reader.close();
          }
          catch(Exception e1)
          {
            e1.printStackTrace();
          }
       
      }
     
    }else
      throw new IllegalArgumentException("Argument must be an file containing a list of scripts to be loaded");
  }

  public void executeAllScriptsInDirectory(File dir)
  {
    this.executeAllScriptsInDirectory(dir, false, 0);
  }

  public void executeAllScriptsInDirectory(File dir, boolean recurseDown, int maxDepth)
  {
    this.executeAllScriptsInDirectory(dir, recurseDown, maxDepth, 0);
  }

  private void executeAllScriptsInDirectory(File dir, boolean recurseDown, int maxDepth, int currentDepth)
  {
    if(dir.isDirectory())
    {
      for(File file : dir.listFiles())
      {
        if(file.isDirectory() && recurseDown && maxDepth > currentDepth)
        {
          if(Config.SCRIPT_DEBUG)
          {
            _log.info("Entering folder: " + file.getName());
          }
          this.executeAllScriptsInDirectory(file, recurseDown, maxDepth, currentDepth + 1);
        }
        else if(file.isFile())
        {
          try
          {
            String name = file.getName();
            int lastIndex = name.lastIndexOf('.');
            String extension;
            if(lastIndex != -1)
            {
              extension = name.substring(lastIndex + 1);
              ScriptEngine engine = getEngineByExtension(extension);
              if(engine != null)
              {
                this.executeScript(engine, file);
              }
            }
          }
          catch(ScriptException e)
          {
            if(Config.ENABLE_ALL_EXCEPTIONS)
              e.printStackTrace();
           
            reportScriptFileError(file, e);
            //e.printStackTrace();
          }
        }
      }
    }
    else
      throw new IllegalArgumentException("The argument directory either doesnt exists or is not an directory.");
  }

  public CompiledScriptCache getCompiledScriptCache()
  {
    return _cache;
  }

  public CompiledScriptCache loadCompiledScriptCache()
  {
    CompiledScriptCache cache = null;
   
    if(Config.SCRIPT_CACHE)
    {
      File file = new File(SCRIPT_FOLDER, "CompiledScripts.cache");
      if(file.isFile())
      {
        FileInputStream fis = null;
        ObjectInputStream ois = null;
        try
        {
          fis = new FileInputStream(file);
          ois = new ObjectInputStream(fis);
          cache = (CompiledScriptCache) ois.readObject();
        }
        catch(InvalidClassException e)
        {
          if(Config.ENABLE_ALL_EXCEPTIONS)
            e.printStackTrace();
          _log.log(Level.SEVERE, "Failed loading Compiled Scripts Cache, invalid class (Possibly outdated).", e);
        }
        catch(IOException e)
        {
          if(Config.ENABLE_ALL_EXCEPTIONS)
            e.printStackTrace();
          _log.log(Level.SEVERE, "Failed loading Compiled Scripts Cache from file.", e);
        }
        catch(ClassNotFoundException e)
        {
          if(Config.ENABLE_ALL_EXCEPTIONS)
            e.printStackTrace();
          _log.log(Level.SEVERE, "Failed loading Compiled Scripts Cache, class not found.", e);
        }
        finally
        {
          if(ois != null)
            try
            {
              ois.close();
            }
            catch(Exception e)
            {
              e.printStackTrace();
            }
          if(fis != null)
            try
            {
              fis.close();
            }
            catch(Exception e)
            {
              e.printStackTrace();
            }
        }
       
      }
     
      if(cache == null){
        cache = new CompiledScriptCache();
      }
     
    }
   
    return cache;
  }

  protected class CleaneCache implements Runnable
  {
    @Override
    public void run()
    {

    }
  }

  public void executeScript(File file) throws ScriptException
  {
    String name = file.getName();
    int lastIndex = name.lastIndexOf('.');
    String extension;
    if(lastIndex != -1)
    {
      extension = name.substring(lastIndex + 1);
    }
    else
      throw new ScriptException("Script file (" + name + ") doesnt has an extension that identifies the ScriptEngine to be used.");

    ScriptEngine engine = getEngineByExtension(extension);
    if(engine == null)
      throw new ScriptException("No engine registered for extension (" + extension + ")");
    executeScript(engine, file);
  }

  public void executeScript(String engineName, File file) throws ScriptException
  {
    ScriptEngine engine = getEngineByName(engineName);
    if(engine == null)
      throw new ScriptException("No engine registered with name (" + engineName + ")");
    executeScript(engine, file);
  }

  public void executeScript(ScriptEngine engine, File file) throws ScriptException
  {
   
    FileInputStream reader = null;
    InputStreamReader buff = null;
    BufferedReader lnr = null;
   
    try
    {
      reader = new FileInputStream(file);
      buff = new InputStreamReader(reader);
      lnr = new BufferedReader(buff);

      if(Config.SCRIPT_DEBUG)
      {
        _log.info("Loading Script: " + file.getAbsolutePath());
      }

      if(Config.SCRIPT_ERROR_LOG)
      {
        String name = file.getAbsolutePath() + ".error.log";
        File errorLogger = new File(name);
        if(errorLogger.isFile())
        {
          errorLogger.delete();
        }
      }

      if(engine instanceof Compilable && Config.SCRIPT_ALLOW_COMPILATION)
      {
        ScriptContext context = new SimpleScriptContext();
        context.setAttribute("mainClass", getClassForFile(file).replace('/', '.').replace('\\', '.'), ScriptContext.ENGINE_SCOPE);
        context.setAttribute(ScriptEngine.FILENAME, file.getName(), ScriptContext.ENGINE_SCOPE);
        context.setAttribute("classpath", SCRIPT_FOLDER.getAbsolutePath(), ScriptContext.ENGINE_SCOPE);
        context.setAttribute("sourcepath", SCRIPT_FOLDER.getAbsolutePath(), ScriptContext.ENGINE_SCOPE);
        context.setAttribute(JythonScriptEngine.JYTHON_ENGINE_INSTANCE, engine, ScriptContext.ENGINE_SCOPE);

        setCurrentLoadingScript(file);
        ScriptContext ctx = engine.getContext();
        try
        {
          engine.setContext(context);
          if(Config.SCRIPT_CACHE)
          {
            CompiledScript cs = _cache.loadCompiledScript(engine, file);
            cs.eval(context);
          }
          else
          {
            Compilable eng = (Compilable) engine;
            CompiledScript cs = eng.compile(lnr);
            cs.eval(context);
          }
        }
        finally
        {
          engine.setContext(ctx);
          setCurrentLoadingScript(null);
          context.removeAttribute(ScriptEngine.FILENAME, ScriptContext.ENGINE_SCOPE);
          context.removeAttribute("mainClass", ScriptContext.ENGINE_SCOPE);
        }
      }
      else
      {
        ScriptContext context = new SimpleScriptContext();
        context.setAttribute("mainClass", getClassForFile(file).replace('/', '.').replace('\\', '.'), ScriptContext.ENGINE_SCOPE);
        context.setAttribute(ScriptEngine.FILENAME, file.getName(), ScriptContext.ENGINE_SCOPE);
        context.setAttribute("classpath", SCRIPT_FOLDER.getAbsolutePath(), ScriptContext.ENGINE_SCOPE);
        context.setAttribute("sourcepath", SCRIPT_FOLDER.getAbsolutePath(), ScriptContext.ENGINE_SCOPE);
        setCurrentLoadingScript(file);
        try
        {
          engine.eval(lnr, context);
        }
        finally
        {
          setCurrentLoadingScript(null);
          engine.getContext().removeAttribute(ScriptEngine.FILENAME, ScriptContext.ENGINE_SCOPE);
          engine.getContext().removeAttribute("mainClass", ScriptContext.ENGINE_SCOPE);
        }

      }
     
    }catch(IOException e){
   
      e.printStackTrace();
   
    }
    finally
    {
      if(lnr != null)
        try
        {
          lnr.close();
        }
        catch(Exception e1)
        {
          e1.printStackTrace();
        }
     
      if(buff != null)
        try
        {
          buff.close();
        }
        catch(Exception e1)
        {
          e1.printStackTrace();
        }
     
      if(reader != null)
        try
        {
          reader.close();
        }
        catch(Exception e1)
        {
          e1.printStackTrace();
        }
     
    }
   
  }

  public static String getClassForFile(File script)
  {
    String path = script.getAbsolutePath();
    String scpPath = SCRIPT_FOLDER.getAbsolutePath();
    if(path.startsWith(scpPath))
    {
      int idx = path.lastIndexOf('.');
      return path.substring(scpPath.length() + 1, idx);
    }
    return null;
  }

  public ScriptContext getScriptContext(ScriptEngine engine)
  {
    return engine.getContext();
  }

  public ScriptContext getScriptContext(String engineName)
  {
    ScriptEngine engine = getEngineByName(engineName);
    if(engine == null)
      throw new IllegalStateException("No engine registered with name (" + engineName + ")");
    return getScriptContext(engine);
  }

  public Object eval(ScriptEngine engine, String script, ScriptContext context) throws ScriptException
  {
    if(engine instanceof Compilable && Config.SCRIPT_ALLOW_COMPILATION)
    {
      Compilable eng = (Compilable) engine;
      CompiledScript cs = eng.compile(script);
      return context != null ? cs.eval(context) : cs.eval();
    }
    return context != null ? engine.eval(script, context) : engine.eval(script);
  }

  public Object eval(String engineName, String script) throws ScriptException
  {
    return this.eval(engineName, script, null);
  }

  public Object eval(String engineName, String script, ScriptContext context) throws ScriptException
  {
    ScriptEngine engine = getEngineByName(engineName);
    if(engine == null)
      throw new ScriptException("No engine registered with name (" + engineName + ")");
    return eval(engine, script, context);
  }

  public Object eval(ScriptEngine engine, String script) throws ScriptException
  {
    return eval(engine, script, null);
  }

  public void reportScriptFileError(File script, ScriptException e)
  {
    String dir = script.getParent();
    String name = script.getName() + ".error.log";
    if(dir != null)
    {
      File file = new File(dir + "/" + name);
      FileOutputStream fos = null;
      try
      {
        if(!file.exists())
        {
          file.createNewFile();
        }

        fos = new FileOutputStream(file);
        String errorHeader = "Error on: " + file.getCanonicalPath() + "\r\nLine: " + e.getLineNumber() + " - Column: " + e.getColumnNumber() + "\r\n\r\n";
        fos.write(errorHeader.getBytes());
        fos.write(e.getMessage().getBytes());
        _log.warning("Failed executing script: " + script.getAbsolutePath() + ". See " + file.getName() + " for details.");
      }
      catch(IOException ioe)
      {
        _log.warning("Failed executing script: " + script.getAbsolutePath() + "\r\n" + e.getMessage() + "Additionally failed when trying to write an error report on script directory. Reason: " + ioe.getMessage());
        ioe.printStackTrace();
      }
      finally
      {
        if(fos != null)
          try
          {
            fos.close();
          }
          catch(Exception e1)
          {
            e1.printStackTrace();
          }
      }
    }
    else
    {
      _log.warning("Failed executing script: " + script.getAbsolutePath() + "\r\n" + e.getMessage() + "Additionally failed when trying to write an error report on script directory.");
    }
  }

  public void registerScriptManager(ScriptManager<?> manager)
  {
    _scriptManagers.add(manager);
  }

  public void removeScriptManager(ScriptManager<?> manager)
  {
    _scriptManagers.remove(manager);
  }

  public List<ScriptManager<?>> getScriptManagers()
  {
    return _scriptManagers;

  }

  /**
   * @param currentLoadingScript The currentLoadingScript to set.
   */
  protected void setCurrentLoadingScript(File currentLoadingScript)
  {
    _currentLoadingScript = currentLoadingScript;
  }

  /**
   * @return Returns the currentLoadingScript.
   */
  protected File getCurrentLoadScript()
  {
    return _currentLoadingScript;
  }

  @SuppressWarnings("synthetic-access")
  private static class SingletonHolder
  {
    protected static final L2ScriptEngineManager _instance = new L2ScriptEngineManager();
  }
}
TOP

Related Classes of com.l2jfrozen.gameserver.scripting.L2ScriptEngineManager$CleaneCache

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.