Java JNI: Creating a Swing Window using JNI from C - java

I'm using JNI to invoke a static java method which in turn creates a Swing JFrame and displays it. The code is fairly simple, and the Java-code is working standalone (i.e. java StartAWT does what it should) whereas when called from C using JNI the process hangs.
I'm using the JDK 1.7.0_09 on Mac OS X 10.8 Mountain Lion.
This is the C code I'm using to invoke the static method:
JavaVM* jvm;
JNIEnv* env = create_vm(&jvm);
jclass class = (*env)->FindClass(env, "StartAWT");
jmethodID method = (*env)->GetStaticMethodID(env, class, "run", "()V");
(*env)->CallStaticVoidMethod(env, class, method);
(*jvm)->DestroyJavaVM(jvm);
The StartAWT class looks like this:
public class StartAWT {
public static class Starter implements Runnable {
public void run() {
System.out.println("Runnning on AWT Queue.");
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("That's a frame!");
JLabel label = new JLabel("A Label");
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
}
public static class GUI implements Runnable {
public void run() {
try {
System.out.println("Going to put something on the AWT queue.");
SwingUtilities.invokeAndWait(new Starter());
} catch (Exception exc) {
throw new RuntimeException(exc);
}
}
}
public static void run() {
Thread gui = new Thread(new GUI());
gui.start();
}
}
When I start the application, I do see Going to put something on the AWT queue but not Running on AWT Queue.
I believe that the Virtual Machine inside my C Process does not have an AWT event queue but I don't know how to set it up for having one either (nor am I sure that this is the reason).
What is to be done in order to show an AWT based GUI using JNI ?
--
EDIT: I've inserted loops to see which threads are alive and which are not (can be seen in this gist). In this version I do the invocation of SwingUtilities.invokeAndWait in another thread. The result: The main thread is alive (C). The first thread dispatched by Java (not the main thread) is alive; the thread doing the Call invokeAndWait is blocked (I don't think that invokeAndWait did even return), the function which should be run on the EventQueue is not even entered.
I've also tried invoking SwingUtilities.invokeAndWait directly, which will give the following message:
2013-02-02 13:50:23.629 swing[1883:707] Cocoa AWT: Apple AWT Java VM was loaded on first thread -- can't start AWT. (
0 liblwawt.dylib 0x0000000117e87ad0 JNI_OnLoad + 468
1 libjava.dylib 0x00000001026076f1 Java_java_lang_ClassLoader_00024NativeLibrary_load + 207
2 ??? 0x000000010265af90 0x0 + 4335185808
)
This is also what I've read in other questions here on StackOverflow, such as the one suggested in the comments below. However, I could not find a solution to the original problem. Maybe it is worth noting that after the above message came up the main thread is still alive, i.e. neither did the process deadlock nor crash.
--
EDIT: I tested the code on Linux where it is working as expected. So I believe this is a Mac OS X issue with Cocoa AWT, but I don't know how to circumvent it.
--
EDIT: I also tried moving the entire invocation of the JVM onto a new native thread. This works on Mac OS X 10.6 with Apples Java 32-bit (1.6.0_37), but results in the same deadlock as described above. On Mac OS X 10.8 this is worse, the application crases with the only message "Trace/BPT trap: 5" (which seems to be related to loading dynamic libraries).
I also tried bundling the binary as described in this Q&A, but the launch fails with the message lsopenurlswithrole() failed with the message -10810, which is an unknown error, according to Apples Launch Services Reference. The latter also happens without attempting to use AWT (the mere JVM invocation fails).

Finally I found a solution.
The problem is not on which thread the Virtual Machine is being created, the problem is on which thread the AWT Event Queue is being initialized. In other words: The first time that an AWT class is loaded, it may not be loaded on the main thread. Thus step 1: Load (for example) java.awt.Component on another thread.
But now the EventQueue will block, as it delegates work to the Cocoa Main Event Queue which is not running - sure enough, since it will only run on the main thread and the main thread is my application. Thus the main run loop needs to be started on the main thread:
void
runCocoaMain()
{
void* clazz = objc_getClass("NSApplication");
void* app = objc_msgSend(clazz, sel_registerName("sharedApplication"));
objc_msgSend(app, sel_registerName("run"));
}
I had to link my application with the Cocoa framework and include <objc/objc-runtime.h>. The main thread is blocked after the call to runCocoaMain (since the event loop is running there), so one needs to resort to another thread for the application itself.
After running the EventQueue using the above snippet the loading of the AWT class on the other thread will succeed and you can proceed there.

I resolved similar problem by instructions of OSX: JavaVM, AWT/Swing and possibly a deadlock , that is to start CFRunLoopRun() after start JVM in another thread.

Related

without main class in java throws error while running [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Printing message on Console without using main() method
Can someone suggest how can a JAVA program run without writing a main method..
For eg:
System.out.println("Main not required to print this");
How can the above line be printed on console without using the public static void main(String arg[]) in the class.
Up to and including Java 6 it was possible to do this using the Static Initialization Block as was pointed out in the question Printing message on Console without using main() method. For instance using the following code:
public class Foo {
static {
System.out.println("Message");
System.exit(0);
}
}
The System.exit(0) lets the program exit before the JVM is looking for the main method, otherwise the following error will be thrown:
Exception in thread "main" java.lang.NoSuchMethodError: main
In Java 7, however, this does not work anymore, even though it compiles, the following error will appear when you try to execute it:
The program compiled successfully, but main class was not found.
Main class should contain method: public static void main (String[] args).
Here an alternative is to write your own launcher, this way you can define entry points as you want.
In the article JVM Launcher you will find the necessary information to get started:
This article explains how can we create a Java Virtual Machine
Launcher (like java.exe or javaw.exe). It explores how the Java
Virtual Machine launches a Java application. It gives you more ideas
on the JDK or JRE you are using. This launcher is very useful in
Cygwin (Linux emulator) with Java Native Interface. This article
assumes a basic understanding of JNI.
Up until JDK6, you could use a static initializer block to print the message. This way, as soon as your class is loaded the message will be printed. The trick then becomes using another program to load your class.
public class Hello {
static {
System.out.println("Hello, World!");
}
}
Of course, you can run the program as java Hello and you will see the message; however, the command will also fail with a message stating:
Exception in thread "main" java.lang.NoSuchMethodError: main
[Edit] as noted by others, you can avoid the NoSuchmethodError by simply calling System.exit(0) immediately after printing the message.
As of JDK6 onward, you no longer see the message from the static initializer block; details here.
public class X { static {
System.out.println("Main not required to print this");
System.exit(0);
}}
Run from the cmdline with java X.
Applets from what I remember do not need a main method, though I am not sure they are technically a program.

JNA + running QT

I need to run a QT application from Java using JNA. The problem is, that QT need to be run from the main thread, however I want to create it on a different thread and manage my java application instantaneously after creating qt window and just send some data to QT via JNA. When I create QTApp from a different thread I get warning "QAppplication was not created in the main() thread" and there is no response to GUI. Is there any clean solution to the problem ?
You can create a QCoreApplication in a QThread. Here is an example snippet from something I recently did:
class MyThread : public QThread
{
public:
void run()
{
int argc = 0;
char* argv[1];// = new char[];
QCoreApplication a(argc,&argv[0]);
// More initilization code here
a.exec();
}
};
Declare your thread in main and call thread.start();

How can you run a Java program without main method? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Printing message on Console without using main() method
Can someone suggest how can a JAVA program run without writing a main method..
For eg:
System.out.println("Main not required to print this");
How can the above line be printed on console without using the public static void main(String arg[]) in the class.
Up to and including Java 6 it was possible to do this using the Static Initialization Block as was pointed out in the question Printing message on Console without using main() method. For instance using the following code:
public class Foo {
static {
System.out.println("Message");
System.exit(0);
}
}
The System.exit(0) lets the program exit before the JVM is looking for the main method, otherwise the following error will be thrown:
Exception in thread "main" java.lang.NoSuchMethodError: main
In Java 7, however, this does not work anymore, even though it compiles, the following error will appear when you try to execute it:
The program compiled successfully, but main class was not found.
Main class should contain method: public static void main (String[] args).
Here an alternative is to write your own launcher, this way you can define entry points as you want.
In the article JVM Launcher you will find the necessary information to get started:
This article explains how can we create a Java Virtual Machine
Launcher (like java.exe or javaw.exe). It explores how the Java
Virtual Machine launches a Java application. It gives you more ideas
on the JDK or JRE you are using. This launcher is very useful in
Cygwin (Linux emulator) with Java Native Interface. This article
assumes a basic understanding of JNI.
Up until JDK6, you could use a static initializer block to print the message. This way, as soon as your class is loaded the message will be printed. The trick then becomes using another program to load your class.
public class Hello {
static {
System.out.println("Hello, World!");
}
}
Of course, you can run the program as java Hello and you will see the message; however, the command will also fail with a message stating:
Exception in thread "main" java.lang.NoSuchMethodError: main
[Edit] as noted by others, you can avoid the NoSuchmethodError by simply calling System.exit(0) immediately after printing the message.
As of JDK6 onward, you no longer see the message from the static initializer block; details here.
public class X { static {
System.out.println("Main not required to print this");
System.exit(0);
}}
Run from the cmdline with java X.
Applets from what I remember do not need a main method, though I am not sure they are technically a program.

How to start a java program?

I have written a java program and I am running it through command line like "java MyProgram"
Now I want to have a GUI that have a start, pause and stop button. How to start that java program by clicking on start button. How to pause it and how to stop it?
I assume your program is something like:
public class MyProgram {
public void doSomething() {
// ... does something ...
}
public static void main(String[] args) {
new MyProgram().doSomething();
}
}
I recommend reading the Swing Tutorial, but a simple GUI to launch your program could be something like:
public class MyProgramLauncher {
public static void main(String[] args) {
final MyProgram myProgram = new MyProgram();
JFrame frame = new JFrame("My Program");
JComponent cp = frame.getContentPane();
cp.add(new JButton(new AbstractAction("Start") {
public void actionPerformed(ActionEvent e) {
myProgram.doSomething();
}
}));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
If your class has a pause() function, you could add a similar JButton to call that function, but you'd have to write/implement the function.
You would, however, have to launch this with java MyProgramLauncher, which isn't very exciting. Still, that will get you a basic GUI in which you can experiment with starting, pausing, etc.
To turn your program into something you can double-click on, you'll need to create a JAR file. This is basically a special ZIP file that includes all the classes in your application, plus a manifest.xml file that describes those classes and (for launchable JAR files) identifies the "main class" whose main() method should be called when the JAR file is launched.
To turn that JAR file into a more or less self-contained deployable application is a bigger pain and there are a whole lot of options. The Deployment Tutorial might be a place to start.
Basically you need a native launcher, but I cannot figure out what do you mean exactly by "pause"... Sending the process to sleep?
I think that should be very easy to implement with a shellscript using the xdialog command in a Unix like system.
You'll need to implement a state machine:
State: "Stopped"
Start: execute java YourProgram and store the PID in a variable. Change state to "Started"
Pause: do nothing/disabled
Stop: do nothing/disabled
State: "Started"
Start: do nothing/disabled
Pause: send the STOP signal (like ctr+z) to the process. Change state to "Paused"
Stop: send the INT signal (like ctr+c) to the process. Change state to "Stopped"
State "Paused"
Start: do nothing/disabled
Pause: send the CONT signal (like doing fg) to the process. Change start to "Started"
Stop: send the INT signal (like ctr+c) to the process. Change state to "Stopped"
With this, you can loop in the script and react to the buttons. Look the reference for kill and dialog or xdialog for more details on the implementation.
First you need to write your "Forms"...
This will be a helpful resource to a beginner.
Basics

Disconnect java application from console/command window [duplicate]

This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
Is there a way to the hide win32 launch console from a Java program (if possible without JNI)
When I run my java swing application in a batch file on windows, the console/command window remains open whilst my java application is running. This creates an extra window on my taskbar which I would prefer not to have. But when I close the command window it stops my java application. Is there a way, perhaps via the batch file or command line parameters or code changes to my application, to have java.exe exit after bringing up my swing app and the console window close whilst my application still runs?
Main method is as follows:
public static void main(String args[]) {
ApplContext applContext = new ApplContext();
Throwable error = null;
try {
applContext.setUserConfigDir(args.length>0 ? args[0] : null);
applContext.loadData();
ApplTools.initLookAndFeel(Parameters.P_NIMBUS_LAF.of(applContext.getParameters()));
} catch (Throwable e) {
error = e;
}
// JWorkSheet is a JFrame.
new JWorkSheet(applContext, error).setVisible();
}
Run your application with javaw.exe rather than java. If you're running from a bat file, use this in combination with the start command:
> start javaw.exe -jar myapp.jar
When run in this mode, it's a good idea to set up proper logging or at least redirect your output streams if you rely on the console for any debugging. For example, with no console, you'll never see those friendly stack traces printed for unhandled exceptions.
Note: java.exe is a Windows console application. As such, no matter how it is started, or what threads are running in it, a console will be allocated for it. This is the reason that javaw.exe exists.
Ideally what you will eventually do somewhere in your code is call SwingUtilities.invokeLater(Runnable r). That will throw your GUI code into the correct thread, and you should be able to close the command line after the main thread exits.
This is a basic example of what I am talking about:
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
JFrame yourWindow = new YourFrame();
yourWindow.createAndShow();
}
}
}

Categories

Resources