-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#1 replace creation of ScriptEngines bound to each thread with Thread…
…Local with a pool of Nashorn ScriptEngines (w/ use of commons-pool)
- Loading branch information
Showing
5 changed files
with
123 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package dasniko.ozark.react; | ||
|
||
import org.apache.commons.pool2.ObjectPool; | ||
import org.apache.commons.pool2.impl.GenericObjectPool; | ||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig; | ||
|
||
import javax.enterprise.context.ApplicationScoped; | ||
import javax.enterprise.context.Initialized; | ||
import javax.enterprise.event.Observes; | ||
import javax.enterprise.inject.Produces; | ||
import javax.script.ScriptEngine; | ||
|
||
/** | ||
* @author Niko Köbler, http://www.n-k.de, @dasniko | ||
*/ | ||
@ApplicationScoped | ||
public class NashornPool { | ||
|
||
private GenericObjectPool<ScriptEngine> pool; | ||
|
||
public void init(@Observes @Initialized(ApplicationScoped.class) Object init) { | ||
GenericObjectPoolConfig config = new GenericObjectPoolConfig(); | ||
config.setMinIdle(1); | ||
|
||
pool = new GenericObjectPool<>(new NashornPoolFactory(), config); | ||
} | ||
|
||
@Produces | ||
public ObjectPool<ScriptEngine> getObjectPool() { | ||
return this.pool; | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package dasniko.ozark.react; | ||
|
||
import org.apache.commons.pool2.BasePooledObjectFactory; | ||
import org.apache.commons.pool2.PooledObject; | ||
import org.apache.commons.pool2.impl.DefaultPooledObject; | ||
|
||
import javax.script.ScriptEngine; | ||
import javax.script.ScriptEngineManager; | ||
import javax.script.ScriptException; | ||
import java.io.File; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.io.Reader; | ||
import java.net.URISyntaxException; | ||
import java.net.URL; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* @author Niko Köbler, http://www.n-k.de, @dasniko | ||
*/ | ||
public class NashornPoolFactory extends BasePooledObjectFactory<ScriptEngine> { | ||
|
||
private static final String DEFAULT_JS_RESOURCE_PATH = "/js"; | ||
private static final String RESOURCE_PATH = System.getProperty("mvc.reactjs.resourcePath", DEFAULT_JS_RESOURCE_PATH); | ||
|
||
@Override | ||
public ScriptEngine create() throws Exception { | ||
ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("nashorn"); | ||
|
||
// initial basically needed files for dealing with react | ||
List<String> jsResources = new ArrayList<>(); | ||
jsResources.add("nashorn-polyfill.js"); | ||
|
||
// add all resources from custom application | ||
jsResources.addAll(getAllFilesFromResourcePath()); | ||
// and load/evaluate them within nashorn | ||
jsResources.forEach(p -> { | ||
try { | ||
nashorn.eval(read(p)); | ||
} catch (ScriptException e) { | ||
throw new RuntimeException(e); | ||
} | ||
}); | ||
|
||
return nashorn; | ||
} | ||
|
||
@Override | ||
public PooledObject<ScriptEngine> wrap(ScriptEngine scriptEngine) { | ||
return new DefaultPooledObject<>(scriptEngine); | ||
} | ||
|
||
private List<String> getAllFilesFromResourcePath() { | ||
URL url = this.getClass().getClassLoader().getResource(RESOURCE_PATH); | ||
if (url != null && url.getProtocol().equals("file")) { | ||
try { | ||
return Arrays.stream(new File(url.toURI()).list()).map(p -> RESOURCE_PATH + "/" + p).collect(Collectors.toList()); | ||
} catch (URISyntaxException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} else { | ||
// TODO do something | ||
return new ArrayList<>(); | ||
} | ||
} | ||
|
||
private Reader read(String path) { | ||
InputStream in = getClass().getClassLoader().getResourceAsStream(path); | ||
return new InputStreamReader(in); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,34 @@ | ||
package dasniko.ozark.react; | ||
|
||
import jdk.nashorn.api.scripting.ScriptObjectMirror; | ||
import org.apache.commons.pool2.ObjectPool; | ||
|
||
import javax.inject.Inject; | ||
import javax.script.Invocable; | ||
import javax.script.ScriptEngine; | ||
import javax.script.ScriptEngineManager; | ||
import javax.script.ScriptException; | ||
import java.io.File; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.io.Reader; | ||
import java.net.URISyntaxException; | ||
import java.net.URL; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* @author Niko Köbler, http://www.n-k.de, @dasniko | ||
*/ | ||
public class React { | ||
|
||
private static final String DEFAULT_JS_RESOURCE_PATH = "/js"; | ||
private static final String RESOURCE_PATH = System.getProperty("mvc.reactjs.resourcePath", DEFAULT_JS_RESOURCE_PATH); | ||
|
||
private ThreadLocal<ScriptEngine> engineHolder = ThreadLocal.withInitial(() -> { | ||
ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("nashorn"); | ||
|
||
// initial basically needed files for dealing with react | ||
List<String> jsResources = new ArrayList<>(); | ||
jsResources.add("nashorn-polyfill.js"); | ||
|
||
// add all resources from custom application | ||
jsResources.addAll(getAllFilesFromResourcePath()); | ||
// and load/evaluate them within nashorn | ||
jsResources.forEach(p -> { | ||
try { | ||
nashorn.eval(read(p)); | ||
} catch (ScriptException e) { | ||
throw new RuntimeException(e); | ||
} | ||
}); | ||
|
||
return nashorn; | ||
}); | ||
|
||
private List<String> getAllFilesFromResourcePath() { | ||
URL url = this.getClass().getClassLoader().getResource(RESOURCE_PATH); | ||
if (url != null && url.getProtocol().equals("file")) { | ||
try { | ||
return Arrays.asList(new File(url.toURI()).list()).stream().map(p -> RESOURCE_PATH + "/" + p).collect(Collectors.toList()); | ||
} catch (URISyntaxException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} else { | ||
// TODO do something | ||
return new ArrayList<>(); | ||
} | ||
} | ||
@Inject | ||
private ObjectPool<ScriptEngine> scriptEnginePool; | ||
|
||
String render(String function, Object object) { | ||
try { | ||
Object html; | ||
ScriptEngine scriptEngine = scriptEnginePool.borrowObject(); | ||
if (function.contains(".")) { | ||
String[] parts = function.split("\\."); | ||
html = ((ScriptObjectMirror) engineHolder.get().get(parts[0])).callMember(parts[1], object); | ||
html = ((ScriptObjectMirror) scriptEngine.get(parts[0])).callMember(parts[1], object); | ||
} else { | ||
html = ((Invocable) engineHolder.get()).invokeFunction(function, object); | ||
html = ((Invocable) scriptEngine).invokeFunction(function, object); | ||
} | ||
scriptEnginePool.returnObject(scriptEngine); | ||
return String.valueOf(html); | ||
} 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); | ||
} | ||
} | ||
} |