views:

649

answers:

2

Hi,

I have a sandboxed Applet, but that should not make a difference.

The Applet consists of 2 jars. If I host both files on the same domain1 all is fine. Due to certain special circumstances I need to host jar2 on a different domain2.

In the applet tag I list both files archive="jar1.jar, http://domain2.com/jar2.jar".

First it seems to be working great. Both jars are loaded and everything works fine. Still, as soon as I try to access a resource (like an image) from INSIDE one of the jars there is a problem.

How do I get resources from my jars? I get resources by first getting an URL for the location of the resource:

public static URL getURL(String name) {return ResUtils.class.getResource(path);}

If I host both jars on domain1 this method returns an URL. When hosted on two domains getURL(...) returns NULL which then results in an Exception when fetching the resource:

Caused by: java.lang.IllegalArgumentException: input == null!
    at javax.imageio.ImageIO.read(Unknown Source)

I guess ResUtils.class.getResource uses its Classloader to return an URL. For some reason when hosting both jars on two domains add calls to getRessource() return NULL.

So my question is:

  • Why does getURL return NULL?

Is the Java plugin designed to disallow hosting those jars on different domains? How do I have to load my resources when I host the jars on different domains?

I am stuck for a week now - thanks for your help,

+2  A: 

Try something like this:

      ClassLoader cl = Thread.currentThread().getContextClassLoader();
      URL url = cl.getResource("imagename.gif");
      System.out.println("URL is: " + url);
      ImageIcon icon = new ImageIcon(url);

Using the context classloader is generally the best way to load images from jar files.

Edit1: BTW, I am surprised that the first suggestion did not work. If memory serves me right, the Thread.currentThread().getContextClassLoader() suggestion should have given you a reference to a classloader that could have located resources from either jar file.

Edit2: none of the above works in this case. Curiosity got the best of me so I had to try it. The plugin classloader just seems too confused to load resources from jar files hosted on another server, even though it has no problems loading classes. What I found is that a manual method does work to load resources like this:

  String manualString = "jar:http://spider.grunt.webhop.net/clubjar.jar!/club.gif";
  URL manualURL = new URL(manualString);
  BufferedImage buf = ImageIO.read(manualURL);
  System.out.println("manual buf: " +buf);

To me, this looks like a bug with the plugin classloader. We should be able to use the classloader getResource() or getResourceAsStream() methods to locate a valid resource. Not so in this case. The ImageIO class can read our manual URL, but the classloader cannot give us one.

Gary
Thanks for your great help. At least I don't feel anymore like a total idiot. This manualString you basically just typed in, or is there a good way to get it? Btw, the jar from the first domain CAN load resources from inside itself.
Andy Schmidt
Can you post a link to you applet example that does not work?
Andy Schmidt
https://iris.dev.java.net also uses jars from different domains. I can only guess that they do not need to load resources from jars from the second domain.
Andy Schmidt
I basically just typed in the url. The format is here:http://java.sun.com/docs/books/tutorial/deployment/jar/jarclassloader.htmlI did notice that the applet would be able to load images from the 2nd jar file when running locally under appletviewer. The same applet fails when running through a browser. I did not actually deploy the applet anywhere public. I was able to see the same results you see running the applet locally through firefox.
Gary
I didn't even try appletviewer because the results are always so much different from what you expect running it on a server.
Andy Schmidt
inquiring minds want to know - did this solution work for you? If so, could you accept this answer?
Gary
Sure - I'll accept it. I wonder if there is a way to automatically generate the URL String: "jar:http://spider.grunt.webhop.net/clubjar.jar!/club.gif" or at least parts of it???
Andy Schmidt
Also marked it as helpful :)Do you think we should file a bug with Sun?
Andy Schmidt
A: 

Thread.currentThread().getContextClassLoader(); doesn't solve my problem.

All my resources are in the same 'res' folder/package - same as the Class to fetch them: ResUtils (see source below).

If a class in jar1 from domain1 calls ResUtils.getImageIcon("trash.gif"); getURL(...) returns an URL: url -> jar:http://domain1/bun.jar!/res/trash.gif

If a class in jar2 from domain2 calls ResUtils.getImageIcon("trash.gif"); getURL(...) returns an NULL: url -> null

package res;

public class ResUtils {
       private static final String PATH =  "/" + (ResUtils.class.getPackage().getName().replace(".", "/")) + "/";
         public static URL getURL(String name)  {return ResUtils.class.getResource(PATH + name);}
          public static ImageIcon getImageIcon(String name) {
           return new ImageIcon(getBufferedImage(name));
       }

       public static BufferedImage getBufferedImage(String name) {
           try {
               URL url = getURL(name);
               return ImageIO.read(url);
           } catch (Exception e) {
               e.printStackTrace();
               return new BufferedImage(10,10, BufferedImage.TYPE_INT_RGB);
           }
       }
}
Andy Schmidt
Your ResUtils.getURL() is using the classloader that loaded the ResUtils class to load all of your images. ResUtils must be located in jar1 in your case. I believe the Java plugin will use separate classloaders to load jars from different domains. Your ResUtils class only knows about one classloader. See next answer for the code.
Gary
BTW, your code section is much easier to read if place all of your code using the code tag
Gary
I know. I tried to do that, but it only decorated 'package res;'Back to the URL problem. Nothing works. I tried now every possible combination. Nada - all URLs returned are Null.Even a simple URL url = Class2.class.getResource("res/trash2.gif"); does not work, although trash2.gif is located in jar2.jar hosted on domain2.I would be happy to be proven wrong but until then I think it is impossible to load any resources from classes in jar2, even if the resources are in jar2.I have Java 1.6_u14 - perhaps they changed something.
Andy Schmidt
I ran into the same issue pasting code. The simplest way to put all the code into a code block is to first paste the code into the edit window, select the code block, then press the code button. I would edit your post to fix it, but it requires a higher reputation.Anyway, I do remember seeing this issue from somewhere before. Java 1.6_u10 changed quite a bit under the covers. I believe there is a documented issue regarding this. Anyway, do you really need to load jar files from multiple domains? Why not just host them all together?
Gary
Ok, I tried to fix code formatting. Thanks! I just tested it with pre-Update10 Java6 and even Java5. Everywhere the same problem.I have setup a minimal testcase with two jar on two domains and I still cannot solve the problem . I guess I will need to convince someone to setup a similar system without my intervention to check this out.
Andy Schmidt
I edited my answer to show a solution I found to work. Yes, I even tried it.
Gary