I'm trying to embed groovy into a large Java application.
The Java application should load some utility Groovy scripts at startup.
The application should then run other scripts multiple times. There is also a need to enter some code at a GUI and execute it at user request.
The problem I'm facing is this:
I am loading the startup script like this:
GroovyShell gShell = new GroovyShell();
gShell.evaluate(new FileReader("scripts/autoload.groovy"));
Suppose my autoload.groovy contains:
def prnt(m) {
println("From Groovy: " + m);
}
This works fine. But when I want to run a user command using:
gShell.evaluate("prnt 66");
I get the error:
groovy.lang.MissingMethodException: No signature of method: Script2.prnt() is applicable for argument types: (java.lang.Integer) values: [66]
How can my user script access the methods already loaded?
Note: I have also tried "autoload.prnt 88", and still get the error.
Each evaluate call is compiled and run as a separate Script, and
def prnt(m) {
println("From Groovy: " + m);
}
defines a method in the Script class generated from autoload.groovy, which is not accessible from the subsequent "calling" script. However, the scripts run by the same GroovyShell share the same binding, so you can store values in the binding from one script and access them in another. Storing a value in the binding is simply a case of assigning the value to an otherwise undeclared variable:
prnt = { m ->
println("From Groovy: " + m);
}
This stores a closure in the binding variable prnt, and you can call the closure from other scripts in the same shell. Note that
def prnt = { m ->
or
Closure prnt = { m ->
would not work, because the def or type makes it a local variable declaration (private to this particular script) rather than an assignment to the binding.
Related
In our project we are using Lightbend Config / TypesafeConfig.
I can run my program with java -jar. The configuration of my program can also be done by using command line parameters.
Example:
java -jar simpleclient.jar -Dservice.url="http://localhost:8123"
Now I introduced https://picocli.info/ to have a better command line handling for my application.
The problem I'm facing now ist, that picocli doesn't allow the usage of -D... parameters in the standard configuration.
How can this be changed?
When you say “picocli doesn’t allow the use of -D... options”, I assume you mean you want to allow end users to set system properties with the -Dkey=value syntax. When such parameters are passed to the application, the application needs to use these values to set system properties, as shown below.
First, users can set system properties by passing -Dkey=value parameters to the java process instead of to the main class in the jar. In the below invocation, the system properties are set directly and are not passed as parameters to the application:
java -Dservice.url="http://localhost:8123" -jar simpleclient.jar
Secondly, you can define a -D option in your application that sets system properties:
#Command
class SimpleClient {
#Option(names = "-D")
void setProperty(Map<String, String> props) {
props.forEach((k, v) -> System.setProperty(k, v == null ? "" : v));
}
}
we are creating a groovy shell object and passing the bindings to the shell then
the parsing the groovy code using the shell and initializing a Script object as below
GroovyShell shell = new GroovyShell(binding);
Script script = shell.parse(//groovy code );
then we are storing the script object in a Concurrent hashmap and running the script using script.run() fetching the script from this hashmap , But the groovy code in the script does not executes completely say 1 in 100 runs . we had placed logs in the //groovy code that shows the code did not run completely and neither any exception is thrown
when you run the same instance of Script in different threads at the same time it could be stopped just by logic of your script.
if you want ta cache the parsed script, then store into your map the parsed class and not the instance of script and for each run re-bind variables.
the following code snippet should give you an idea how to do that:
scriptMap = new HashMap()
Script getScript(String code){
Class<Script> scriptClass = scriptMap.get(code);
if(scriptClass)return script.newInstance();
GroovyShell shell = new GroovyShell();
Script script = shell.parse( code );
scriptMap.put(code, script.getClass());
return script;
}
Object runScript(String code, Map variables){
Script script=getScript(code);
script.setBinding( new Binding(variables) );
return script.run();
}
println runScript("a+b", [a:2,b:7])
println runScript("(b-a)*3", [a:7,b:9])
println scriptMap
I'm building a Python UI using Tkinter. For the needs of the program, I've to connect Python with Java to do some stuff, so I'm using a simple Jython script as a linker. I cant use Tkinter with Jython because it's not supported.
Python (ui.py) -> Jython (linker.py) -> Java (compiled in jars)
To call the Jython function in Python I use subprocess as follows:
ui.py:
cmd = 'jython linker.py"'
my_env = os.environ
my_env["JYTHONPATH"] = tons_of_jars
subprocess.Popen(cmd, shell=True, env=my_env)
Then, in the Jython file, linker.py, I import the Java classes already added on the JYTHONPATH, and I create an object with the name m and call to some functions of the Java class.
linker.py:
import handler.handler
m = handler.handler(foo, moo, bar)
m.schedule(moo)
m.getFullCalendar()
m.printgantt()
The thing is that I've created a m object, that will be destroyed after the execution of jython linker.py ends.
So the question is: Is possible to save that m object somewhere so I can call it from ui.py whenever I want? If it's not possible, is there any other way to do this?
Thanks in advance.
I finally solved it by using ObjectOutputStream.
from java import io
def saveObject(x, fname="object.bin"):
outs = io.ObjectOutputStream(io.FileOutputStream(fname))
outs.writeObject(x)
outs.close()
def loadObject(fname="object.bin"):
ins = io.ObjectInputStream(io.FileInputStream(fname))
x=ins.readObject()
ins.close()
return x
I am trying to call a java script function from java code.
Here is my Java code
public static void main(String[] args) throws FileNotFoundException {
try {
/**
* To call a anonymous function from java script file
*/
ScriptEngine engine = new ScriptEngineManager()
.getEngineByName("javascript");
FileReader fr = new FileReader("src/js/MySpec.js");
engine.eval(fr);
} catch (ScriptException scrEx) {
scrEx.printStackTrace();
}
}
Here is my java script file:
(function() {
alert("Hello World !!!");
})();
But when I run main method of driver class it is giving me error as below:
Exception in thread "main" javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "alert" is not defined. (<Unknown source>#2) in <Unknown source> at line number 2
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:110)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:232)
at Java6RhinoRunner.load(Java6RhinoRunner.java:42)
at Java6RhinoRunner.main(Java6RhinoRunner.java:12)
What I know is that it need some script engine to execute it.
For that I added rhino.jar file in to my class path.But this is not working.
I an not getting how to solve this error.
Please help.Thanks in advance.
alert is not part of JavaScript, it's part of the window object provided by web browsers. So it doesn't exist in the context you're trying to use it in. (This is also true of setInterval, setTimeout, and other timer-related stuff, FYI.)
If you just want to do simple console output, Rhino provides a print function to your script, so you could replace alert with print. Your script also has access to all of the Java classes and such, so for instance java.lang.System.out.println('Hello'); would work from your JavaScript script (although it's a bit redundant with the provided print function). You can also make Java variables available to your script easily via ScriptEngine.put, e.g:
engine.put("out", System.out);
...and then in your script:
out.println('Hello from JavaScript');
...so that's a third way to do output from the script. :-)
See the discussion in the javax.script package documentation, in particular ScriptEngine#put, or for more complex cases, Bindings (and SimpleBindings) and ScriptContext.
public class HelloWorld{
public static void add(int a, int b){
System.out.println(a+b);
}
}
and I load it into oracle via
loadjava -user system/admin Helloworld.class
This words fine.
After that I write this procedure:
create or replace
PROCEDURE start_helloworld(a in number, b in number)
AS language java
name 'HelloWorld.add(int,int)';
I want to be able to call the procedure in PL/SQL:
exec start_helloworld(1,1);
but it gives the error I mentioned.
You can't do console output from Oracle java code, since it's running within the database. Perhaps if you passed in and in/out variable, assigned the output of your arithmetic assignment to the variable and output that in the calling PL/SQL block:
var mynum NUMBER
exec start_helloworld(1,1,:mynum);
print mynum;
You would of course need to modify your java and PL/SQL wrapper to add the new parameter:
public static void add(int a, int b, int c){
c = a+b;
}
and
create or replace
PROCEDURE start_helloworld(a in number, b in number, c in out number)
AS language java
name 'HelloWorld.add(int,int,int)';
I am not an Oracle expert by any means but I have hit this issue recently so I just wanted to comment. For some reason I can't just leave a comment, So here's my answer.
Comment:
When I get the Ora-29516 error, it comes with a reason description. Is there more to the error when you get it?
Answer:
If your Aurora Assertion error comes with the reason "Uncaught exception System error: java/lang/UnsupportedClassVersionError" =>
I get this error when the version of Java I used to compile the class file isn't the same as the version of Java in Oracle (1.5.0 in 11g). To be sure you match perfectly, let Oracle compile the class for you. You'll get two benefits: 1) You will be sure the Java version matches exactly. 2) You'll have the source code loaded as a database "JAVA SOURCE" object for future reference. For security purposes, you may want to lock it down.
loadjava -user scott/tiger -resolve HelloWorld.java
By using the source file with the resolve option, Oracle will create the source object and compile the code for the class object. If you leave out the -resolve option, Oracle will create the source object and only compile it when it is called. I presume this may have good flexibility options but performance drawbacks.
This error occurs because incompatibility of different java versions in oracle and java compiler.
-> oracle version:
--TO CHECK JAVA VERSION IN ORACLE
SELECT dbms_java.get_ojvm_property(PROPSTRING=>'java.version') FROM dual;
FOLLOW THIS STEPS :
//java
class simple{
public static String world(){
return("Hello Java");
}
}
Insted of loading class Simple load your java directly,
STEP1 :
loadjava -user system/admin simple.java
STEP2:
then > create one procedure
CREATE OR REPLACE PROCEDURE PROC_DEMO as
language java
name 'simple.world()';
/
STEP3:
declare -- Parameter declaration
RESULT VARCHAR2(2000);
begin
-- Please customize initialization
-- Call the procedure/function
RESULT := FUNC_DEMO;
-- Print out the results
dbms_output.put_line( 'RESULT = ' || SUBSTR( RESULT, 1, 255));
end;