1

I have a web app that needs to be able open a file locally on a client machine, with the ability to save the file after editing. The web app generates a document on the server in a folder that is shared out via WebDAV & FTP and this folder is mounted on the client machine.

I cannot use a file:// type URI as it would not permit saving back to the server.

I intend trying to solve the problem with a small java applet embedded in the web app that handles this file opening, but I am having difficulties with permissions in Java. (Java isn't my field of expertise). Anyhow, I've narrowed the code down to the following:

localfile.html

<html>
<body>
  <input id="input" value="Call from Javascript" type="button" onclick="callApplet('/Users/conor/1.txt')">
  <script type='text/javascript'>
  function callApplet(path) {
    applet = document.getElementById('localfile');
    applet.openFile(path);
  }
  </script>
<applet id="localfile" code="localfile.class" archive="localfile.jar"  width="150" height="50"></applet>
</body>
</html>

localfile.java

import java.applet.*;
import java.awt.*;
import java.util.*;
import java.lang.*;
import java.text.*;
import java.awt.event.*;
import java.io.*;

import java.security.*;

public class localfile extends Applet {
  public localfile() {
    Panel p = new Panel();
    p.add(new Button("Call from Java"));
    add("North",p);
  }
  public void openFile(String path) {
    System.out.println("File: " + path);
    final File ffile = new File(path);
    System.out.println("Got file.");
    if (Desktop.isDesktopSupported()) {
      System.out.println("Desktop is supported.");
      final Desktop desktop = Desktop.getDesktop();
      System.out.println("Got Desktop Handle.");
      try {
        desktop.open(ffile);
      } catch(Exception ex) {
        ex.printStackTrace();
      }
      System.out.println("File Opened.");
    }
  }

  public boolean action(Event evt, Object arg) {
    openFile("/Users/conor/1.txt");
    return true;
  }
}

I have compiled, created a jar file and signed it from the java source.

This produces a page with two buttons - a Java one (for testing) and a Javascript one. The Java button works fine as expected - and I can save the file etc. I want to pass the file path to the applet though so it is really the Javascript button I wish to get working. The Javascript one throws the following though:

Stack Trace

java.security.AccessControlException: access denied ("java.awt.AWTPermission" "showWindowWithoutWarningBanner")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:366)
at java.security.AccessController.checkPermission(AccessController.java:560)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.awt.Desktop.checkAWTPermission(Desktop.java:239)
at java.awt.Desktop.open(Desktop.java:267)
at localfile.openFile(localfile.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at sun.plugin.javascript.JSInvoke.invoke(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at sun.plugin.javascript.JSClassLoader.invoke(Unknown Source)
at sun.plugin2.liveconnect.JavaClass$MethodInfo.invoke(Unknown Source)
at sun.plugin2.liveconnect.JavaClass$MemberBundle.invoke(Unknown Source)
at sun.plugin2.liveconnect.JavaClass.invoke0(Unknown Source)
at sun.plugin2.liveconnect.JavaClass.invoke(Unknown Source)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$DefaultInvocationDelegate.invoke(Unknown Source)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo.doObjectOp(Unknown Source)
at sun.plugin2.main.client.LiveConnectSupport$PerAppletInfo$LiveConnectWorker.run(Unknown Source)
at java.lang.Thread.run(Thread.java:722)

I have also tried embedding the desktop.open call into a doPrivileged block, as follows:

  AccessController.doPrivileged(new PrivilegedAction() {
    public Object run() {
      try {
        desktop.open(ffile);
      } catch(Exception ex) {
        ex.printStackTrace();
      }
      return null;
    }
  });

but that throws error for javascript & java buttons as follows:

java.lang.SecurityException: class "localfile$1" does not match trust level of other classes in the same package

Any help would be appreciated.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
user1731782
  • 322
  • 2
  • 12
  • Consider using the [JWS file service](http://pscode.org/jws/api.html#fs) for this. It can be used even by a sand-boxed applet. – Andrew Thompson Jan 28 '13 at 23:35
  • Thanks for the feedback! I really need to make the call to the desktop.open() method though in order to open the relevant application to handle the file type. I'm not really interested in the files contents (within the helper applet anyway). The applet does no processing on the files contents, but only serves as a tool to open the relevant application on the client desktop for the given filetype. System is for web based document management btw. – user1731782 Jan 29 '13 at 00:26
  • *"need to make the call to the desktop.open()"* My bad. There were several 'applet permissions problem' questions open in my browser at the same time and I got confused. – Andrew Thompson Jan 29 '13 at 00:41
  • *"I have also tried.. doPrivileged block"* Yes, this will need it. 1) Edit the main code to show how you are using it. 2) Rebuild the Jar. 3) Check there are no 'loose' class files in the codebase. 4) Flush the class cache in the browser and reload the applet. – Andrew Thompson Jan 29 '13 at 01:35
  • It appears the security model doesn't allow it, unless the applet is added to the document by other Javascript: http://stackoverflow.com/questions/1068271/signed-applet-gives-accesscontrolexception-access-denied-when-calling-from-jav – VGR Jan 29 '13 at 11:18

1 Answers1

0

Got it to work, so thought I'd post the solution here...

When I was compiling the java file with the doPrivileged call in it, the javac compiler creates two files - localfile.class and localfile$1.class. I wasn't sure initially what the localfile$1.class was and just presumed it was a temporary file of some sort. It was however a class file corresponding to the anonymous class within the doPrilileged block and needed to be included in the .jar file and properly signed.

So anyway, html file is as before, and final java file is as follows:

localfile.java

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.security.*;

public class localfile extends Applet {

private static final long serialVersionUID = 1L;

public localfile() {
  Panel p = new Panel();
  p.add(new Button("Call from Java"));
  add("North",p);
}

public void openFile(String path) {
  System.out.println("File: " + path);
  final File ffile = new File(path);
  System.out.println("Got file.");
  if (Desktop.isDesktopSupported()) {
    System.out.println("Desktop is supported.");
    final Desktop desktop = Desktop.getDesktop();
    System.out.println("Got Desktop Handle.");
    AccessController.doPrivileged(new PrivilegedAction() {
      public Object run() {
        try {
          desktop.open(ffile);
        } catch(Exception ex) {
          ex.printStackTrace();
        }
        return null;
      }
    });
    System.out.println("File Opened.");
  }
}

public boolean action(Event evt, Object arg) {
  openFile("/Users/conor/1.txt");
  return true;
}

}

I also found that there was no need to have the javascript in the html file create the applet and insert it into the DOM. I think this was mentioned in the link @VGR linked to but it worked for me without it.

Thanks for all the help guys!

user1731782
  • 322
  • 2
  • 12