I try to set the --ignore-gpu-blacklist argument to JCEF but I can't find a way. The method I should be using is this one: CefApp::onBeforeCommandLineProcessing(String, CefCommandLine). But I can't find an example or good instructions of how to do it. CefCommandLine is an interface and I cannot find any implementation.
All the instructions I found are related to CEF, not JCEF and apparently there are classes that are different. Can anyone post a small example of how to pass Chromium arguments to CEF from a String str = "--ignore-gpu-blacklist"; ?
You have several possibilities to pass over arguments from JCEF to CEF/chromium.
1) The easiest way:
public static void main(String [] args) {
[...]
ArrayList<String> mySwitches = new ArrayList<>();
mySwitches.add("--persist-session-cookies=true");
CefApp app = CefApp.getInstance(mySwitches.toArray(new String[mySwitches.size()]));
CefClient client = app.createClient();
CefBrowser browser = client.createBrowser("http://www.google.com", false, false);
[...]
}
Just create a string array, containing all your switches you want to pass over and assign that array to CefApp.getInstance(..) at the very first call of that static method.
If you have only some simple settings, you can use the class CefSettings as well and pass over the object to getInstance(). Beside that, you can combine both (there are four different "getInstance()" methods).
2) Create your own CefAppHandler implementation to do some advanced stuff.
(a) Create an own AppHandler:
public class MyAppHandler extends CefAppHandlerAdapter {
public MyAppHandler(String [] args) {
super(args);
}
#Override
public void onBeforeCommandLineProcessing(String process_type, CefCommandLine command_line) {
super.onBeforeCommandLineProcessing(process_type, command_line);
if (process_type.isEmpty()) {
command_line.appendSwitchWithValue("persist-session-cookies","true");
}
}
}
(b) Pass AppHandler over to CefApp
public static void main(String [] args) {
[...]
MyAppHandler appHandler = new MyAppHandler(args);
CefApp.addAppHandler(appHandler);
CefApp app = CefApp.getInstance(args);
CefClient client = app.createClient();
CefBrowser browser = client.createBrowser("http://www.google.com", false, false);
[...]
}
Using this approach you'll do two things:
(a) you pass over the program arguments (args) to CefApp and
(b) you take the advantage of having the opportunity to manipulate the complete process of parsing the arguments within onBeforeCommandLineProcessing.
If you open the example code of JCEF detailed main frame, you will find this approach implemented in:
- tests.detailed.MainFrame.MainFrame(boolean, String, String[])
So implementing the onBeforeCommandLineProcessing is equal to CEF but written in Java instead of C/C++.
Regards,
Kai
Related
I am currently executing my JavaScript-scripts with this java code:
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("awesome_script.js"));
I need to call Java functions from JavaScript, so I defined this at the top of my awesome_script.js file:
var first = Java.type('io.github.awesomeprogram.FirstClass');
var second = Java.type('io.github.awesomeprogram.SecondClass');
var extra = Java.type('io.github.awesomeprogram.ExtraClass');
I can then call some methods from these classes, e.g.:
second.coolmethod("arg1",2);
My problem is now that I need to use many java classes inside of my scripts. I also have a lot of scripts and I think it is very inefficient to define every single one of this classes in every script.
So I am looking for a solution to create the objects created inside of JavaScript with Java.type() inside of Java and then pass them to the script I want to execute.
How can I do this?
Thanks in advance!
You may want to avoid using the "internal" classes in packages like "jdk.internal.", "jdk.nashorn.internal.". In jdk9, dynalink is an API ("jdk.dynalink" has exported packages). In jdk9, you can call jdk.dyanlink.beans.StaticClass.forClass(Class) [ http://download.java.net/java/jdk9/docs/jdk/api/dynalink/jdk/dynalink/beans/StaticClass.html#forClass-java.lang.Class- ] to construct "type" objects and expose those as global variables to the script engine. For jdk8, you could pre-eval a script that uses Java.type(String) calls before evaluating "user" scripts. You can also call "Java.type" function from Java code.
Solution for jdk9:
import jdk.dynalink.beans.StaticClass;
import javax.script.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
e.put("AList", StaticClass.forClass(java.util.ArrayList.class));
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
Solution for jdk8:
import javax.script.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
// eval a "boot script" before evaluating user script
// Note that this script could come from your app resource URL
e.eval("var AList = Java.type('java.util.ArrayList')");
// now evaluate user script!
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
Alternative solution for jdk8:
import javax.script.*;
import jdk.nashorn.api.scripting.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
// get Java.type function as object
JSObject javaTypeFunc = (JSObject) e.eval("Java.type");
// you can javaTypeFunc from java code many times
Object alType = javaTypeFunc.call(null, "java.util.ArrayList");
// expose that as global
e.put("AList", alType);
// now evaluate user script!
e.eval("var al = new AList(); al.add('hello'), al.add('world')");
e.eval("print(al)");
}
}
After quite a bit of research I found a way to put global variables in the ScriptEngine before executing: The Java Scripting API (Oracle Docs)
This enabled me to put any object I want into a global variable. However, I still needed a way to get the Object that Java.type() creates inside of Java. So I wrote a test script which returns one of this objects and I found out it is an object of the type jdk.internal.dynalink.beans.StaticClass. This class has an constructor which takes a ordinary Class as an argument. Sadly, this constructor is not usable in my code because it is not visible. To bypass this I used reflection and made this method:
public StaticClass toNashornClass(Class<?> c) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Class<?> cl = Class.forName("jdk.internal.dynalink.beans.StaticClass");
Constructor<?> constructor = cl.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
StaticClass o = (StaticClass) constructor.newInstance(c);
return o;
}
If I pass the Class of the object I want as a global variable I just need to call toNashornClass(Example.class); and put the resulting object into a global var with engine.put("example",object);
It works fine. I can use the example var completely like a var created by Java.type().
I am trying to pass few specific paths as a string arg in one program to call another java program. I get an ArrayIndexOutOfBoundsException error but when I pass the exact same arg in the command line it works perfectly
What is doable in command line:
program1 /filepath/{A,B,C}/*.zip
What I want to do that is giving me an error:
program2 [call program 1]:
status = ToolRunner.run(conf, program1, new String[]{"/filepath/{A,B,C}/*.zip"});
I am not sure how I can pass it that way, even if I want to pass all the paths and change the second program I am not sure how can I aggregate all the paths and assign it as input stream.
I appreciate your help,
Thank you :)
ToolRunner.run() method receives as arguments:
A Configuration object
A Tool object
A String array of arguments to be passed to the Tool object
Is your "program1" an object extending the Tool interface? Attending to the name you used, it seems it is more a refence to some "binary" or executable thing...
Please, have a look to the documentation.
ToolRunner is typically used in Hadoop applications as:
public final class MyMRClass extends Configured implements Tool {
...
public static void main(String[] args) throws Exception {
int res = ToolRunner.run(new Configuration(), new MyMRClass(), args);
System.exit(res);
} // main
#Override
public int run(String[] args) throws Exception {
Configuration conf = this.getConf();
Job job = Job.getInstance(conf, "some job name");
...
}
}
I'm curious to know if it is possible to determine the startup arguments of a Java application when you don't have access to the arguments array from the main line.
public static void main(String[] args)
{
// Invokes my code without providing arguments.
mycode();
}
public static void mycode()
{
// Attempting to determine arguments here.
// TODO GetArgs()
}
I'm in this situation by doing some plugin work and the core application does not provide a list of startup arguments. Any thoughts?
Not unless the plugin is given them, but that kind of goes without saying (at least in Java).
If you need to set some options specifically for your plugin, but can't access the command line, there are at least two options:
Options file (several mechanisms)
Set system params on the command line
For the second option, just use the normal -D option and namespace the param name, like:
java -Dcom.davelnewton.plugins.foo.bar=anOptionValue etc...
Retrieve them via System.getProperty(anOptionName) or one of its cousins.
IMO an options file is a better (ahem) option, even if you're specifying the file path on the command line, but if you only have an option or two, maybe not--just depends.
Pass the arguments to the function?
public static void main(String[] args)
{
mycode(args);
}
public static void mycode(String[] args)
{
String arg1 = args[0];
}
You could do:
public static void main(String[] args)
{
System.setProperty("cmdArgs", args);
mycode();
}
public static void mycode()
{
// Attempting to determine arguments here.
String[] args = System.getProperty("cmdArgs");
}
I am building a user interface in netBeans (coding by hand, more flexible) with multiple toolbars.
What I am trying to do is create an actionListener for each button. I am retrieving names of the functions from XML and parse them to string. I will write implementations for those functions in a separate class, but my problem is the following:
How do I make the link between the function name and the string containing it's name?
Example: String is Open(), function will be Open(someParameter) and in the definitions class there will be static void Open(param).
First of all, consider my comment about your idea of dynamic button behavior resolved from strings being a wrong approach. However if you still need exactly what you asked, what you need is Reflection API.
Here's an example:
Class c = SomeClassWithMethods.class;
Method m = c.getMethod("someMethodName", String.class, Integer.class, Integer.TYPE);
m.invoke(baseObjectFromWhichToCallTheMethod, "stringParam", 10, 5);
Added:
Another option, which is a little bit prettier than reflection, but still a messy design, would be to use a map to link those Strings to methods. The code is a bit longer, but from the Java perspective it is much better than using reflection for your task (unless you have some specific requirement of which I'm not aware). This is how it would work:
//Interface whose instances will bind strings to methods
interface ButtonClickHandler {
void onClick();
}
class SomeClassYouNeed {
//One of the methods that will be bound to "onButtonOneClick()"
public void onButtonOneClick() {
log.info("ButtonOneClick method is called");
}
public void onButtonTwoClick() {
log.info("ButtonTwoClick method is called");
}
//Map that will hold your links
private static Map<String, ButtonClickHandler> buttonActionMap;
//Static constructor to initialize the map
static {
buttonActionMap = new Map<String, ButtonClickHandler>();
buttonActionMap.put("onButtonOneClick()",new ButtonClickHandler() {
#Override
public void onClick() {
onButtonOneClick();
}
});
buttonActionMap.put("onButtonTwoClick()",new ButtonClickHandler() {
#Override
public void onClick() {
onButtonTwoClick();
}
});
}
public void callByName(String methodName) {
final ButtonClickHandler handler = buttonActionMap.get(methodName);
if (handler == null) {
throw new IllegalArgumentException("No handler found by name: "+methodName);
}
handler.onClick();
}
}
After you call callByName("onButtonTwoClick()") it will fetch the respective instance of ButtonClickHandler which will use the static method onButtonTwoClick() to process the click of the button.
It seems to me that you are looking for the equivalent of JS "eval" function in Java. This might help. Nevertheless it is generally not a good idea as #Max stated, you might want to rethink your design.
If i have understood your question correctly you are trying to generate your code files based on some strings taken from a XML file. I can suggest you this library to generate your codes.
For tutorials you can visit this link.
You may even use the Java Reflection API. Here is a link for the tutorial.
Its upto you, that which of the above two you use.
I was trying to learn reflection and I came across this IllegalAccessException. Please see the following code:
public class ReflectionTest
{
public static void main(String[] args)
{
Set<String> myStr = new HashSet<String>();
myStr.add("obj1");
Iterator itr = myStr.iterator();
Method mtd = itr.getClass().getMethod("hasNext");
System.out.println(m.invoke(it));
}
}
When I tried to run this program, I got the following:
Exception in thread "main" IllegalAccessException
I don't understand what's going on. Any ideas? Thanks in advance.
The troublesome piece of code is this:
itr.getClass().getMethod
You probably wanted hasNext on the Iterator class. What you have written is the HashMap.KeyIterator class, which according the Java language access specifiers (or at least the rough interpretation of JDK 1.0 used by reflection) is not available to your code.
Use instead:
Iterator.class.getMethod
(And if it wasn't for learning purposes, stay away from reflection.)
You cannot access it, because the Iterator is a private inner class. More explanation can be found here.
It's apparent that your currently executing method does not have access to the method named hasNext, e.g., by it being private or protected. You could try to enable access to it using method.setAccessible(true);
It might also be that you have some restrictions defined in your security manager (which, if you use e.g., linux, might have been included default from the distributions java package).
[EDIT] As it turns out, Tom Hawtin identified the correct root cause. You are indeed operating on HashMap.KeyIterator. Although the solution would be to use Iterator.class instead of itr.getClass() you could still enable access to it using setAccessible(true).
I suspect you should use getDeclaredMethod (among other issues). I don't bother to remember Reflection API details (they're for the compiler!), but in your case compare your code with that produced by dp4j:
$ javac -Averbose=true -All -cp dp4j-1.2-SNAPSHOT-jar-with-dependencies.jar ReflectionTest.java
ReflectionTest.java:6: Note:
import java.util.*;
public class ReflectionTest {
public ReflectionTest() {
super();
}
#com.dp4j.Reflect()
public static void main(String[] args) throws java.lang.ClassNotFoundException, java.lang.NoSuchFieldException, java.lang.IllegalAccessException, java.lang.NoSuchMethodException, java.lang.reflect.InvocationTargetException, java.lang.InstantiationException, java.lang.IllegalArgumentException {
final java.lang.reflect.Constructor hashSetConstructor = Class.forName("java.util.HashSet").getDeclaredConstructor();
hashSetConstructor.setAccessible(true);
Set<String> myStr = (.java.util.Set<.java.lang.String>)hashSetConstructor.newInstance();
final java.lang.reflect.Method addWithEMethod = Class.forName("java.util.Set").getDeclaredMethod("add", .java.lang.Object.class);
addWithEMethod.setAccessible(true);
addWithEMethod.invoke(myStr, new .java.lang.Object[1][]{"obj1"});
final java.lang.reflect.Method iteratorMethod = Class.forName("java.util.Set").getDeclaredMethod("iterator");
iteratorMethod.setAccessible(true);
Iterator itr = (.java.util.Iterator)iteratorMethod.invoke(myStr);
final java.lang.reflect.Method hasNextMethod = Class.forName("java.util.Iterator").getDeclaredMethod("hasNext");
hasNextMethod.setAccessible(true);
final java.lang.reflect.Method printlnWithbooleanMethod = Class.forName("java.io.PrintStream").getDeclaredMethod("println", .java.lang.Boolean.TYPE);
printlnWithbooleanMethod.setAccessible(true);
printlnWithbooleanMethod.invoke(System.out, new .java.lang.Object[1][]{hasNextMethod.invoke(itr)});
}
}
public static void main(String[] args)
^
...
$ java ReflectionTest
true
The only change you need to do is annotate your main method with #com.dp4j.Reflect:
$ vim ReflectionTest.java
import java.util.*;
public class ReflectionTest
{
#com.dp4j.Reflect
public static void main(String[] args)
{
Set<String> myStr = new HashSet<String>();
myStr.add("obj1");
Iterator itr = myStr.iterator();
// Method mtd = itr.getClass().getMethod("hasNext");
System.out.println(itr.hasNext());
}
}
NB: this works only with dp4j-1.2-SNAPSHOT (I've just added suport for it). If you don't use Maven, download the jar from here. You find the test case with your problem here.