SWT in Java WebStart App stopped working on OSX after upgrading to Java 7 [message #957764] |
Thu, 25 October 2012 09:21  |
Eclipse User |
|
|
|
Hi Forum-Readers,
i'm maintaining a JavaWS application using SWT for our company for quite a while now. I have reports that it stopped to work on Apple OSX computers, so i started digging into it.
It seems Apple has dropped their own Java 1.6 implementation and Oracle's Java 7 is now installed by default. An here the misery begins...
My app started to report the known "***WARNING: Display must be created on main thread due to Cocoa restrictions. / org.eclipse.swt.SWTException: Invalid thread access" issue. Okay, it seems that -XstartOnFirstThread works for Apple's 1.6 but not for Oracle's java 7?
After digging into it i found out that Oracle's implementation didn't do a restart with -XstartOnFirstThread during javaws init. The cause was that i've dropped signing the application's jnlp file due to some issues on the Microsoft platform. Don't care, i signed it again and next try - and i got one step further:
Java is now restarted with -XstartOnFirstThread, but then everything freezes up. It seems there is a massive problem bringing up the AWT/Swing subsystem because javaws launcher is sitting on the main thread and AWT also want's the main thread because of the same cause we want it for SWT...
My next try was to add an additional -Djava.awt.headless=true parameter, and at least everything comes up into my app - but i'm dying on the "Invalid thread access" issue again. I think the javaws starter or maybe AWT is still fooling around with the threads...
BTW: i just tried it with swt-4.2.1.
Anyone out there having the same issue or idea's what else i can try?
Thanks & Bye,
Chris
|
|
|
|
|
|
|
|
|
|
|
|
Re: SWT in Java WebStart App stopped working on OSX after upgrading to Java 7 [message #982056 is a reply to message #977694] |
Mon, 12 November 2012 17:47   |
Eclipse User |
|
|
|
I have made some progress in my RCP application. Inside my implementation of IApplication.start(), I have (ignore the sloppy error handling for now):
if (SystemHelpers.isOSMac()) {
private boolean isDisplayBuilt = false;
try {
try {
Class<?> comAppleConcurrentDispatch = Class.forName("com.apple.concurrent.Dispatch");
Method getInstance = comAppleConcurrentDispatch.getMethod("getInstance", (Class<?>[]) null);
Object dispatchInstance = getInstance.invoke(null, (Object[]) null);
Method getNonBlockingMainQueueExecutor = dispatchInstance.getClass().getMethod("getNonBlockingMainQueueExecutor",(Class<?>[]) null);
Executor executor = (Executor) getNonBlockingMainQueueExecutor.invoke(dispatchInstance, (Object[]) null);
executor.execute(new Runnable() {
public void run() {
try {
if (display == null) {
display = PlatformUI.createDisplay();
PlatformUI.createAndRunWorkbench(display,
new MyWorkbenchAdvisor()); //my implementation of WorkbenchAdvisor
isDisplayBuilt = true;
}
} catch (Throwable t) {
//log error
}
}
});
} catch (Throwable t) {
//log error
}
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
while (isDisplayBuilt == false) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
//log error
}
}
}
});
} catch (Throwable t) {
//log error
}
Putting the AWT EventQueue thread to sleep was a pretty brutal way to go, but it was the only way I could figure out to wait to get the Display object initialized and b) get the non-blocking main queue executor to actually fire the run method.
But now I'm up against the next issue, which is that my application also uses the AWT_SWT bridge. The first time I try and get an AWT/Swing class running, I get the following:
(AppKit Thread) A org.eclipse.swt.SWTError object with a message of:
org.eclipse.swt.SWTError: Not implemented (java.lang.ClassNotFoundException: apple.awt.CEmbeddedFrame)
was generated in the following call stack:
at org.eclipse.swt.SWT.error(SWT.java:4109)
at org.eclipse.swt.SWT.error(SWT.java:3998)
at org.eclipse.swt.awt.SWT_AWT.new_Frame(SWT_AWT.java:145)
at com.lspeed.workbench.AstoriaNavigatorWindowAdvisor.prepareModalFrame(AstoriaNavigatorWindowAdvisor.java:416)
at com.lspeed.workbench.AstoriaNavigatorWindowAdvisor.createWindowContents(AstoriaNavigatorWindowAdvisor.java:325)
at org.eclipse.ui.internal.WorkbenchWindow.createContents(WorkbenchWindow.java:1016)
at org.eclipse.jface.window.Window.create(Window.java:431)
at org.eclipse.ui.internal.Workbench$22.runWithException(Workbench.java:1208)
at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:35)
at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:134)
at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:3593)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3286)
at org.eclipse.ui.application.WorkbenchAdvisor.openWindows(WorkbenchAdvisor.java:803)
at org.eclipse.ui.internal.Workbench$31.runWithException(Workbench.java:1567)
at org.eclipse.ui.internal.StartupThreading$StartupRunnable.run(StartupThreading.java:31)
at org.eclipse.swt.widgets.Synchronizer.syncExec(Synchronizer.java:179)
at org.eclipse.ui.internal.UISynchronizer.syncExec(UISynchronizer.java:150)
at org.eclipse.swt.widgets.Display.syncExec(Display.java:4240)
at org.eclipse.ui.internal.StartupThreading.runWithoutExceptions(StartupThreading.java:94)
at org.eclipse.ui.internal.Workbench.init(Workbench.java:1562)
at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2567)
at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2438)
at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:671)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:664)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
at com.lspeed.workbench.AstoriaNavigatorApp$1.run(AstoriaNavigatorApp.java:84)
Caused by: java.lang.ClassNotFoundException: apple.awt.CEmbeddedFrame
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at org.eclipse.swt.awt.SWT_AWT.new_Frame(SWT_AWT.java:140)
... 25 more
due to the following cause:
This appears to come down to the reported bug in OpenJDK: http://www.java.net/forum/topic/jdk/java-se-snapshots-project-feedback/eclipse-swtawt-bridge-broken-mac-os-x-openjdk-7u4ea
I think I'm stuck there.
|
|
|
Re: SWT in Java WebStart App stopped working on OSX after upgrading to Java 7 [message #986215 is a reply to message #982056] |
Mon, 19 November 2012 08:45   |
Eclipse User |
|
|
|
Dear Dylan,
sorry for the late reply, it seems i've missed the notification about your post.
I also had the issue with not starting the main thread via com.apple.concurrent.Dispatch as long as the JRE was not relaunched during JavaWS-Initialization. I enabled 'tracing' and 'logging' from java preferences and when it works right, you'll find two trace files in Library/Application Support/Oracle/Java/Deployment/log/javaws....trace for each application launch. The first one only tells that JRE is restarted and the second one does the 'real work'.
Look for lines like:
basic: DefaultMatchJRE:
JREDesc: JREDesc[version 0+, heap=-1--1, args=null, sel=true, com.sun.javaws.jnl.ResourcesDesc@5956ca9f, null]
JREInfo: JREInfo for index 0:
platform is: 1.7
product is: 1.7.0_09
location is: ht tp:// java.sun.com/products/autodl/j2se
path is: /Library/Internet Plug-ins/JavaAppletPlugin.plugin/Contents/Home/bin/java
args is: null
native platform is: Mac OS X, x86_64 [ x86_64, 64bit ]
JavaFX runtime is: JavaFX 2.2.3 found at /Library/Internet Plug-ins/JavaAppletPlugin.plugin/Contents/Home/
enabled is: true
registered is: true
system is: true
Init Heap: -1
Max Heap: 67108864
Satisfying: false, true
SatisfyingVersion: true
SatisfyingJVMArgs: false, true
SatisfyingSecure: false
Selected JVMParam: [JVMParameters: isSecure: false, args: -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true]
Running JVMParam: [JVMParameters: isSecure: true, args: ]
temp: Convert image: /Volumes/data/marvin/Library/Application Support/Oracle/Java/Deployment/cache/6.0/1/1dee1481-26720c99->/Volumes/data/user/Library/Application Support/Oracle/Java/Deployment/cache/6.0/1/1dee1481-26720c99.icns
basic: Saving session state to /var/folders/j_/403v_c_s3zzg5yrb2397fs240000gp/T/session7806841378132485821
================
basic: Launching new JRE version: JREInfo for index 0: <---- LOOK for this!
platform is: 1.7
product is: 1.7.0_09
location is: http:/ /java.sun.com/products/autodl/j2se
path is: /Library/Internet Plug-ins/JavaAppletPlugin.plugin/Contents/Home/bin/java
args is: null
native platform is: Mac OS X, x86_64 [ x86_64, 64bit ]
JavaFX runtime is: JavaFX 2.2.3 found at /Library/Internet Plug-ins/JavaAppletPlugin.plugin/Contents/Home/
enabled is: true
registered is: true
system is: true
basic: jvmParams: [JVMParameters: isSecure: false, args: -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true] <---- LOOK for this!
The idea to use SwingUtilities.invokeAndWait() could be quite interesting. I think Swing and AWT also want to use the first thread for the UI - so i think code started with SwingUtils.invokeAndWait() also could run on the right thread - have you tried to start your SWT app via SwingUtils.invokeAndWait()?
And for your issue with concurrently using AWT besides SWT: We don't use AWT in our app, so we didn't have issues yet - and all I say is guessed. Besides solfing your ClassNotFoundException issue, i think you also need to call the AWT and Swing event handlers from your main loop. All GUI activity on OSX has to be done from the first thread launched by an app - so all Toolkits need to be served from the same thread...
Maybe it might be worth having a look how things are managed by a offline app started with -XstartOnFirstThread - As far as i know concurrent AWT / Swing / SWT is possible here, so there has to be some kind of a 'master loop' calling SWT, AWT and Swing event handlers from first thread...
Hope this brings you further,
Bye,
Chris
|
|
|
|
|
|
|
Re: SWT in Java WebStart App stopped working on OSX after upgrading to Java 7 [message #1798266 is a reply to message #957764] |
Wed, 14 November 2018 12:30   |
Eclipse User |
|
|
|
I've found a working solution - the trick seems to be to initialize awt before switching the thread.
On issue: I can not go to fullscreen. :-/
import java.awt.Toolkit;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class SWTTest
{
private static void log(final Object theMessage)
{
log(theMessage, null);
}
private static void log(final Object theMessage, final Throwable theError)
{
System.out.println("" + theMessage);
if (theError != null)
theError.printStackTrace(System.err);
Logger.getLogger("webstart_test").log(Level.INFO, "" + theMessage, theError);
}
public static void main(String[] args)
throws Exception
{
final Logger logger = Logger.getLogger("webstart_test");
final FileHandler logfile = new FileHandler("%h/webstart_test.log");
final ConsoleHandler console = new ConsoleHandler();
logfile.setFormatter(new SimpleFormatter());
console.setFormatter(new SimpleFormatter());
logger.addHandler(logfile);
logger.addHandler(console);
log("start");
String osName = System.getProperty("os.name");
log("OS: " + osName);
if (!osName.startsWith("Mac") && !osName.startsWith("Darwin"))
{
SWTTest.run();
}
else
{
try
{
Class<?> _c = Class.forName("com.apple.concurrent.Dispatch");
final Method _get_instance = _c.getMethod("getInstance", null);
final Object _instance = _get_instance.invoke(null, null);
final Method _get_executor = _instance.getClass().getMethod("getNonBlockingMainQueueExecutor", null);
final Executor _executor = (Executor) _get_executor.invoke(_instance, null);
Toolkit.getDefaultToolkit();
final FutureTask<Void> _f = new FutureTask<Void>(new Callable<Void>()
{
/**
* {@inheritDoc}
*/
@Override
public Void call()
throws Exception
{
log("Los gehts...");
SWTTest.run();
log("app fertig");
return null;
}
});
_executor.execute(_f);
_f.get();
TimeUnit.SECONDS.sleep(5);
log("main fertig");
}
catch (final Throwable _e)
{
log(_e.getMessage(), _e);
}
}
}
private static void run()
{
try
{
log("creating display");
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("Hello, world!");
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
catch (Exception _e)
{
log(_e.getMessage(), _e);
}
finally
{
log("bye....");
}
}
}
Attention: com.apple.concurrent.Dispatch was removed in Java 9 - so this seems to work only in java 8.
Or get the classes from: https://github.com/openjdk-mirror/jdk7u-jdk/tree/master/src/macosx/classes/com/apple/concurrent
Al
|
|
|
|
Powered by
FUDForum. Page generated in 0.09849 seconds