Current situation
We currently use an applet to perform some operations, after which it redirects the current page. In its core, you could see the applet as the following:
public class ExampleApplet extends Applet {
@Override
public void init() {
Button redirect = new Button("Redirect");
this.add(redirect);
final String target = this.getParameter("targetPage");
redirect.addActionListener((ActionEvent e) -> {
try {
getAppletContext().showDocument(new URL(target), "_parent");
} catch (MalformedURLException ex) {}
});
}
}
with the applet being called in its simplest way:
<applet code="com.example.applet.ExampleApplet.class" archive="${appletUrl}" width="100" height="30">
<param name="targetPage" value="http://localhost:8080/applet/"/>
</applet><br/><br/>
where ${appletUrl}
returns the location of the applet JAR.
So the applet is nothing more than a simple button that calls getAppletContext().showDocument(new URL(target), "_parent");
to refresh the current page. This has done its job correctly for a long time. Now here's the issue.
Migration
As many may know, Chrome does not support Applet
s. Which was put aside for a while since IE
and FireFox
still supported them. At the end of 2016, they will also no longer support them. So we decided to migrate the applet using JWS
and JNLP
.
Migrating this simple redirect button example would give the following html
snippet and JNLP
file:
<a href="${jnlpUrl}">Launch JNLP</a>
${jnlpUrl}
returns the location to the JNLP
file which is:
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://localhost:8080/applet/assets/1.0-SNAPSHOT-DEV/app/assets/" href="jnlp/example.jnlp">
<security>
<all-permissions/>
</security>
<resources>
<j2se version="1.5+" initial-heap-size="32m" max-heap-size="128m" />
<property name="jnlp.versionEnabled" value="false"/>
<jar href="applets/ExampleApplet.jar" main="true"/>
</resources>
<applet-desc name="code" main-class="com.example.applet.ExampleApplet.class" width="30" height="30" >
<param name="targetPage" value="http://localhost:8080/applet/"/>
</applet-desc>
</jnlp>
So far so good, the same applet successfuly deploys as a JWS
application. Allowing it to be used from any browser since it's executed outside of it. Which also is kind of the problem.
The problem
The line getAppletContext().showDocument(new URL(target), "_parent");
still does a redirect, but it's using the default browser as stated in the migration documentation.
For AppletContext.showDocument(URL url, String target), the target argument will be ignored by Java Web Start technology.
Similar to AppletContext.showDocument, Java Web Start applications are capabile of showing an HTML page using the system's default web browser by using the BasicService.showDocument API.
So if my default browser is FireFox, but I happen to be browsing to this JWS-enabled applet
in IE/Chrome, a new tab will be opened in FireFox. This is a problem, since I have information (e.g. login) stored in the original browser!
Findings
Since the application is running outside of the browser, I'm having issues to think of possibilities to communicate back to the original browser. I can't use JavaScript
since it doesn't run within the browser. I can't really define a system-independent way to open a tab in the original browser. I've also thought of WebSockets
since they could allow direct communication, but from what I've read it's pretty high-level and requires a server, not a simple applet.
Is there any possibility of communicating between the original browser (e.g. websockets and parameters) or passing the session from one browser to another when the applet opens a new window?
I have found out a working solution.
Since the applet
loses all connection to the browser and its session, another way to provide communication is with WebSockets
or Comet
. In my case I used Comet
with the Atmosphere
framework and a Tapestry-Atmosphere
implementation, since Tapestry
is the view-framework I'm using.
Without going too deep into the Tapestry
implementation, I have done the following:
Topic
on the client-side browser which will listen to broadcasted messages in a typical publish/subscribe
manner.Topic
's ID which is unique to the current browsing user into the Applet
, along with a URL
to send a request to. Using the Topic
ID as a request parameter for the url.Topic
as a request parameter. Using this parameter, it sends a broadcast (possibly empty) to the topic.Topic
receives the notification and executes an event in itself. The event being to re-render specific content of the page.Since it's using Comet
(but could also use WebSockets
) it happens directly in the browser. Every browser subscribed to that Topic
actually, but here there's only one.
Making it in fact possible, to update the page from a simple request from the applet. The applet only had the line getAppletContext().showDocument(new URL(target), "_parent");
changed to new URL(target).openConnection().getInputStream();
. With target
being a URL with the included request parameter.