1313 * @author unascribed
1414 * @version 1.0
1515 */
16+ import blue .BlueData ;
1617import blue .BlueSystem ;
18+ import java .io .File ;
19+ import java .io .IOException ;
20+ import java .io .Reader ;
21+ import java .io .Writer ;
22+ import java .util .ArrayList ;
23+ import java .util .Map ;
24+ import java .util .WeakHashMap ;
1725import javax .script .ScriptContext ;
1826import javax .script .ScriptEngine ;
1927import javax .script .ScriptException ;
2028import org .netbeans .api .scripting .Scripting ;
2129
2230public class JavaScriptProxy {
2331
24- private static ScriptEngine engine ;
32+ private static final Map <BlueData , ProjectEngineState > projectEngineStates
33+ = new WeakHashMap <>();
2534
26- static {
35+ private static ProjectEngineState defaultEngineState ;
2736
28- }
37+ private static final ArrayList <JavaScriptProxyListener > listeners
38+ = new ArrayList <>();
2939
3040 public static synchronized final void reinitialize () {
3141// if (cx != null) {
@@ -34,20 +44,37 @@ public static synchronized final void reinitialize() {
3444// cx = Context.enter();
3545// scope = cx.initStandardObjects(null);
3646// engine = new ScriptEngineManager().getEngineByName("graal.js");
37- engine = Scripting .createManager ().getEngineByMimeType ("text/javascript" );
38- engine .getContext ().setAttribute (ScriptEngine .FILENAME , "script.mjs" , ScriptContext .ENGINE_SCOPE );
47+ ProjectEngineState state = createEngineState ();
48+ BlueData currentData = BlueSystem .getCurrentBlueData ();
49+
50+ if (currentData == null ) {
51+ defaultEngineState = state ;
52+ } else {
53+ projectEngineStates .put (currentData , state );
54+ }
55+
56+ ScriptContext context = state .engine .getContext ();
57+ context .setAttribute (ScriptEngine .FILENAME , "script.mjs" , ScriptContext .ENGINE_SCOPE );
3958// Context.newBuilder("js").allowIO(true).currentWorkingDirectory(workingDirectory)
4059 System .out .println (BlueSystem .getString ("scripting.js.reinitialized" ));
60+
61+ for (JavaScriptProxyListener listener : listeners ) {
62+ listener .javascriptProxyReinitializePerformed ();
63+ }
64+ }
65+
66+ public static synchronized void addJavaScriptProxyListener (JavaScriptProxyListener listener ) {
67+ listeners .add (listener );
68+ }
69+
70+ public static synchronized void removeJavaScriptProxyListener (JavaScriptProxyListener listener ) {
71+ listeners .remove (listener );
4172 }
4273
4374 public static synchronized final String processJavascriptScore (String script ,
4475 double subjectiveDuration , String soundObjectId ) throws ScriptException {
45- if (engine == null ) {
46- reinitialize ();
47- }
48-
49-
50- String returnScore = "" ;
76+ ScriptEngine scriptEngine = getCurrentEngineState ().engine ;
77+ setProjectBindings (scriptEngine );
5178
5279 String init = "blueDuration = " + subjectiveDuration
5380 + ";\n " ;
@@ -57,12 +84,12 @@ public static synchronized final String processJavascriptScore(String script,
5784// engine.setBindings(bindings, ScriptContext.GLOBAL_SCOPE);
5885 //engine.setContext(context);
5986
60- engine .eval (init );
61- engine .eval (script );
87+ scriptEngine .eval (init );
88+ scriptEngine .eval (script );
6289
6390// cx.evaluateString(scope, init, "init", 1, null);
6491// cx.evaluateString(scope, script, soundObjectId, 1, null);
65- var res = engine .get ("score" );
92+ var res = scriptEngine .get ("score" );
6693
6794//
6895//
@@ -75,11 +102,8 @@ public static synchronized final String processJavascriptScore(String script,
75102
76103 public static synchronized final String processJavascriptInstrument (String script ,
77104 String instrumentId ) throws ScriptException {
78- if (engine == null ) {
79- reinitialize ();
80- }
81- String returnInstrument = "" ;
82-
105+ ScriptEngine scriptEngine = getCurrentEngineState ().engine ;
106+ setProjectBindings (scriptEngine );
83107 String init = "instrument = '';\n " ;
84108
85109// try {
@@ -96,11 +120,174 @@ public static synchronized final String processJavascriptInstrument(String scrip
96120// } catch (JavaScriptException e) {
97121// System.out.println(e.getLocalizedMessage());
98122// }
99- engine .eval (init );
100- engine .eval (script );
101- var res = engine .get ("instrument" );
123+ scriptEngine .eval (init );
124+ scriptEngine .eval (script );
125+ var res = scriptEngine .get ("instrument" );
102126 return java .util .Objects .toString (res , null );
103127
104128 }
105129
130+ public static synchronized Object processScript (String script , Reader stdin ,
131+ Writer stdout , Writer stderr ) throws ScriptException {
132+ ProjectEngineState state = getCurrentEngineState ();
133+ ScriptEngine scriptEngine = state .engine ;
134+ setProjectBindings (scriptEngine );
135+ state .consoleReader .setDelegate (stdin );
136+ state .consoleWriter .setDelegate (stdout );
137+ state .consoleErrorWriter .setDelegate (stderr );
138+
139+ try {
140+ return scriptEngine .eval (script );
141+ } finally {
142+ state .consoleReader .clearDelegate ();
143+ state .consoleWriter .clearDelegate ();
144+ state .consoleErrorWriter .clearDelegate ();
145+ }
146+ }
147+
148+ private static ProjectEngineState getCurrentEngineState () {
149+ BlueData currentData = BlueSystem .getCurrentBlueData ();
150+
151+ if (currentData == null ) {
152+ if (defaultEngineState == null ) {
153+ defaultEngineState = createEngineState ();
154+ }
155+
156+ return defaultEngineState ;
157+ }
158+
159+ ProjectEngineState state = projectEngineStates .get (currentData );
160+
161+ if (state == null ) {
162+ state = createEngineState ();
163+ projectEngineStates .put (currentData , state );
164+ }
165+
166+ return state ;
167+ }
168+
169+ private static ProjectEngineState createEngineState () {
170+ ScriptEngine engine = Scripting .createManager ().getEngineByMimeType ("text/javascript" );
171+ ProjectEngineState state = new ProjectEngineState (engine );
172+ installConsoleIo (state , engine .getContext ());
173+ return state ;
174+ }
175+
176+ private static void installConsoleIo (ProjectEngineState state , ScriptContext context ) {
177+ state .consoleReader .clearDelegate ();
178+ state .consoleWriter .clearDelegate ();
179+ state .consoleErrorWriter .clearDelegate ();
180+
181+ state .consoleReader .setFallback (context .getReader ());
182+ state .consoleWriter .setFallback (context .getWriter ());
183+ state .consoleErrorWriter .setFallback (context .getErrorWriter ());
184+
185+ context .setReader (state .consoleReader );
186+ context .setWriter (state .consoleWriter );
187+ context .setErrorWriter (state .consoleErrorWriter );
188+ }
189+
190+ private static void setProjectBindings (ScriptEngine scriptEngine ) {
191+ File currentDirFile = BlueSystem .getCurrentProjectDirectory ();
192+ String currentDir = currentDirFile == null ? ""
193+ : currentDirFile .getAbsolutePath () + File .separator ;
194+
195+ scriptEngine .put ("blueData" , BlueSystem .getCurrentBlueData ());
196+ scriptEngine .put ("blueProjectDir" , currentDir );
197+ }
198+
199+ private static final class ProjectEngineState {
200+
201+ private final ScriptEngine engine ;
202+
203+ private final DelegatingReader consoleReader = new DelegatingReader ();
204+
205+ private final DelegatingWriter consoleWriter = new DelegatingWriter ();
206+
207+ private final DelegatingWriter consoleErrorWriter = new DelegatingWriter ();
208+
209+ private ProjectEngineState (ScriptEngine engine ) {
210+ this .engine = engine ;
211+ }
212+ }
213+
214+ private static final class DelegatingReader extends Reader {
215+
216+ private Reader fallback ;
217+
218+ private Reader delegate ;
219+
220+ synchronized void setFallback (Reader fallback ) {
221+ this .fallback = fallback ;
222+ }
223+
224+ synchronized void setDelegate (Reader delegate ) {
225+ this .delegate = delegate ;
226+ }
227+
228+ synchronized void clearDelegate () {
229+ this .delegate = null ;
230+ }
231+
232+ private synchronized Reader current () {
233+ return delegate != null ? delegate : fallback ;
234+ }
235+
236+ @ Override
237+ public int read (char [] cbuf , int off , int len ) throws IOException {
238+ Reader reader = current ();
239+ return reader == null ? -1 : reader .read (cbuf , off , len );
240+ }
241+
242+ @ Override
243+ public void close () {
244+ }
245+ }
246+
247+ private static final class DelegatingWriter extends Writer {
248+
249+ private Writer fallback ;
250+
251+ private Writer delegate ;
252+
253+ synchronized void setFallback (Writer fallback ) {
254+ this .fallback = fallback ;
255+ }
256+
257+ synchronized void setDelegate (Writer delegate ) {
258+ this .delegate = delegate ;
259+ }
260+
261+ synchronized void clearDelegate () {
262+ this .delegate = null ;
263+ }
264+
265+ private synchronized Writer current () {
266+ return delegate != null ? delegate : fallback ;
267+ }
268+
269+ @ Override
270+ public void write (char [] cbuf , int off , int len ) throws IOException {
271+ Writer writer = current ();
272+
273+ if (writer != null ) {
274+ writer .write (cbuf , off , len );
275+ }
276+ }
277+
278+ @ Override
279+ public void flush () throws IOException {
280+ Writer writer = current ();
281+
282+ if (writer != null ) {
283+ writer .flush ();
284+ }
285+ }
286+
287+ @ Override
288+ public void close () throws IOException {
289+ flush ();
290+ }
291+ }
292+
106293}
0 commit comments