The JSR223 Bindings class allows you to expose arbitrary Java objects to scripting languages. But they have to be objects. I would like to define a function quit() that can be called from the scripting environment that turns into quitObject.run() in Java. But JSR223 doesn't define the concept of a function object. Is there a language-independent way to do the following in Javascript, namely to take a Runnable() and create a function in the scripting environment?
static private Object asFunction(ScriptEngine engine, Runnable r)
throws ScriptException
{
final Bindings bindings = engine.createBindings();
bindings.put("r", r);
return engine.eval(
"(function (r) { var f = function() { r.run(); }; return f;})(r)",
bindings);
}
Runnable quitObject = /* get/create a Runnable here */
Bindings bindings = engine.createBindings();
bindings.put("quit", asFunction(engine, quitObject));
With the builtin Javascript support for JSR223 this creates a sun.org.mozilla.javascript.internal.InterpretedFunction which does what I want. But it obviously won't work in Jython or whatever, and I'd like to make this language-independent.
I don't want my script users to have to type quitObject.run() as that's clumsy, and I don't want to parse script input to find quit() as it could be buried within other code.
If you look at javascript engine source code you'll find how oracle/sun implemented 2 functions (print, and println) which are magically (or not so magically) present when you fire up your engine.
Those function are 'scripted' , which is more or less what you did.
What I would do is : load and evaluate a bootstrap.[language_extension] before evaluating any other input in the new context.
You could easily create such scripts for each language you intend to support.
Related
We have a requirement where we need to execute several short JavaScript snippets via Java. For that we are using the Nashorn engine that comes embedded along with Java. Java version is 1.8.0_191.
We initialize the script engine only once in the life cycle of the program. Then we pre-compile the snippets (as the snippets will repeat) in cache. We use pre-compiled scripts for eval. The bindings will be different each time and those are created before every execution.
Following is the snippet.
public class RuleExecutor {
private ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
private Map<String, CompiledScript> ruleCache = new HashMap<>();
..
....
public Object execute(Rule rule) {
Bindings bindings = engine.createBindings();
bindings.put(....);
compiled = ruleCache.get(rule.getTarget());
if (compiled == null) {
compiled = ((Compilable) engine).compile(rule.getExpr());
ruleCache.put(rule.getTarget(), compiled);
}
compiled.eval(bindings);
output = bindings.get(rule.getTarget());
return output;
}
The rule expressions can be arbitrary self contained scripts. However they repeat, hence the caching.
With the above, we are getting 120000 executions per minute.
How do we expedite the executions ?
Performance improved greatly on creating the Bindings only once during the program life cycle. After each execution, the bindings need to be cleared using bindings.clear()
I'm working with a PlayFramework example but I'm having trouble with the asynchronous calls. The function thenCombineAsync seems to only take in a BiFunction. I'd like to pass in multiple arguments to my render function (such as vendors) but I'm not sure how to add more.
return entryRepository.lookup(id).thenCombineAsync(vendorsFuture(entryOptional, vendors) -> {
// This is the HTTP rendering thread context
Entry c = entryOptional.get();
Form<Entry> entryForm = formFactory.form(Entry.class).fill(c);
return ok(views.html.editForm.render(id, entryForm, vendors));
}, httpExecutionContext.current());
From java code i am able to run the vbscript by using this code
Runtime.getRuntime().exec("wscript C:\\ppt\\test1.vbs ");
But want to know how to call the method of vbscript from java..for example in test1.vbs
Set objPPT = CreateObject("PowerPoint.Application")
objPPT.Visible = True
Set objPresentation = objPPT.Presentations.Open("C:\ppt\Labo.ppt")
Set objSlideShow = objPresentation.SlideShowSettings.Run.View
sub ssn1()
objPPT.Run "C:\ppt\Labo.ppt!.SSN"
End sub
how to call only ssn1() method from java.Otherwise can we run the macro of a power point from java code..kindly help!!
This should make you happy :) Go to the WScript section : http://technet.microsoft.com/library/ee156618.aspx
Here's my idea... in your vbscript file, make your script listen to a command line parameter that would specify which method to call. Then, in Java, you could only have to use this parameter whenever you want to call a specific method in the file.
Otherwise, if you want to access powerpoint in java, you will need to access its API like you did in vbscript, which is possible if vbscript can do it but the approach / syntax may change.
I'm not so much into the visual basic script side, but if you can expose your visual basic script as a COM object, the you can access the methods of it from java by usage of frameworks such as for example com4j:
http://com4j.java.net/
The PowerPoint application object's .Run method lets you call any public subroutine or function in any open presentation or loaded add-in
This post answers the OP's question:
Otherwise can we run the macro of a power point from java code..kindly help!!
(but does not address the original vbscript question)
There's the JACOB library, which stands for Java COM Bridge, you can find here: http://sourceforge.net/projects/jacob-project/?source=directory
With it you can invoke Excel, Word, Outlook, PowerPoint application object model methods.
I've tried this with Excel but not PowerPoint. (This is just some sample code, one might want to make it more object oriented.)
public class Excel {
private static ActiveXComponent xl = null;
public static Init() {
try {
ComThread.InitSTA();
xl = ActiveXComponent.connectToActiveInstance("Excel.Application.14");
// 14 is Office 2010, if you don't know what version you can do "Excel.Application"
if (xl==null) {
// code to launch Excel if not running:
xl = new ActiveXComponent("Excel.Application");
Dispatch.put(xl, "Visible", Constants.kTrue);
}
}
catch (Exception e) {
ComThread.Release();
}
}
public static String Run(String vbName) {
// Variant v = Dispatch.call(xl, "Run", vbName); // using string name lookup
Variant v = Dispatch.call(xl, 0x103, vbName); // using COM offset
// return Dispatch.get(this, "Name").getString();
return v.getString();
}
public static Variant Run1p(String vbName, Object param) {
// Variant v = Dispatch.call(xl, "Run", vbName, param);
return Dispatch.call(xl, 0x103, vbName, param);
// return Dispatch.get(this, "Name").getString();
}
public static Worksheet GetActiveWorksheet () {
// Dispatch d = xl.getProperty("ActiveSheet").toDispatch();
Dispatch d = Dispatch.get(xl, 0x133).toDispatch ();
return d; // you may want to put a wrapper around this...
}
}
Notes:
For Excel, at least, to get Run to invoke a VBA macro/subroutine several things have to be true:
The Excel workbook containing the macro must be "Active" (i.e. must
be the ActiveWorkbook) otherwise Run will not find the VBA subroutine. (However the workbook does not have to be
screen visible!! This means you can call a VBA Macro that is in an add-in!).
You can then pass the name of the macro using the following syntax as a string literal:
VBAProjectName.VBAModuleName.SubroutineName
For COM object invocations, you can use the name lookup version or the id number version. The id numbers come from the published COM interfaces (which you can find in C++ header files, or possibly have JACOB look them up for you).
If you successfully did the connection to Excel, be sure to call ComThread.Release() when you're done. Put it in some appropriately surrounding finally. If the process of your Java code terminates without calling it, the COM reference count on Excel will be wrong, and the Excel process will never terminate, even after you exit the Excel application. Once that happens, needless to say, Excel starts to behave screwy then (when you try to use it next, it runs but will fail to load any plug-ins/add-ons). If that happens (as it can during debugging esp. if you are bypassing finally's for better debugging) you have to use the task manager to kill the Excel process.
How can I execute a local file from JavaScript running within Rhino in Java? I will consider any method that works from within the Rhino environment. My current exploration of the issue is below.
I am attempting this through java.lang.Runtime.exec, with help from the Mozilla "Scripting Java" tutorial i can access it. However this is a restricted action so calling it directly gives an access control exception.
To solve this I need to use the AccesController.doPrivileged method. An example of using this in Java is below;
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// Code goes here. Any permission checks within this
// run method will require that the intersection of the
// callers protection domain and the snapshot's
// context have the desired permission.
}
The road block is replicating the construction of a PrivilegedAction in javascript.
var ourRuntime = Packages.java.lang.Runtime.getRuntime();
//ourRuntime.exec("notepad.exe") //will raise Access Control Exception
var controller = Packages.java.security.AccessController.doPrivileged
var action = new Packages.java.security.PrivilegedAction(ourRuntime.exec("notepad.exe")) // somehow make this wwrk
controller.doPrivileged(action)
Mozilla Scripting Java
java.securit.AccessController
Rhino is supported by Java 6 scripting API, so you can wrap eval of your script with doPrivileged and execute entire script with necessary permissions. Example of java scripting API combined with doPrivileged is here
I've had success starting KWrite (for example) this way. I basically expose the Runtime object to the embedded JavaScript interpreter.
public class RunBasicScript {
public static void main(String[] args) {
// Get a handle to the JavaScript context
Context cx = Context.enter();
try
{
// Set up the standard JavaScript objects
// like Object, Function etc.
Scriptable scope = cx.initStandardObjects();
// Make Runtime.getRuntime available to our JavaScript code
Object exec = Context.javaToJS(Runtime.getRuntime(), scope);
ScriptableObject.putProperty(scope, "exec", exec);
// Build our awesome script
String script = "exec.exec('kwrite');";
// Now we execute the script
Object obj = cx.evaluateString(scope, script, "Testing", 1, null);
}
catch (Exception e)
{
System.err.println("Error : " + e);
}
finally
{
// We need to exit the Context.
Context.exit();
}
}
}
I have built a variety of little scripts using Ruby's very simple Queue class, and share the Queue between Ruby and JRuby processes using DRb. It would be nice to be able to access these from Scala (and maybe Java) using JRuby.
I've put together something Scala and the JSR-223 interface to access jruby-complete.jar.
import javax.script._
class DRbQueue(host: String, port: Int) {
private var engine = DRbQueue.factory.getEngineByName("jruby")
private var invoker = engine.asInstanceOf[Invocable]
engine.eval("require \"drb\" ")
private var queue = engine.eval("DRbObject.new(nil, \"druby://" + host + ":" + port.toString + "\")")
def isEmpty(): Boolean = invoker.invokeMethod(this.queue, "empty?").asInstanceOf[Boolean]
def size(): Long = invoker.invokeMethod(this.queue, "length").asInstanceOf[Long]
def threadsWaiting: Long = invoker.invokeMethod(this.queue, "num_waiting").asInstanceOf[Long]
def offer(obj: Any) = invoker.invokeMethod(this.queue, "push", obj.asInstanceOf[java.lang.Object])
def poll(): Any = invoker.invokeMethod(this.queue, "pop")
def clear(): Unit = { invoker.invokeMethod(this.queue, "clear") }
}
object DRbQueue {
var factory = new ScriptEngineManager()
}
(It conforms roughly to java.util.Queue interface, but I haven't declared the interface because it doesn't implement the element and peek methods because the Ruby class doesn't offer them.)
The problem with this is the type conversion. JRuby is fine with Scala's Strings - because they are Java strings. But if I give it a Scala Int or Long, or one of the other Scala types (List, Set, RichString, Array, Symbol) or some other custom type.
This seems unnecessarily hacky: surely there has got to be a better way of doing RMI/DRb interop without having to use JSR-223 API. I could either make it so that the offer method serializes the object to, say, a JSON string and takes a structural type of only objects that have a toJson method. I could then write a Ruby wrapper class (or just monkeypatch Queue) to would parse the JSON.
Is there any point in carrying on with trying to access DRb from Java/Scala? Might it just be easier to install a real message queue? (If so, any suggestions for a lightweight JVM-based MQ?)
Its worthwile to install a enterprise message queue because DRB and ruby is not the technology for Queuing.
In my opinion you are creating a tech debt here.
If you want to persist on the same path you can use the twitter queuing they abandoned starling.
I think there are heaps of queues available in the Java world JMS.
If you wrote a DRB server you could have sufficed even doing an array implementing the queue interface thats dead simple!
then scale appropriately
http://www.java-tips.org/java-se-tips/java.lang/array-based-queue-implementation-in-java.html
In my opinion stick to proven enterprise technologies and not hacky unproven ones, I have leanrt that the hard way.