8
8
import de .undercouch .citeproc .helper .json .JsonBuilder ;
9
9
import de .undercouch .citeproc .helper .json .JsonObject ;
10
10
import de .undercouch .citeproc .helper .json .StringJsonBuilder ;
11
- import de .undercouch .citeproc .script .*;
11
+ import de .undercouch .citeproc .script .AbstractScriptRunner ;
12
+ import de .undercouch .citeproc .script .GraalScriptRunner ;
13
+ import de .undercouch .citeproc .script .ScriptRunnerException ;
12
14
import org .graalvm .polyglot .Context ;
13
15
import org .graalvm .polyglot .PolyglotException ;
14
16
import org .graalvm .polyglot .Source ;
15
17
import org .graalvm .polyglot .Value ;
16
18
17
- import java .io .*;
19
+ import java .io .IOException ;
20
+ import java .io .InputStream ;
21
+ import java .io .InputStreamReader ;
22
+ import java .io .Reader ;
18
23
import java .util .*;
19
24
20
25
public class JSContext extends AbstractScriptRunner {
21
- private HeadlessWindow window ;
22
- private Context rawContext = Context .newBuilder ("js" ).allowAllAccess (true ).build ();
23
- private Map <JavaScriptAPI , Boolean > loadedJSWebAPIs = new HashMap <>();
26
+ private final HeadlessWindow window ;
27
+ private final Context rawContext = Context .newBuilder ("js" ).allowAllAccess (true ).build ();
28
+ private final Map <JavaScriptAPI , Boolean > loadedJSWebAPIs = new HashMap <>();
24
29
25
30
public JSContext (HeadlessWindow window ) {
26
31
this .window = window ;
@@ -32,7 +37,7 @@ public JSContext(HeadlessWindow window) {
32
37
33
38
// Register all JavaScript Web-APIs:
34
39
loadedJSWebAPIs .forEach ((api , override ) -> {
35
- try {
40
+ try {
36
41
registerAndLoad (api .getJSVarName (), api .getObject (), override );
37
42
} catch (Exception exception ) {
38
43
System .err .println ("Failed to load one/multiple JavaScript Web-API(s) into the current JavaScript-Context! Details:" );
@@ -42,20 +47,102 @@ public JSContext(HeadlessWindow window) {
42
47
43
48
}
44
49
50
+ /**
51
+ * Recursively convert a JavaScript value to a Java object
52
+ *
53
+ * @param v the value to convert
54
+ * @return the object
55
+ */
56
+ private static Object convert (Value v ) {
57
+ Object o = v ;
58
+ if (v .isNull ()) {
59
+ o = null ;
60
+ } else if (v .isBoolean ()) {
61
+ o = v .asBoolean ();
62
+ } else if (v .isDate ()) {
63
+ o = v .asDate ();
64
+ } else if (v .isDuration ()) {
65
+ o = v .asDuration ();
66
+ } else if (v .isHostObject ()) {
67
+ o = v .asHostObject ();
68
+ } else if (v .isInstant ()) {
69
+ o = v .asInstant ();
70
+ } else if (v .isNativePointer ()) {
71
+ o = v .asNativePointer ();
72
+ } else if (v .isNumber ()) {
73
+ if (v .fitsInInt ()) {
74
+ o = v .asInt ();
75
+ } else if (v .fitsInLong ()) {
76
+ o = v .asLong ();
77
+ } else if (v .fitsInDouble ()) {
78
+ o = v .asDouble ();
79
+ } else {
80
+ throw new IllegalStateException ("Unknown type of number" );
81
+ }
82
+ } else if (v .isProxyObject ()) {
83
+ o = v .asProxyObject ();
84
+ } else if (v .isString ()) {
85
+ o = v .asString ();
86
+ } else if (v .isTime ()) {
87
+ o = v .asTime ();
88
+ } else if (v .isTimeZone ()) {
89
+ o = v .asTimeZone ();
90
+ } else if (v .hasArrayElements ()) {
91
+ o = convertArray (v );
92
+ } else if (v .hasMembers ()) {
93
+ o = convertObject (v );
94
+ }
95
+ return o ;
96
+ }
97
+
98
+ /**
99
+ * Recursively convert a JavaScript array to a list
100
+ *
101
+ * @param arr the array to convert
102
+ * @return the list
103
+ */
104
+ private static List <Object > convertArray (Value arr ) {
105
+ List <Object > l = new ArrayList <>();
106
+ for (int i = 0 ; i < arr .getArraySize (); ++i ) {
107
+ Value v = arr .getArrayElement (i );
108
+ Object o = convert (v );
109
+ l .add (o );
110
+ }
111
+ return l ;
112
+ }
113
+
114
+ /**
115
+ * Recursively convert a JavaScript object to a map
116
+ *
117
+ * @param obj the object to convert
118
+ * @return the map
119
+ */
120
+ private static Map <String , Object > convertObject (Value obj ) {
121
+ Map <String , Object > r = new LinkedHashMap <>();
122
+ for (String k : obj .getMemberKeys ()) {
123
+ Value v = obj .getMember (k );
124
+ Object o = convert (v );
125
+ r .put (k , o );
126
+ }
127
+ return r ;
128
+ }
129
+
45
130
/**
46
131
* Registers and loads this API into the provided {@link JSContext}. <br>
132
+ *
47
133
* @param id
48
134
*/
49
135
public void registerAndLoad (String id , Object object , boolean override ) throws DuplicateRegisteredId , IOException {
50
- if (!override && rawContext .getBindings ("js" ).getMember (id ) != null )
51
- throw new DuplicateRegisteredId ("Failed to register because of already existing/registered id '" + id + "'." );
136
+ if (!override && rawContext .getBindings ("js" ).getMember (id ) != null )
137
+ throw new DuplicateRegisteredId ("Failed to register because of already existing/registered id '" + id + "'." );
52
138
rawContext .getBindings ("js" ).putMember (id , object );
53
139
}
54
140
55
141
/**
56
142
* Executes the given jsCode in the current context. <br>
57
143
* This means that all the jsCode that has been ran before in this {@link JSContext} is accessible
58
144
* for the given jsCode.
145
+ *
59
146
* @param jsCode JavaScript code to run in the current {@link JSContext}.
60
147
* @throws ScriptRunnerException
61
148
* @throws IOException
@@ -76,14 +163,12 @@ public Context getRawContext() {
76
163
return rawContext ;
77
164
}
78
165
79
-
80
166
/**
81
167
* ALL METHODS BELOW ARE TAKEN FROM {@link GraalScriptRunner}. <br>
82
168
* Some methods were added to provide extra functionality.
83
169
*/
84
170
85
171
86
-
87
172
@ Override
88
173
public String getName () {
89
174
return rawContext .getEngine ().getImplementationName ();
@@ -96,14 +181,6 @@ public String getVersion() {
96
181
97
182
@ Override
98
183
public void eval (Reader reader ) throws IOException {
99
- String jsCode = null ;
100
- try (BufferedReader bufferedReader = new BufferedReader (reader )) {
101
- while ((jsCode = bufferedReader .readLine ()) != null ) {
102
- jsCode = jsCode +jsCode ;
103
- }
104
- } catch (IOException e ) {
105
- throw e ;
106
- }
107
184
rawContext .eval (Source .newBuilder ("js" , reader , null ).cached (false ).build ());
108
185
}
109
186
@@ -131,7 +208,7 @@ public void callMethod(String name, Object... args) throws ScriptRunnerException
131
208
public <T > T callMethod (Object obj , String name , Class <T > resultType , Object ... args )
132
209
throws ScriptRunnerException {
133
210
try {
134
- return convert (((Value )obj ).getMember (name )
211
+ return convert (((Value ) obj ).getMember (name )
135
212
.execute (convertArguments (args )), resultType );
136
213
} catch (IOException | PolyglotException e ) {
137
214
throw new ScriptRunnerException ("Could not call method" , e );
@@ -142,100 +219,24 @@ public <T> T callMethod(Object obj, String name, Class<T> resultType, Object...
142
219
public void callMethod (Object obj , String name , Object ... args )
143
220
throws ScriptRunnerException {
144
221
try {
145
- ((Value )obj ).getMember (name ).executeVoid (convertArguments (args ));
222
+ ((Value ) obj ).getMember (name ).executeVoid (convertArguments (args ));
146
223
} catch (IOException | PolyglotException e ) {
147
224
throw new ScriptRunnerException ("Could not call method" , e );
148
225
}
149
226
}
150
227
151
- /**
152
- * Recursively convert a JavaScript value to a Java object
153
- * @param v the value to convert
154
- * @return the object
155
- */
156
- private static Object convert (Value v ) {
157
- Object o = v ;
158
- if (v .isNull ()) {
159
- o = null ;
160
- } else if (v .isBoolean ()) {
161
- o = v .asBoolean ();
162
- } else if (v .isDate ()) {
163
- o = v .asDate ();
164
- } else if (v .isDuration ()) {
165
- o = v .asDuration ();
166
- } else if (v .isHostObject ()) {
167
- o = v .asHostObject ();
168
- } else if (v .isInstant ()) {
169
- o = v .asInstant ();
170
- } else if (v .isNativePointer ()) {
171
- o = v .asNativePointer ();
172
- } else if (v .isNumber ()) {
173
- if (v .fitsInInt ()) {
174
- o = v .asInt ();
175
- } else if (v .fitsInLong ()) {
176
- o = v .asLong ();
177
- } else if (v .fitsInDouble ()) {
178
- o = v .asDouble ();
179
- } else {
180
- throw new IllegalStateException ("Unknown type of number" );
181
- }
182
- } else if (v .isProxyObject ()) {
183
- o = v .asProxyObject ();
184
- } else if (v .isString ()) {
185
- o = v .asString ();
186
- } else if (v .isTime ()) {
187
- o = v .asTime ();
188
- } else if (v .isTimeZone ()) {
189
- o = v .asTimeZone ();
190
- } else if (v .hasArrayElements ()) {
191
- o = convertArray (v );
192
- } else if (v .hasMembers ()) {
193
- o = convertObject (v );
194
- }
195
- return o ;
196
- }
197
-
198
228
@ Override
199
229
@ SuppressWarnings ("unchecked" )
200
230
public <T > T convert (Object o , Class <T > type ) {
201
231
if (type != Object .class && o instanceof Value ) {
202
- o = convert ((Value )o );
232
+ o = convert ((Value ) o );
203
233
}
204
- return (T )o ;
205
- }
206
-
207
- /**
208
- * Recursively convert a JavaScript array to a list
209
- * @param arr the array to convert
210
- * @return the list
211
- */
212
- private static List <Object > convertArray (Value arr ) {
213
- List <Object > l = new ArrayList <>();
214
- for (int i = 0 ; i < arr .getArraySize (); ++i ) {
215
- Value v = arr .getArrayElement (i );
216
- Object o = convert (v );
217
- l .add (o );
218
- }
219
- return l ;
220
- }
221
-
222
- /**
223
- * Recursively convert a JavaScript object to a map
224
- * @param obj the object to convert
225
- * @return the map
226
- */
227
- private static Map <String , Object > convertObject (Value obj ) {
228
- Map <String , Object > r = new LinkedHashMap <>();
229
- for (String k : obj .getMemberKeys ()) {
230
- Value v = obj .getMember (k );
231
- Object o = convert (v );
232
- r .put (k , o );
233
- }
234
- return r ;
234
+ return (T ) o ;
235
235
}
236
236
237
237
/**
238
238
* Convert arguments that should be passed to a JavaScript function
239
+ *
239
240
* @param args the arguments
240
241
* @return the converted arguments or `args` if conversion was not necessary
241
242
* @throws IOException if an argument could not be converted
@@ -253,7 +254,7 @@ private Object[] convertArguments(Object[] args) throws IOException {
253
254
.build ();
254
255
o = rawContext .eval (src );
255
256
} else if (v instanceof VariableWrapper ) {
256
- o = new VariableWrapperWrapper ((VariableWrapper )o );
257
+ o = new VariableWrapperWrapper ((VariableWrapper ) o );
257
258
}
258
259
if (o != v ) {
259
260
if (copy == args ) {
@@ -284,6 +285,7 @@ public void close() {
284
285
* Wraps around {@link VariableWrapper} and converts
285
286
* {@link VariableWrapperParams} objects to JSON objects. This class is
286
287
* public because Graal JavaScript needs to be able to access it.
288
+ *
287
289
* @author Michel Kraemer
288
290
*/
289
291
public static class VariableWrapperWrapper {
@@ -295,9 +297,10 @@ private VariableWrapperWrapper(VariableWrapper wrapper) {
295
297
296
298
/**
297
299
* Call the {@link VariableWrapper} with the given parameters
298
- * @param params the context in which an item should be rendered
299
- * @param prePunct the text that precedes the item to render
300
- * @param str the item to render
300
+ *
301
+ * @param params the context in which an item should be rendered
302
+ * @param prePunct the text that precedes the item to render
303
+ * @param str the item to render
301
304
* @param postPunct the text that follows the item to render
302
305
* @return the string to be rendered
303
306
*/
0 commit comments