/* * JBoss, Home of Professional Open Source * Copyright 2011, Red Hat, Inc. and/or its affiliates, and individual * contributors by the @authors tag. See the copyright.txt in the * distribution for a full listing of individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.solder.resourceLoader; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.net.URL; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.annotation.PreDestroy; import javax.enterprise.inject.Any; import javax.enterprise.inject.Instance; //import org.jboss.solder.core.Veto; import org.apache.deltaspike.core.api.exclude.annotation.Exclude; import org.jboss.solder.reflection.AnnotationInstanceProvider; /** * <p> * The ResourceProvider allows dynamic loading of managed resources. For * example: * </p> * <p/> * <pre> * @Inject * void readXml(ResourceProvider provider, String fileName) * { * InputStream webXml = provider.loadResourceStream(fileName); * } * </pre> * <p/> * <p> * If you know the name of the resource you are loading at development time you * can inject it directly using the <code>@{@link Resource}</code> * qualifier. * </p> * <p/> * <p> * If a input stream is loaded, it will be automatically closed when the * InputStream goes out of scope. If a URL is used to create an input stream, * the application is responsible for closing it. For this reason it is * recommended that managed input streams are used where possible. * </p> * * @author Pete Muir * @see Resource */ @Exclude public class ResourceProvider implements Serializable { private static final long serialVersionUID = -4463427096501401965L; private final transient AnnotationInstanceProvider annotationInstanceProvider = new AnnotationInstanceProvider(); ; private final Instance<URL> urlProvider; private final Instance<InputStream> inputStreamProvider; private final Instance<Properties> propertiesBundleProvider; private final Instance<Collection<URL>> urlsProvider; private final Instance<Collection<InputStream>> inputStreamsProvider; private final Instance<Collection<Properties>> propertiesBundlesProvider; // Workaround WELD-466 private final Set<InputStream> streamsCache; //@Inject ResourceProvider(@Any Instance<InputStream> inputStreamProvider, @Any Instance<URL> urlProvider, @Any Instance<Collection<InputStream>> inputStreamsProvider, @Any Instance<Collection<URL>> urlsProvider, @Any Instance<Properties> propertiesBundleProvider, @Any Instance<Collection<Properties>> propertiesBundlesProvider) { this.inputStreamProvider = inputStreamProvider; this.urlProvider = urlProvider; this.urlsProvider = urlsProvider; this.inputStreamsProvider = inputStreamsProvider; this.propertiesBundleProvider = propertiesBundleProvider; this.propertiesBundlesProvider = propertiesBundlesProvider; this.streamsCache = new HashSet<InputStream>(); } /** * <p> * Load a resource. * </p> * <p/> * <p> * The resource loaders will be searched in precedence order, the first * result found being returned. The default search order is: * </p> * <p/> * <ul> * <li>classpath</li> * <li>servlet context, if available</li> * </ul> * <p/> * <p> * However extensions may extend this list. * </p> * * @param name the resource to load * @return an input stream providing access to the resource, or * <code>null</code> if no resource can be loaded * @throws RuntimeException if an error occurs loading the resource */ public InputStream loadResourceStream(String name) { if (name == null || name.equals("")) { throw new IllegalArgumentException("You must specify the name of the resource to load"); } Map<String, Object> values = new HashMap<String, Object>(); values.put("value", name); InputStream stream = inputStreamProvider.select(annotationInstanceProvider.get(Resource.class, values)).get(); // Workaround WELD-466 streamsCache.add(stream); return stream; } /** * <p> * Load all resources known to the resource loader by name. * </p> * <p/> * <p> * By default, Solder will search: * </p> * <p/> * <ul> * <li>classpath</li> * <li>servlet context, if available</li> * </ul> * <p/> * <p> * However extensions may extend this list. * </p> * * @param name the resource to load * @return a collection of input streams pointing to the resources, or an * empty collection if no resources are found * @throws RuntimeException if an error occurs loading the resource */ public Collection<InputStream> loadResourcesStreams(String name) { if (name == null || name.equals("")) { throw new IllegalArgumentException("You must specify the name of the resource to load"); } Map<String, Object> values = new HashMap<String, Object>(); values.put("value", name); Collection<InputStream> streams = inputStreamsProvider.select(annotationInstanceProvider.get(Resource.class, values)).get(); // Workaround WELD-466 streamsCache.addAll(streams); return streams; } /** * <p> * Load a resource. * </p> * <p/> * <p> * The resource loaders will be searched in precedence order, the first * result found being returned. The default search order is: * </p> * <p/> * <ul> * <li>classpath</li> * <li>servlet context, if available</li> * </ul> * <p/> * <p> * However extensions may extend this list. * </p> * * @param name the resource to load * @return a URL pointing to the resource, or <code>null</code> if no * resource can be loaded * @throws RuntimeException if an error occurs loading the resource */ public URL loadResource(String name) { if (name == null || name.equals("")) { throw new IllegalArgumentException("You must specify the name of the resource to load"); } Map<String, Object> values = new HashMap<String, Object>(); values.put("value", name); return urlProvider.select(annotationInstanceProvider.get(Resource.class, values)).get(); } /** * <p> * Load all resources known to the resource loader by name. * </p> * <p/> * <p> * By default, Solder will search: * </p> * <p/> * <ul> * <li>classpath</li> * <li>servlet context, if available</li> * </ul> * <p/> * <p> * However extensions may extend this list. * </p> * * @param name the resource to load * @return a collection of URLs pointing to the resources, or an empty * collection if no resources are found * @throws RuntimeException if an error occurs loading the resource */ public Collection<URL> loadResources(String name) { if (name == null || name.equals("")) { throw new IllegalArgumentException("You must specify the name of the resource to load"); } Map<String, Object> values = new HashMap<String, Object>(); values.put("value", name); return urlsProvider.select(annotationInstanceProvider.get(Resource.class, values)).get(); } /** * <p> * Load a properties bundle. * </p> * <p/> * <p> * The resource loaders will be searched in precedence order, the first * result found being returned. The default search order is: * </p> * <p/> * <ul> * <li>classpath</li> * <li>servlet context, if available</li> * </ul> * <p/> * <p> * However extensions may extend this list. * </p> * * @param name the name of the properties bundle to load * @return a set of properties, or an empty set if no properties bundle can * be loaded * @throws RuntimeException if an error occurs loading the resource */ public Properties loadPropertiesBundle(String name) { if (name == null || name.equals("")) { throw new IllegalArgumentException("You must specify the name of the properties bundle to load"); } Map<String, Object> values = new HashMap<String, Object>(); values.put("value", name); return propertiesBundleProvider.select(annotationInstanceProvider.get(Resource.class, values)).get(); } /** * <p> * Load all properties bundles known to the resource loader by name. * </p> * <p/> * <p> * By default, Solder will search: * </p> * <p/> * <ul> * <li>classpath</li> * <li>servlet context, if available</li> * </ul> * <p/> * <p> * However extensions may extend this list. * </p> * * @param name the name of the properties bundle to load * @return a collection of properties bundles, or an empty collection if no * resources are found * @throws RuntimeException if an error occurs loading the properties bundle */ public Collection<Properties> loadPropertiesBundles(String name) { if (name == null || name.equals("")) { throw new IllegalArgumentException("You must specify the name of the properties bundles to load"); } Map<String, Object> values = new HashMap<String, Object>(); values.put("value", name); return propertiesBundlesProvider.select(annotationInstanceProvider.get(Resource.class, values)).get(); } @SuppressWarnings("unused") @PreDestroy private void cleanup() { for (InputStream stream : streamsCache) { try { stream.close(); } catch (IOException e) { // Nothing we can do about this } } } }