Where I work we have some Oracle Forms applications and, in one of them, we need to embed a webpage which will itself contain an applet... Pretty much the only solution I found to achieve this in Java 6+ is the SWT Browser component.
I have made a proof of concept embedding the SWT Browser component inside a JApplet
and everything works fine! But when we replace the top JApplet
with a VBean
and we embed it in our Forms application, it gives this error :
java.lang.IllegalArgumentException: Argument not valid [peer not created]
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.awt.SWT_AWT.new_Shell(Unknown Source)
at xx.xxxxx.forms.utils.webbrowser.BrowserCanvas$1.run(BrowserCanvas.java:65)
I found some posts about this error on the net but nothing helped! The tests are done on a Windows 64bits machine. The Java version is JRE 1.6.0_12-b04 Java HotSpot(TM) Client VM
.
Here's the code (heavily based on this article) :
SwtWebBrowser (the VBean) :
import java.awt.BorderLayout;
import javax.swing.JPanel;
import oracle.forms.handler.IHandler;
import oracle.forms.ui.VBean;
import org.eclipse.swt.browser.Browser;
//public class SwtWebBrowser extends JApplet {
public class SwtWebBrowser extends VBean {
private static final long serialVersionUID = 1L;
private JPanel panel;
private BrowserCanvas browserCanvas;
@Override
//public void init() {
public void init(IHandler handler) {
// Required for Linux systems
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=161911
try {
System.setProperty("sun.awt.xembedserver", "true");
} catch (Exception ex) {
// ok on Windows
}
this.browserCanvas = new BrowserCanvas();
this.panel = new JPanel(new BorderLayout());
this.panel.setPreferredSize(this.getPreferredSize());
this.panel.add(this.browserCanvas, BorderLayout.CENTER);
add(this.panel);
// This is VERY important: Make the frame visible BEFORE
// connecting the SWT Shell and starting the event loop!
setVisible(true);
this.browserCanvas.connect();
setURL("http://google.com");
}
protected Browser getBrowser() {
return this.browserCanvas.getBrowser();
}
protected JPanel getPanel() {
return this.panel;
}
protected void executeInBrowser(Runnable runnable) {
getBrowser().getDisplay().asyncExec(runnable);
}
public void setURL(final String url) {
executeInBrowser(new Runnable() {
@Override
public void run() {
getBrowser().setUrl(url);
}
});
}
}
BrowserCanvas :
import java.awt.Canvas;
import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class BrowserCanvas extends Canvas {
private static final long serialVersionUID = 1L;
private Thread swtThread;
private Browser swtBrowser;
/**
* Connect this canvas to a SWT shell with a Browser component and
* starts a background thread to handle SWT events. This method waits
* until the browser component is ready.
*/
public void connect() {
if (this.swtThread == null) {
final Canvas canvas = this;
this.swtThread = new Thread() {
@Override
public void run() {
try {
Display display = new Display();
// The exception is here :
Shell shell = SWT_AWT.new_Shell(display, canvas);
shell.setLayout(new FillLayout());
synchronized (this) {
BrowserCanvas.this.swtBrowser = new Browser(shell, SWT.NONE);
this.notifyAll();
}
shell.open();
while (!isInterrupted() && !shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
shell.dispose();
display.dispose();
} catch (Exception e) {
interrupt();
}
}
};
this.swtThread.start();
}
// Wait for the Browser instance to become ready
synchronized (this.swtThread) {
while (this.swtBrowser == null) {
try {
this.swtThread.wait(100);
} catch (InterruptedException e) {
this.swtBrowser = null;
this.swtThread = null;
break;
}
}
}
}
/**
* Returns the Browser instance. Will return "null" before "connect()"
* or after "disconnect()" has been called.
*/
public Browser getBrowser() {
return this.swtBrowser;
}
/**
* Stops the swt background thread.
*/
public void disconnect() {
if (this.swtThread != null) {
this.swtBrowser = null;
this.swtThread.interrupt();
this.swtThread = null;
}
}
/**
* Ensures that the SWT background thread is stopped if this canvas is
* removed from it's parent component (e.g. because the frame has been
* disposed).
*/
@Override
public void removeNotify() {
super.removeNotify();
disconnect();
}
}
Any idea on how to make it work would be really appreciated! Or in fact any other ideas on how to embed a webpage that contains an applet.