Why does Rhino Javascript engine complain a function does not exist? - java

Please forgive me, as I am a Java man dabbling in Javascript business :)
I wanted to be able to define a set of integration test cases to be easy to script against a Java application. I thought Javascript would be a perfect language to script against. To that end, I am using the Rhino engine that comes with JDK 7, via Java's Scripting API. The scripts would have access to Java classes already defined in the application, and could be reused to define use case scenarios for integration testing.
In the Java application, I have binded the javascript engine itself to the script as jsengine, so that I can load javascript files (Including a JavaScript file during Rhino eval).
I have two Javascript files, as defined below:
Function.js:
function send(msg) {
send.sendMessage(msg);
}
TestCase.js
jsengine.eval(new java.io.FileReader("Function.js");
sendMsg("Test Message");
I also have the following object defined and binded to the script as "javaobj":
public class TestConnection {
...
public void send(String message) {
// Code to send the string message via JMS
}
}
However, the Rhino engine complains with the following Exception. It seems to not like calling the javaobj's send method, for some reason.
javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: TypeError: Cannot find function send in object
function sendMsg(msg) {...}. (TestCase.js#3) in TestCase.js at line number 3
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:224)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:212)
at com.foo.test.scenario.JavaScriptEngine.execute(JavaScriptEngine.java:56)
at com.foo.test.TestSuite.start(TestSuite.java:88)
at com.foo.test.TestSuite.main(TestSuite.java:41)
Caused by: sun.org.mozilla.javascript.internal.EcmaError: TypeError: Cannot find function send in object
function sendMsg(msg) {...}. (TestCase.js#3) in TestCase.js at line number 3
at sun.org.mozilla.javascript.internal.ScriptRuntime.constructError(ScriptRuntime.java:3773)
at sun.org.mozilla.javascript.internal.ScriptRuntime.constructError(ScriptRuntime.java:3751)
at sun.org.mozilla.javascript.internal.ScriptRuntime.typeError(ScriptRuntime.java:3779)
at sun.org.mozilla.javascript.internal.ScriptRuntime.typeError2(ScriptRuntime.java:3798)
at sun.org.mozilla.javascript.internal.ScriptRuntime.notFunctionError(ScriptRuntime.java:3869)
at sun.org.mozilla.javascript.internal.ScriptRuntime.getPropFunctionAndThisHelper(ScriptRuntime.java:2345)
at sun.org.mozilla.javascript.internal.ScriptRuntime.getPropFunctionAndThis(ScriptRuntime.java:2312)
at sun.org.mozilla.javascript.internal.Interpreter.interpretLoop(Interpreter.java:1524)
at sun.org.mozilla.javascript.internal.Interpreter.interpret(Interpreter.java:854)
at sun.org.mozilla.javascript.internal.InterpretedFunction.call(InterpretedFunction.java:164)
at sun.org.mozilla.javascript.internal.ContextFactory.doTopCall(ContextFactory.java:429)
at com.sun.script.javascript.RhinoScriptEngine$1.superDoTopCall(RhinoScriptEngine.java:116)
at com.sun.script.javascript.RhinoScriptEngine$1.doTopCall(RhinoScriptEngine.java:109)
at sun.org.mozilla.javascript.internal.ScriptRuntime.doTopCall(ScriptRuntime.java:3163)
at sun.org.mozilla.javascript.internal.InterpretedFunction.exec(InterpretedFunction.java:175)
at sun.org.mozilla.javascript.internal.Context.evaluateReader(Context.java:1159)
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:214)
... 4 more
Has anyone ever encountered this type of issue with Rhino?
P.S. This question seems related, but no answer given as well (TypeError in Rhino: migration from Java 6 to Java 7)

Looks like I found my own answer. There was a name conflict between the Javascript function and the name of the binded Java object. Both having the same name, the engine tries to call a non-existent method on a Function object!
Silly me... :P

Related

Using enums with LispWorks' Java interface

I'm trying to use the EWS Java library (link) with LispWorks 7.1.2 Win32's Java interface. I am somewhat familiar with basic Java concepts but have no experience with the Java language. This is the code I am trying to mimic:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
So I figured I would create an ExchangeVersion object (which is an enum), set it to the value "Exchange2010_SP2", and pass it to another create-java-object expression for the ExchangeService object.
This was my first step:
(create-java-object "microsoft.exchange.webservices.data.core.ExchangeService"
"microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion.Exchange2010_SP2")
However, I get the following error message: constructor of microsoft/exchange/webservices/data/core/ExchangeService first arguments is wrong type, wanted microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion got "microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion.Exchange2010_SP2"
OK, so then I tried this:
(create-java-object "microsoft.exchange.webservices.data.core.ExchangeService"
"microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion")
which gave me the error: constructor of microsoft/exchange/webservices/data/core/ExchangeService first arguments is wrong type, wanted microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion got "microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion". Which doesn't make much sense to me. So finally I tried to create a standalone ExchangeVersion object:
(create-java-object "microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion")
which led to this error message: CREATE-JAVA-OBJECT: : Failed to find constructors for class "microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion".
I wonder if anyone have suggestions on what am I doing wrong?
Many Thanks!

Py4j launch_gateway not connecting properly

I am trying to use py4j to open up a gateway that I can use to pass objects from java into python. When I try to open a gateway with the py4j function launch_gateway it does not seem to properly connect to my Java class. However, when I launch my java class in the command line and then connect to it in python using JavaGateway everything works as expected. I would like to be able to use the built in method as I am sure that I am not accounting for things that have already been considered in the design of py4j, but I'm just not sure what I'm doing wrong.
Let's say I wanted to create a gateway to the class sandbox.demo.solver.UtilityReporterEntryPoint.class. In the command line I can do this by executing the following:
java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer
This launches as expected and I can use the methods in my class from within python after connecting to the gateway. So far so good.
My understanding of the py4j documentation would lead me to believe I should do the following to launch the gateway in python:
port = launch_gateway(classpath='sandbox.demo.solver.UtilityReporterEntryPoint')
params = GatewayParameters(port=port)
gateway= JavaGateway(gateway_parameters=params)
I get no errors when executing these three lines, but when I try to access my java class methods with gateway.entry_point.someMethod() it fails with the following error:
Py4JError: An error occurred while calling t.getReport. Trace:
py4j.Py4JException: Target Object ID does not exist for this gateway :t
at py4j.Gateway.invoke(Gateway.java:277)
at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
at py4j.commands.CallCommand.execute(CallCommand.java:79)
at py4j.GatewayConnection.run(GatewayConnection.java:214)
at java.lang.Thread.run(Thread.java:745)
Obviously something is not getting called correctly within launch_gateway or I am feeding it the wrong information.
In the py4j source code for launch_gateway you can see that given the inputs you provide and those constructed by the function, a command is constructed that eventually gets called by subprocess.Popen. So given the input passed to launch_gateway above the command passed into Popen would be:
command = ['java', '-classpath', '/Users/grr/anaconda/share/py4j/py4j0.10.4.jar:sandbox.demo.solver.UtilityReporterEntryPoint', 'py4j.GatewayServer', '0']
Passing this command to Popen returns the listening port as expected. However, connecting to this listening port still does not allow access to my class methods.
Finally, passing the command as a single string to Popen without the final argument ('0'), properly launches a gateway which again operates as expected. Having taken a glance at the Java source code for py4j.GatewayServer.class this makes no sense as the main method seems to indicate that the class should exit with status 1 if the length of arguments is 0.
At this point I'm kind of at a loss. I can hack my way into a workable solution, but as I said I'm sure that ignores important aspects of the gateway behavior and I don't like hacky solutions. I'd love to tag #Barthelemy in this one, but hopefully he reads this. Thanks in advance for any help.
EDIT
For now I have been able to work around this issue with the following steps.
Package entire project including all external dependencies into a single jar file magABM-all.jar, with 'Main-Class' set to UtilityReporterEntryPoint.
Include if...else block regarding presence of --die-on-exit exactly like it is in GatewayServer.java
Use subprocess.Popen to call the command to run the project jar.
UtilityReporterEntryPoint.java
public static void main(String[] args) throws IOException {
GatewayServer server = new GatewayServer(new UtilityReporterEntryPoint());
System.out.println("Gateway Server Started");
server.start();
if (args[0].equals("--die-on-exit")) {
try {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF-8")));
stdin.readLine();
System.exit(0);
} catch (java.io.IOException e) {
System.exit(1);
}
}
}
app.py
def setup_gateway()
"""Launch a py4j gateway using UtilityReporterEntryPoint."""
process = subprocess.Popen('java -jar magABM-all.jar --die-on-exit', shell=True)
time.sleep(0.5)
gateway = JavaGateway()
return gateway
In this way I can still use gateway.shutdown if necessary and if the python process that starts the py4j gateway dies or is closed the gateway will be closed.
N.B I would by no means consider this a final solution as py4j was written by much smarter individuals with a clear purpose in mind and I am sure that there is a way to manage this exact workflow within the confines of py4j. This is just a stopgap solution.
There are a few issues:
The classpath parameter in launch_gateway should be a directory or a jar file, not a class name. For example, if you want to include additional Java libraries, you would add them to the classpath parameter.
The error you receive when you call gateway.entry_point.someMethod() means that you have no entry point. When you call launch_gateway, the JVM is started with GatewayServer.main, which launches a GatewayServer with no entry point: GatewayServer server = new GatewayServer(null, port). It is not possible currently to use launch_gateway and specify an entry point.
When you start the JVM with java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer I believe the JVM uses UtilityReporterEntryPoint as the main class. Although you did not provide the code, I assume that this class has a main method and that it launches a GatewayServer with an instance of UtilityReporterEntryPoint as the entry point. Note that there is a whitespace between the colon and the class name so UtilityReporterEntryPoint is seen as the main class and not as being part of the classpath.

Calling methods between groovy scripts with correct parameters

I just started learning about groovy and trying to transpose my java code to groovy scripts. Usually java allows you have a class with only methods that you can call from other classes. I wanted to translate that to groovy. I have in one file - lets call it File1- a method like this:
def retrieveData(String name){
// do something
}
and in the second file, File2, I call File1 like this:
def file1Class = this.class.classLoader.parseClass(new File("../File1.groovy"))
and then try to call the method in File1 like this:
def data = file1Class.retrieveData("String")
but it keeps giving me this error - MissingMethodException:
groovy.lang.MissingMethodException: No signature of method: static File1.retrieveData() is applicable for argument types: (java.lang.String) values: [String] Possible solutions: retrieveData(java.lang.String)
so it does recognize that I am sending in the correct number of parameters and even the correct object, but it isn't running the method as it should?
Is there something I am missing? I tried to remove the object definition from the method - in other words - like this:
def retrieveData(name){
// do something
}
but that didn't work either. I am clueless about what the next step would be. Can anyone please help push me in the right direction? I would greatly appreciate it.
See the answer provided in this StackOverflow reponse.
Use the GroovyScriptEngine class. What does the GroovyScriptEngine do? From the docs:
Specific script engine able to reload modified scripts as well as
dealing properly with dependent scripts.
See the example below.
def script = new GroovyScriptEngine( '.' ).with {
loadScriptByName( '..\File1.groovy' )
}
this.metaClass.mixin script
retrieveData()
Note how we use the loadScriptByNamemethod to
Get the class of the scriptName in question, so that you can
instantiate Groovy objects with caching and reloading.
This will allow you to access Groovy objects from files however you please.

Using Inline::Java in perl with threads

I am writing a trading program in perl with the newest Finance::InteractiveBrokers::TWS
module. I kick off a command line interface in a separate thread at the
beginning of my program but then when I try to create a tws object, my program
exits with this message:
As of Inline v0.30, use of the Inline::Config module is no longer supported or
allowed. If Inline::Config exists on your system, it can be removed. See the
Inline documentation for information on how to configure Inline. (You should
find it much more straightforward than Inline::Config :-)
I have the newest versions of Inline and Inline::Java. I looked at TWS.pm and it doesn't seem to be using Inline::Config. I set 'SHARED_JVM => 1' in the 'use Inline()' and 'Inline->bind()' calls in TWS.pm but that did not resolve the issue...
My Code:
use Finance::InteractiveBrokers::TWS;
use threads;
use threads::shared;
our $callback;
our $tws;
my $interface = UserInterface->new();
share($interface);
my $t = threads->create(sub{$interface->runUI()});
$callback= TWScallback->new();
$tws = Finance::InteractiveBrokers::TWS->new($manager); #This is where the program fails
So is Inline::Config installed on your system or not? A cursory inspection of the code is not sufficient to tell whether Perl is loading a module or not. There are too many esoteric ways (some intentional and some otherwise) to load a package or otherwise populate a namespace.
The error message in question comes from this line of code in Inline.pm:
croak M14_usage_Config() if %main::Inline::Config::;
so something in your program is populating the Inline::Config namespace. You should do what the program instructs you to do: find out where Inline/Config.pm is installed on your system (somewhere in your #INC path) and delete it.

Is it possible to connect to java from a firefox extension in the way described below

My objective is to:
Use Firefox to take a series of screendump images and save on the local Filesystem with a reference.
also via my custom extension send a reference to a java program that performs the ftp to a remote server.
This is pretty intimidating
https://developer.mozilla.org/en/JavaScript/Guide/LiveConnect_Overview
Is it possible?
Can you see any potential problems or things Id need to consider?
(I'm aware of file system problems but its for local use only)
Are there any tutorials / references that might be handy?
Ive tried linking to java but hit problems using my own classes Im getting a class not found exception when I try
JS:
var myObj = new Packages.message();
Java file:
public class Message {
private String message;
public Message()
{
this.message = "Hello";
}
public String getMessage()
{
return this.message;
}
}
not using a package java side.
Just trying to run a quick test to see if it is viable and under time pressure from those above so just wanted to see if it was a worthwhile time investment or a dead end
You might consider this Java tutorial instead: http://www.oracle.com/technetwork/java/javase/documentation/liveconnect-docs-349790.html.
What Java version are you using? Is your message class an object inside Java applet?

Categories