package org.jboss.solder.servlet.resource; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import javax.servlet.ServletContext; import org.jboss.solder.logging.Logger; import org.jboss.solder.util.Sortable; import org.jboss.solder.util.service.ServiceLoader; /** * <p> * A utility for classes that need to access web resources. * </p> * <p> * This class provides a way to obtain the location of web resources without using the {@link ServletContext}. This is * especially interesting for extensions that are executed very early in the CDI startup process because the * {@link ServletContext} may not be available in this stage. * </p> * <p> * The class makes use of the {@link WebResourceLocationProvider} SPI to actually find the resources. This allows to write * custom implementations optimized for specific environments. * </p> * * @author Christian Kaltepoth * @see WebResourceLocationProvider */ public class WebResourceLocator { private final Logger log = Logger.getLogger(WebResourceLocator.class); /** * Returns the resource located at the named path as an <code>InputStream</code> object. The path must begin with a * <tt>/</tt> and is interpreted as relative to the current context root. * * @param path The path of the resource (e.g. "/WEB-INF/web.xml") * @return the <code>InputStream</code> or <code>null</code> if the resource could not be located */ public InputStream getWebResource(String path) { // execute the SPI implementation URL resourceLocation = getWebResourceUrl(path); // accept the first result if (resourceLocation != null) { // try to open an InputStream try { return resourceLocation.openStream(); } // log failure and continue with next provider catch (IOException e) { if (log.isDebugEnabled()) { log.debug("Error opening: " + resourceLocation.toString(), e); } } } return null; } /** * Returns the <code>URL</code> for the resource located at the named path. The path must begin with a * <tt>/</tt> and is interpreted as relative to the current context root. * * @param path The path of the resource (e.g. "/WEB-INF/web.xml") * @return the <code>URL</code> or <code>null</code> if the resource could not be located */ public URL getWebResourceUrl(final String path) { // build sorted list of provider implementations List<WebResourceLocationProvider> providers = new ArrayList<WebResourceLocationProvider>(); Iterator<WebResourceLocationProvider> iterator = ServiceLoader.load(WebResourceLocationProvider.class).iterator(); while (iterator.hasNext()) { providers.add(iterator.next()); } Collections.sort(providers, new Sortable.Comparator()); // prefer the context classloader ClassLoader classLoader = WebResourceLocator.class.getClassLoader(); // process each provider one by one for (WebResourceLocationProvider provider : providers) { // execute the SPI implementation final URL resourceLocation = provider.getWebResource(path, classLoader); if (resourceLocation != null) { return resourceLocation; } } return null; } }