Package dovetaildb.dbrepository

Source Code of dovetaildb.dbrepository.StandardDbRepository$ScriptEnv

package dovetaildb.dbrepository;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import dovetaildb.apiservice.ApiService;
import dovetaildb.apiservice.ChangesetBuffer;
import dovetaildb.coordinator.Coordinator;
import dovetaildb.dbservice.DbService;

public abstract class StandardDbRepository implements DbRepository {
 
  static class ScriptFile {
    String code;
    String language = "ECMAScript";
    static final Pattern propRegex = Pattern.compile("^\\bDDB_(\\w+)\\s*=\\s*(\\S+)\\b");
    static final Pattern nlRegex = Pattern.compile("[\\r\\n]+");
    public ScriptFile(String code) {
      this.code = code;
      Matcher nlMatcher = nlRegex.matcher(code);
      int firstNewline;
      if (nlMatcher.find()) {
        firstNewline = nlMatcher.start();
        if (nlMatcher.find()) { //in the first two lines
          firstNewline = nlMatcher.start();
        }
      } else {
        firstNewline = code.length();
      }
      Matcher matcher = propRegex.matcher(code);
      while(matcher.find()) {
        if (matcher.start() > firstNewline) break;
        String key = matcher.group(1);
        String val = matcher.group(2);
        if (key.equals("language")) language = val;
        else throw new RuntimeException("Unsupported code parameter: \""+key+"\"");
      }
    }
  }
 
  static class ScriptEnv {
    public ScriptEngineManager manager = new ScriptEngineManager();
    public ArrayList<ScriptEngine> engines = new ArrayList<ScriptEngine>();
    void ingestScript(String code) {
      ScriptFile file = new ScriptFile(code);
      ScriptEngine engine = manager.getEngineByName(file.language);
      if (engine == null) throw new RuntimeException("Unsupported script language: "+file.language);
      try {
        engine.eval(code);
      } catch (ScriptException e) {
        throw new RuntimeException(e);
      }
    }
    <T>T getInterface(Class<T> iface, Object... args) {
      T impl = null;
      for(ScriptEngine engine : engines) {
        if (engine instanceof Invocable) {
          T curImpl = ((Invocable)engine).getInterface(iface);
          if (impl != null) throw new RuntimeException("The "+iface.getSimpleName()+" interface is implemented multiple times in different scripting languages.");
          impl = curImpl;
        }
      }
      return impl;
    }
    public Object invokeFunction(String functionName, Object[] args) {
      for(ScriptEngine engine : engines) {
        if (engine instanceof Invocable) {
          try {
            return ((Invocable)engine).invokeFunction(functionName, args);
          } catch (ScriptException e) {
            throw new RuntimeException(e);
          } catch (NoSuchMethodException e) {
          }
        }
      }
      throw new RuntimeException("Function not defined: \""+functionName+"\"");
    }
  }
 
  static ScriptEnv buildScriptEnv(Collection<String> codeFiles) {
    ScriptEnv env = new ScriptEnv();
    for(String code : codeFiles) {
      env.ingestScript(code);
    }
    return env;
  }

  static interface WrapApiService {
    public ApiService wrapApiService(ApiService apiService);
  }
 
  static class DbRecord implements Serializable {
    private static final long serialVersionUID = -1307143029380559827L;
    DbService db;
    Map<String,String> code;
    Coordinator coordinator;
    transient ScriptEnv scriptEnv;
    transient WrapApiService apiServiceWrapperFn;
    transient RequestAcceptor requestAcceptor;
    public void signalCodeChange() {
      ScriptEnv scriptEnv = buildScriptEnv(code.values());
      apiServiceWrapperFn = scriptEnv.getInterface(WrapApiService.class);
    }
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
      in.defaultReadObject();
      signalCodeChange();
    }
  }

  ConcurrentHashMap<String, DbRecord> repo;

 
  public ApiService newSession(String db) {
    DbRecord rec = repo.get(db);
    ApiService api = new ChangesetBuffer(rec.db, rec.coordinator);
    if (rec.apiServiceWrapperFn != null)
      api = rec.apiServiceWrapperFn.wrapApiService(api);
    return api;
  }

  public RequestAcceptor getRequestAcceptor(String dbName) {
    DbRecord rec = repo.get(dbName);
    return rec.requestAcceptor;
  }

  public Object invokeFunction(String dbName, String functionName, Object[] args) {
    DbRecord rec = repo.get(dbName);
    return rec.scriptEnv.invokeFunction(functionName, args);
  }
 
  public DbService getDbService(String db) {
    return repo.get(db).db;
  }

  public void setDbService(String dbName, DbService dbService, Coordinator coordinator) {
    DbRecord rec = new DbRecord();
    rec.db = dbService;
    rec.coordinator = coordinator;
    repo.put(dbName, rec);
  }

  public boolean deleteDbService(String dbName) {
    if (!repo.containsKey(dbName)) return false;
    DbRecord rec = repo.get(dbName);
    rec.db.drop();
    DbRecord last = repo.remove(dbName);
    return (last != null);
  }


  public void addCodeFile(String dbName, String fileName, String content) {
    DbRecord rec = repo.get(dbName);
    rec.code.put(fileName, content);
    rec.signalCodeChange();
  }
  public boolean deleteCodeFile(String dbName, String fileName) {
    DbRecord rec = repo.get(dbName);
    boolean removed = (rec.code.remove(fileName) != null);
    rec.signalCodeChange();
    return removed;
  }
  private static final String[] EMPTY_STRING_ARRAY = new String[]{};
  public String[] getCodeFilenames(String dbName) {
    DbRecord rec = repo.get(dbName);
    return rec.code.keySet().toArray(EMPTY_STRING_ARRAY);
  }

  public void close() {}
 
}
TOP

Related Classes of dovetaildb.dbrepository.StandardDbRepository$ScriptEnv

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.