Monthly Archives: July 2011

Regexp searching resources in web app classpath

Couple of times by now I had to solve the issue of finding and loading some files which are embedded in jar files in a web application, and each time had to find a solution. This time, however made a post on the blog, so next time I’m confronted with the same problem, the solution would be handy.

So, let’s assume we have couple of property files, or xml files or whatever, which could be possibly embedded in the jar files of the web application located in WEB-INF/libs folder. So, how can we retrieve the list of them, as we aren’t even aware of the jar files which could be in the libs folder?

By searching the net, I found this thread discussing the issue, however seems like the code fails to work in Tomcat 6. After a bit of debugging the code and tweaking it, turned out the issue was related to the way the ClassLoader  was retrieved. The code which should be used (at least in case of Tomcat 6) is:

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

After a bit more tweaking around and fixing some small issue, I ended up with a handy singleton which is really easy to be used:

package some.package;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * Adapted source from
 * http://www.coderanch.com/t/278514/Streams/java/Reading-files-classpath-searching-pattern
 */
public class ClassPathSearcher
{
    static ClassPathSearcher instance = null;
    Set<String> classPathSet = new HashSet<String>();
    static final Logger log = Logger.getLogger(
            ClassPathSearcher.class.getName());

    private ClassPathSearcher()
    {
    }

    public static ClassPathSearcher getInstance()
    {
        if (instance == null)
        {
            instance = new ClassPathSearcher();
            instance.init();
            log.log(Level.INFO, "ClassPathSearcher initialized");
        }

        return instance;
    }

    private void init()
    {
        ClassLoader applicationClassLoader = Thread.currentThread()
                .getContextClassLoader();

        URL[] urls = ((URLClassLoader) applicationClassLoader).getURLs();

        for (URL url : urls)
        {
            String urlStr = url.getPath();
            if (urlStr.startsWith("file:"))
            {
                urlStr = urlStr.substring(5);
            }

            if (urlStr.endsWith("!/"))
            {
                urlStr = urlStr.substring(0,urlStr.length() - 2);
            }

            classPathSet.add(urlStr);
        }

        String classPath = System.getProperty("java.class.path");

        String[] pathElements = classPath.split(
                System.getProperty("path.separator"));

        for (String el : pathElements)
        {
            classPathSet.add(el);
        }
    }

    public Map<String, InputStream> findFilesInClassPath(String fileNamePattern)
    {
        Map<String, InputStream> result = new TreeMap<String, InputStream>();

        for (String element : classPathSet)
        {
            try
            {
                File newFile = new File(element);

                if (newFile.isDirectory())
                {
                    result.putAll(findResourceInDirectory(newFile,
                            fileNamePattern));
                }
                else
                {
                    result.putAll(findResourceInFile(newFile, fileNamePattern));
                }
            }
            catch (IOException e)
            {
                log.log(Level.WARNING, "Exception:"+ e);
            }
        }

        return result;
    }

    private Map<String, InputStream> findResourceInFile(File resourceFile,
            String fileNamePattern)
            throws IOException
    {
        Map<String, InputStream> result = new TreeMap<String, InputStream>();

        if (resourceFile.canRead() &&
                resourceFile.getAbsolutePath().endsWith(".jar"))
        {
            JarFile jarFile = new JarFile(resourceFile);

            Enumeration<JarEntry> entries = jarFile.entries();

            while (entries.hasMoreElements())
            {
                JarEntry singleEntry = entries.nextElement();

                if (singleEntry.getName().matches(fileNamePattern))
                {
                    result.put(jarFile.getName() + "/" + singleEntry.getName(),
                            jarFile.getInputStream(singleEntry));
                }
            }
        }
        return result;
    }

    private Map<String, InputStream> findResourceInDirectory(File directory,
            String fileNamePattern)
        throws IOException
    {
        Map<String, InputStream> result = new TreeMap<String, InputStream>();

        File[] files = directory.listFiles();

        for (File currentFile : files)
        {
            if (currentFile.getAbsolutePath().matches(fileNamePattern))
            {
                result.put(currentFile.getAbsolutePath(), new FileInputStream(
                        currentFile));
            }
            else if (currentFile.isDirectory())
            {
                result.putAll(findResourceInDirectory(currentFile,
                        fileNamePattern));
            }
            else
            {
                result.putAll(findResourceInFile(currentFile, fileNamePattern));
            }
        }

        return result;
    }
}

Using it is really easy:

Map<String, InputStream> files = ClassPathSearcher.
                getInstance().findFilesInClassPath("<your pattern here>");

Sources can be found here: ClassPathSearcher.java