Opening Sockets in a Java Applet using LiveConnect

May 20th, 2009

I recently had to create my first Java Applet. One of the requirements was that it needed a Javascript API for controlling all the major functions that the applet could perform. Before I started, I wasn’t entirely sure this was even possible. It turns out, the Java plugin used in web browsers has a feature called LiveConnect that enables applet to javascript communication. Java.net has a pretty comprehensive LiveConnect guide here: https://jdk6.dev.java.net/plugin2/liveconnect/, but there was one major issue I had.

My applet used sockets to communicate with a server. In order to use sockets in an applet, you need to sign your jar files. You can find more information about signing jar files here: http://java.sun.com/docs/books/tutorial/deployment/jar/signing.html However, even though I had signed all my jars, I still wasn’t able to open a socket.  When I tried, I was getting this exception:

java.security.AccessControlException: access denied (java.net.SocketPermission ....)

Thankfully, one of my co-workers had run into this problem before. The issue is: Java code called directly from Javascript using LiveConnect has no permissions, even if your jars are signed.

For example: in Javascript I call a login() method on my Java object.  The login() method needs to open a socket, but since it was called from Javascript, it doesn’t have permission and fails.

My solution was to create a queue that executes inside the code with permissions. I was then able to insert objects into the queue from code without permissions and have them execute with permissions. My queue class:

public class JsEventQueue implements Runnable {
    private static final Logger logger = Logger.getLogger(JsEventQueue.class);
    private final Thread thread = new Thread(this, "JsEventQueue");
    private final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
    private boolean running = true;

    public JsEventQueue() {
        thread.setDaemon(true);
        thread.start();
    }

    public void run() {
        while (running) {
            try {
                Runnable runnable = queue.take();
                if (runnable != null) {
                    runnable.run();
                }
            } catch (InterruptedException ie) {
                logger.error("Interrupted while waiting for new task.", ie);
            }
        }
    }

    public void add(Runnable runnable) {
        queue.add(runnable);
    }

    public boolean isRunning() {
        return running;
    }

    public void setRunning(boolean running) {
        this.running = running;
    }
}

I instantiate this class when my applet starts and then pass it Runnable objects from outside the permission zone. So, in my example, when I call login() from Javascript, the login method creates a new Runnable object with the login code and passes that to my JsEventQueue reference:

public void login() {
        //queue = previously instantiated reference to JsEventQueue object
        queue.add(new Runnable() {
            public void run() {
                /**
                 * Code for performing login, this code will have permissions.
                 */
            }
        });
    }

This is an easy way to call Java code with permissions from Javascript.