1 /*
  2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package pseudoScriptEngineCompilable;
 27 
 28 import javax.script.Bindings;
 29 import javax.script.ScriptContext;
 30 import javax.script.ScriptEngine;
 31 import javax.script.ScriptEngineFactory;
 32 import javax.script.ScriptException;
 33 
 34 import javax.script.Compilable;
 35 import javax.script.CompiledScript;
 36 
 37 import javax.script.AbstractScriptEngine;
 38 import javax.script.SimpleScriptContext;
 39 import javax.script.SimpleBindings;
 40 
 41 import java.util.ArrayList;
 42 import java.util.Set;
 43 import java.util.TreeMap;
 44 import java.io.Reader;
 45 import java.io.BufferedReader;
 46 import java.io.IOException;
 47 
 48 import java.time.Instant;
 49 
 50 public class RgfPseudoScriptEngineCompilable extends AbstractScriptEngine implements Compilable {
 51     static final boolean bDebug = false; // true;
 52 
 53     /** Allows to log and access the ScriptEngine instances with their evalDataList. */
 54     static final ArrayList<RgfPseudoScriptEngineCompilable> enginesUsed = new ArrayList();
 55     public static ArrayList<RgfPseudoScriptEngineCompilable> getEnginesUsed() {
 56         return enginesUsed;
 57     }
 58 
 59     public RgfPseudoScriptEngineCompilable() {
 60         enginesUsed.add(this);
 61     }
 62 
 63     public ScriptEngineFactory getFactory() {
 64         return new RgfPseudoScriptEngineCompilableFactory();
 65     }
 66 
 67     /** ArrayList of eval() (invocation) information. */
 68     final ArrayList<InvocationInfos> invocationList = new ArrayList();
 69 
 70     /**
 71      * Returns ArrayList of eval() (invocation) information.
 72      * @return invocationList
 73      */
 74     public ArrayList<InvocationInfos> getInvocationList() {
 75         return invocationList;
 76     }
 77 
 78     public Bindings createBindings() {
 79         return new SimpleBindings();
 80     }
 81 
 82     public Object eval(Reader reader, ScriptContext context) {
 83         if (bDebug) System.err.println("[debug: " + this + ".eval(Reader,ScriptContext), ScriptContext=" + context + "]");
 84 
 85         return eval(readReader(reader), context);
 86     }
 87 
 88     public Object eval(String script, ScriptContext context) {
 89         if (bDebug) System.err.print("[debug: " + this + ".eval(String,ScriptContext), ScriptContext=" + context + "]");
 90 
 91         // create copies of the Bindings for later inspection as they may
 92         // get reused and changed on each eval() invocation
 93         TreeMap<Integer,TreeMap> bindings = new TreeMap();
 94         for (Integer scope : context.getScopes()) {
 95             Bindings binding = context.getBindings(scope);
 96             bindings.put(scope, binding == null ? new TreeMap<String,Object>() : new TreeMap<String,Object>(binding));
 97         }
 98         invocationList.add(new InvocationInfos(script,context));
 99         if (bDebug) System.err.println(" | invocationList.size()=" + invocationList.size());
100         return invocationList;
101     }
102 
103     public CompiledScript compile(Reader script) throws ScriptException {
104         return compile (readReader(script));
105     }
106 
107     public CompiledScript compile(String script) throws ScriptException {
108         if (script.indexOf("FAIL COMPILATION") != -1) {
109                 throw new ScriptException("test script contains FAIL COMPILATION");
110         }
111 
112         String code = "RgfPseudoCompiledScript=[" + script + "]";
113         RgfPseudoCompiledScript rpcs = new RgfPseudoCompiledScript(code, this);
114         return rpcs;
115     }
116 
117     String readReader(Reader reader) {
118         if (reader == null) {
119             return "";
120         }
121 
122         BufferedReader bufferedReader = new BufferedReader(reader);
123         StringBuilder sb = new StringBuilder();
124         // caters for possible IOException in read() and close()
125         try {
126             try {
127                 char[] charBuffer = new char[1024];
128                 int r = 0;
129 
130                 while ((r = bufferedReader.read(charBuffer)) != -1) {
131                     sb.append(charBuffer, 0, r);
132                 }
133             } finally {
134                 bufferedReader.close();
135             }
136         } catch (IOException ioe) {
137             throw new RuntimeException(ioe.getMessage(), ioe);
138         }
139         return sb.toString();
140     }
141 }