/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.plugins.javascript.rhino.worker.internal;
import org.gradle.api.Action;
import org.gradle.api.UncheckedIOException;
import org.gradle.util.GFileUtils;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.FunctionObject;
import org.mozilla.javascript.Scriptable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.LinkedHashMap;
import java.util.Map;
public abstract class RhinoWorkerUtils {
public interface ScopeOperation<T> {
void initContext(Context context);
T action(Scriptable scope, Context context);
}
public static class DefaultScopeOperation<T> implements ScopeOperation<T> {
public void initContext(Context context) {}
public T action(Scriptable scope, Context context) {
return null;
}
}
public static String readFile(File file, String encoding) {
return GFileUtils.readFile(file, encoding);
}
public static void writeFile(String content, File destination, String encoding) {
GFileUtils.writeFile(content, destination, encoding);
}
public static Scriptable parse(File source, String encoding) {
return parse(source, encoding, null);
}
public static <T> T parseRhino(File rhinoScript, ScopeOperation<T> operation) {
Context context = Context.enter();
try {
operation.initContext(context);
Scriptable scope = context.initStandardObjects();
String printFunction = "function print(message) {}";
context.evaluateString(scope, printFunction, "print", 1, null);
context.evaluateString(scope, readFile(rhinoScript, "UTF-8"), rhinoScript.getName(), 1, null);
return operation.action(scope, context);
} finally {
Context.exit();
}
}
public static Scriptable parse(File source, String encoding, Action<Context> contextConfig) {
Context context = Context.enter();
if (contextConfig != null) {
contextConfig.execute(context);
}
Scriptable scope = context.initStandardObjects();
try {
Reader reader = new InputStreamReader(new FileInputStream(source), encoding);
try {
context.evaluateReader(scope, reader, source.getName(), 0, null);
} finally {
reader.close();
}
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
Context.exit();
}
return scope;
}
public static <R> R childScope(Scriptable parentScope, ScopeOperation<R> operation) {
Context context = Context.enter();
try {
operation.initContext(context);
Scriptable childScope = context.newObject(parentScope);
childScope.setParentScope(parentScope);
return operation.action(childScope, context);
} finally {
Context.exit();
}
}
public static Map<String, Object> toMap(Scriptable obj) {
Map<String, Object> map = new LinkedHashMap<String, Object>();
for (Object id : obj.getIds()) {
String key;
Object value;
if (id instanceof String) {
key = (String) id;
value = obj.get(key, obj);
} else if (id instanceof Integer) {
key = id.toString();
value = obj.get((Integer) id, obj);
} else {
throw new IllegalArgumentException(String.format("Unexpected key type: %s (value: %s)", id.getClass().getName(), id));
}
map.put(key, toJavaValue(value));
}
return map;
}
public static Object toJavaValue(Object object) {
if (object == null || object.equals(Context.getUndefinedValue())) {
return null;
} else if (object.getClass().getPackage().getName().startsWith("java.")) {
return object;
} else if (object instanceof FunctionObject) {
throw new IllegalArgumentException(String.format("Cannot convert function object to value (object: %s)", object));
} else if (object instanceof Scriptable) {
return toMap((Scriptable) object);
} else {
throw new IllegalArgumentException(String.format("Can't convert JS object %s (type: %s) to native Java object", object, object.getClass().getName()));
}
}
}