0

I have a problem accessing VFS resources in JBoss using ClassLoader#getResources(-).

I want to list all classpath resources (WEB-INF/classes/*) of some web application (*.war), so I can start with something like:

ClassLoader cl = Thread.currentThread().getContextClassLoader();

Enumeration<URL> resources = cl.getResources("");

while (resources.hasMoreElements()) {
    Path path = Paths.get(resources.nextElement().toURI());
    InputStream is = Files.newInputStream(path);
}

If I use this code in JBoss AS 7.1 which deploys the application in exploded mode - it works correctly.
As soon as you try to deploy it not in an exploded mode but as an *.war archive it starts throwing the NoSuchFileException.

I assume it's because the non-exploded archive uses virtual filesystem and all such loaded resources starts with `vfs:; in my case it was e.g. vfs:///content/WEB-INF/classes/someResource/.

Therefore the used Path was equal to /content/WEB-INF/classes/someResource and it was treated as a path that doesn't exist (it starts with root-node, slash) and throws an exception.

Just forget for a while about all those cases when the resources was loaded using the HTTP, FTP or others; I'm also not interested in scanning jar's within the classpath. I just want to read all file-based resources on the classpath root.

The problem is I need to enter each resource and find out if this is a folder - if so, list its all elements. That's why the Path element would be very useful here.

The problem is - what is the correct way you should list all resources within your web application?

It seems that resources with vfs: prefix was loaded by some special JBoss classloader, right?

Hence, will I be even able to access the resources in a portable manner (code that will work for JBoss, Glassfish, TomEE, ...)?

EDIT: To give you the context why I need the above: I would like to scan all *.properties files within the classpath and be able to access them with CDI. It has been described here.

Right now I'm switching from old File objects in favour of NIO.2 Paths, Files and basically: input streams.
However, both approaches have the same problem with the vfs:/ resources.

Piotr Nowicki
  • 17,914
  • 8
  • 63
  • 82
  • I doubt you will be able to find a solution that will work with any application server. When you try to hack something like that, it is usually a smell that it was not designed for it in the first place. What about going up to your real needs so we can find an alternative solution to "scan all my resources." – Raphael Jolivet Dec 06 '12 at 23:58
  • @RaphaelJolivet I've updated the question to give you more context why do I need this. Thanks! – Piotr Nowicki Dec 07 '12 at 09:48

2 Answers2

2

Does the following work?

ClassLoader cl = Thread.currentThread().getContextClassLoader();

Enumeration<URL> resources = cl.getResources("");

while (resources.hasMoreElements()) {
    InputStream is = resources.nextElement().openStream();
}
Philippe Marschall
  • 4,452
  • 1
  • 34
  • 52
  • Well, it works but at the same time I loose information if this is a directory or not. It's just an input stream - it doesn't have to be a directory and even if I'm sure it is - I don't know about any way of listing its content. This is something I will just updated in the original question. Thanks! – Piotr Nowicki Dec 07 '12 at 15:05
  • AFAIK it will never be a directory. – Philippe Marschall Dec 09 '12 at 22:27
  • That is the only standard and portable way to make it work on all app servers / environments. – Tomaz Cerar Dec 16 '12 at 23:23
0

Use this dependence

    <dependency>
        <groupId>org.jboss</groupId>
        <artifactId>jboss-vfs</artifactId>
        <version>3.2.15.Final</version>
    </dependency>

Import classs

import org.jboss.vfs.VFS;
import org.jboss.vfs.VirtualFile;
import org.jboss.vfs.VirtualFileFilter;

Method for list all class from WAR

 public void scan(ClassLoader classLoader) throws IOException, URISyntaxException {
    String optionalMainPackage="";
    // Example optionalMainPackage="com.domolin.security"
    Enumeration resources = classLoader.getResources(optionalMainPackage);
    while (resources.hasMoreElements()) {
        URL resource = (URL) resources.nextElement();
        System.out.println("URL "+resource);
        VirtualFile vfDir = VFS.getChild(resource.toURI());
        List<VirtualFile> jsonVFs = vfDir.getChildrenRecursively(new VirtualFileFilter() {
            @Override
            public boolean accepts(VirtualFile file) {
                return (file.isDirectory() || file.getName().endsWith(".class"));
            }
        });
        for (int i = 0; i < jsonVFs.size(); i++) {
            VirtualFile vf = jsonVFs.get(i);
            File f = vf.getPhysicalFile();
            System.out.println("CLASS: "+f.getName());
        }
    }
}

Usage

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
scan(classLoader);
Ronald Coarite
  • 4,460
  • 27
  • 31