Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CompiledScript Version #9

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 31 additions & 16 deletions src/main/java/com/winterbe/react/React.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,58 @@

import jdk.nashorn.api.scripting.NashornScriptEngine;

import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.*;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class React {

private ThreadLocal<NashornScriptEngine> engineHolder = new ThreadLocal<NashornScriptEngine>() {
private ThreadLocal<CompiledScript> scriptHolder = new ThreadLocal<CompiledScript>(){
@Override
protected NashornScriptEngine initialValue() {
NashornScriptEngine nashornScriptEngine = (NashornScriptEngine) new ScriptEngineManager().getEngineByName("nashorn");
protected CompiledScript initialValue() {

String script = Stream.of("static/nashorn-polyfill.js",
"static/vendor/react.js",
"static/vendor/showdown.min.js",
"static/commentBox.js")
.map(ThrowingFunction.wrap(React::slurp)).collect(Collectors.joining());

try {
nashornScriptEngine.eval(read("static/nashorn-polyfill.js"));
nashornScriptEngine.eval(read("static/vendor/react.js"));
nashornScriptEngine.eval(read("static/vendor/showdown.min.js"));
nashornScriptEngine.eval(read("static/commentBox.js"));
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
Compilable compilingEngine = (Compilable) engine;
CompiledScript cs = compilingEngine.compile(script);

// this is a noop but required to initialize the context of the compiled script
cs.eval(engine.getBindings(ScriptContext.ENGINE_SCOPE));
return cs;
} catch (ScriptException e) {
throw new RuntimeException(e);
}
return nashornScriptEngine;
}
};

public String renderCommentBox(List<Comment> comments) {
try {
Object html = engineHolder.get().invokeFunction("renderServer", comments);
return String.valueOf(html);
CompiledScript cscript = scriptHolder.get();

Invocable invocable = (Invocable) cscript.getEngine();

return String.valueOf(invocable.invokeFunction("renderServer", comments));
}
catch (Exception e) {
throw new IllegalStateException("failed to render react component", e);
}
}

private Reader read(String path) {
InputStream in = getClass().getClassLoader().getResourceAsStream(path);
return new InputStreamReader(in);
public static String slurp(String path) throws java.io.IOException {
try (InputStream resource = React.class.getClassLoader().getResourceAsStream(path)) {
return String.join("\n", new BufferedReader(new InputStreamReader(resource,
StandardCharsets.UTF_8)).lines().collect(Collectors.toList())) + "\n";
}
}
}
30 changes: 30 additions & 0 deletions src/main/java/com/winterbe/react/ThrowingFunction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.winterbe.react;
import java.util.function.Function;

/**
* Checked exceptions side effects which make functional programming hard.
* Here we convert checked to unchecked which is something Spring has done for years to compose
* interfaces here we are doing it to be able to properly compose functions.
*
* https://stackoverflow.com/a/29691649/329496
* @param <T>
* @param <R>
*/
@FunctionalInterface
public interface ThrowingFunction<T,R> extends Function<T,R> {

@Override
public default R apply(T t) {
try {
return throwingApply(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public static<T,R> Function<T,R> wrap(ThrowingFunction<T,R> f) {
return f;
}

R throwingApply(T t) throws Exception;
}
5 changes: 5 additions & 0 deletions src/test/java/com/winterbe/react/ReactTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
import static org.junit.Assert.assertThat;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
Expand All @@ -15,6 +19,7 @@ public class ReactTest {

@Test
public void testRenderCommentBox() throws Exception {

List<Comment> comments = new ArrayList<>();
comments.add(new Comment("Peter Parker", "This is a comment."));
comments.add(new Comment("John Doe", "This is *another* comment."));
Expand Down