Why can't I open a JBoss vfs:/ URL?

13.8k views Asked by At

We are upgrading our application from JBoss 4 to JBoss 6.

A couple of pieces of our application get delivered to the client in an unusual way: jars are looked up inside of our application and sent to the client from a servlet, where the client extracts them in order to run certain support functions.

In JBoss 4 we would look these jars up with the classloader and find a jar:// URL which would be used to read the jar and send its contents to the client.

In JBoss 6 when we perform the lookup we get a vfs:/ URL. I understand that this is from the org.jboss.vfs package. Unfortunately when I call openStream() on this URL and read from the stream, I immediately get an EOF (read() returns -1).

What gives? Why can't I read the resource this URL refers to?

I've tried trying to access the underlying VFS packages to open the file through the JBoss VFS API, but most of the API appears to be private, and I couldn't find a routine to translate from a vfs:/ URL to a VFS VirtualFile object, so I couldn't get anywhere.

I can try to find the file on disk within JBoss, but that approach sounds very failure prone on upgrade.

Our old approach was to use Java Web Start to distribute the jars to the client and then look them up within Java Web Start's cache to extract them. But that broke on every minor upgrade of Java because the layout of the cache changed.

5

There are 5 answers

0
stacker On BEST ANSWER

The issue JBVFS-147 Cannot read from vfs: protocol URL is still unresolved, maybe you want to vote and watch this issue.

0
skiphoppy On

I've discovered that the getContent() method will give me a VirtualFile, which perhaps I can use. Still doesn't explain why I can't just do an openStream() on a vfs:/ URL.

import org.jboss.vfs.*;

URLConnection conn = new URL("vfs:/...").openConnection();
VirtualFile vf = (VirtualFile)conn.getContent();
InputStream is = vf.openStream();
0
skiphoppy On

Previous answer still yields a stream that can't be read from.

I found that I can get a physical File that the VirtualFile refers to, but the returned result refers to a directory named contents/ , within a directory that contains the actual file I'm looking for. So:

 import org.jboss.vfs.*;

  String filename = ...;
  URLConnection conn = new URL("vfs:/...").openConnection();
  VirtualFile vf = (VirtualFile)conn.getContent();
  File contentsFile = vf.getPhysicalFile();
  File dir = contentsFile.getParentFile();
  File physicalFile = new File(dir, filename);
  InputStream is = new FileInputStream(physicalFile);

What a mess. I still don't understand my original question, which is why would JBoss hand me a URL that can't be read from? But at least I can move on, for now.

0
Enver Haase On

I have investigated the behaviour in WildFly11.

In particular, only calling

getPhysicalFile();

has the side effect of actually creating physical files, and only those it seems you can read. In order to create all the files in a virtual directory I did:

      // Reflection as we cannot afford a dependency to WildFly11
      Object virtualFile = url.openConnection().getContent();
      Class virtualFileClass = virtualFile.getClass();         

      Method getChildrenRecursivelyMethod = virtualFileClass.getMethod("getChildrenRecursively");
      Method getPhysicalFileMethod = virtualFileClass.getMethod("getPhysicalFile");

      List virtualFiles = (List) getChildrenRecursivelyMethod.invoke(virtualFile);
      for (Object child : virtualFiles){
        File physical = (File) getPhysicalFileMethod.invoke(child); // side effect: create real-world files
      }
      File rootDir = (File) getPhysicalFileMethod.invoke(virtualFile);

Now I can list the root directory and access its files, in the physical world.

0
Enver Haase On

That getContent() approach for virtual files does not work either. I tested it, using reflection to avoid a dependency to JBoss/Wildfly which you probably don't want in a Servlet.

// Reflection as we cannot afford a dependency to WildFly11
Object virtualFile = url.openConnection().getContent();
Class virtualFileClass = virtualFile.getClass();
DevModeInitializer.log(virtualFileClass.getCanonicalName());
Method openStreamMethod = virtualFileClass.getMethod("openStream");
InputStream inputStream = (InputStream) openStreamMethod.invoke(virtualFile);

Reading from that Stream also yields only "-1", that is, it is empty.