001 /* This file is part of the project "Hilbert II" - http://www.qedeq.org
002 *
003 * Copyright 2000-2011, Michael Meyling <mime@qedeq.org>.
004 *
005 * "Hilbert II" is free software; you can redistribute
006 * it and/or modify it under the terms of the GNU General Public
007 * License as published by the Free Software Foundation; either
008 * version 2 of the License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU General Public License for more details.
014 */
015
016 package org.qedeq.base.io;
017
018 import java.io.File;
019 import java.io.IOException;
020 import java.io.InputStream;
021 import java.lang.reflect.InvocationTargetException;
022 import java.lang.reflect.Method;
023 import java.net.URL;
024
025 import org.qedeq.base.trace.Trace;
026
027
028 /**
029 * Utility methods for accessing classes and resources using an appropriate class loader.
030 * Adapted from org.apache.myfaces.trinidad.util.ClassLoaderUtils.
031 *
032 * @author Michael Meyling
033 */
034 public final class ResourceLoaderUtility {
035
036 /** This class. */
037 private static final Class CLASS = ResourceLoaderUtility.class;
038
039 /**
040 * Constructor, should never be called.
041 */
042 private ResourceLoaderUtility() {
043 // don't call me
044 }
045
046 /**
047 * Loads the class with the specified name. For Java 2 callers, the current thread's context
048 * class loader is preferred, falling back on the system class loader of the caller when the
049 * current thread's context is not set, or the caller is pre Java 2.
050 *
051 * @param name Name of class to load.
052 * @return The resulting <code>Class</code> object
053 * @exception ClassNotFoundException Class was not found.
054 */
055 public static Class loadClass(final String name) throws ClassNotFoundException {
056 return loadClass(name, null);
057 }
058
059 /**
060 * Locates the resource with the specified name. For Java 2 callers, the current thread's
061 * context class loader is preferred, falling back on the system class loader of the caller when
062 * the current thread's context is not set, or the caller is pre Java 2.
063 *
064 * @param name Resource name.
065 * @return Resulting <code>URL</code> object. Maybe <code>null</code>.
066 */
067 public static URL getResourceUrl(final String name) {
068 return getResourceUrl(name, ResourceLoaderUtility.class.getClassLoader());
069 }
070
071 /**
072 * Locates the stream resource with the specified name. For Java 2 callers, the current thread's
073 * context class loader is preferred, falling back on the system class loader of the caller when
074 * the current thread's context is not set, or the caller is pre Java 2.
075 *
076 * @param name the name of the resource
077 * @return the resulting <code>InputStream</code> object
078 */
079 public static InputStream getResourceAsStream(final String name) {
080 return getResourceAsStream(name, null);
081 }
082
083 /**
084 * Loads the class with the specified name. For Java 2 callers, the current thread's context
085 * class loader is preferred, falling back on the class loader of the caller when the current
086 * thread's context is not set, or the caller is pre Java 2. If the callerClassLoader is null,
087 * then fall back on the system class loader.
088 *
089 * @param name the name of the class
090 * @param callerClassLoader the calling class loader context
091 * @return the resulting <code>Class</code> object
092 * @exception ClassNotFoundException if the class was not found
093 */
094 public static Class loadClass(final String name, final ClassLoader callerClassLoader)
095 throws ClassNotFoundException {
096 Class clazz = null;
097
098 try {
099 final ClassLoader loader = getContextClassLoader();
100
101 if (loader != null) {
102 clazz = loader.loadClass(name);
103 }
104 } catch (ClassNotFoundException e) {
105 // treat as though loader not set
106 }
107
108 if (clazz == null) {
109 if (callerClassLoader != null) {
110 clazz = callerClassLoader.loadClass(name);
111 } else {
112 clazz = Class.forName(name);
113 }
114 }
115
116 return clazz;
117 }
118
119 /**
120 * Locates the resource with the specified name. For Java 2 callers, the current thread's
121 * context class loader is preferred, falling back on the class loader of the caller when the
122 * current thread's context is not set, or the caller is pre Java 2. If the callerClassLoader is
123 * null, then fall back on the system class loader.
124 *
125 * @param name the name of the resource
126 * @param callerClassLoader the calling class loader context
127 * @return the resulting <code>URL</code> object
128 */
129 public static URL getResourceUrl(final String name, final ClassLoader callerClassLoader) {
130 checkResourceName(name);
131
132 URL url = null;
133
134 final ClassLoader loader = getContextClassLoader();
135
136 if (loader != null) {
137 url = loader.getResource(name);
138 }
139
140 if (url == null) {
141 // no success, now we try the given class loader
142 if (callerClassLoader != null) {
143 url = callerClassLoader.getResource(name);
144 } else {
145 // last try: get resource via classpath
146 url = ClassLoader.getSystemResource(name);
147 }
148 }
149 return url;
150 }
151
152 /**
153 * Locates the resource stream with the specified name. For Java 2 callers, the current thread's
154 * context class loader is preferred, falling back on the class loader of the caller when the
155 * current thread's context is not set, or the caller is pre Java 2. If the callerClassLoader is
156 * null, then fall back on the system class loader.
157 *
158 * @param name the name of the resource
159 * @param callerClassLoader the calling class loader context
160 * @return the resulting <code>InputStream</code> object
161 */
162 public static InputStream getResourceAsStream(final String name,
163 final ClassLoader callerClassLoader) {
164 checkResourceName(name);
165
166 InputStream stream = null;
167
168 final ClassLoader loader = getContextClassLoader();
169
170 if (loader != null) {
171 stream = loader.getResourceAsStream(name);
172 }
173 if (stream == null) {
174 if (callerClassLoader != null) {
175 stream = callerClassLoader.getResourceAsStream(name);
176 } else {
177 stream = ClassLoader.getSystemResourceAsStream(name);
178 }
179 }
180
181 return stream;
182 }
183
184 /**
185 * Dynamically accesses the current context class loader. Returns <code>null</code> if there is
186 * no per-thread context class loader. Also if the JRE is below 1.2 or something else went wrong
187 * the method returns <code>null</code>.
188 *
189 * @return ClassLoader.
190 */
191 public static ClassLoader getContextClassLoader() {
192 try {
193 final Method method = Thread.class.getMethod("getContextClassLoader", null);
194 return (ClassLoader) method.invoke(Thread.currentThread(), null);
195 } catch (RuntimeException e) {
196 return null;
197 } catch (IllegalAccessException e) {
198 return null;
199 } catch (InvocationTargetException e) {
200 return null;
201 } catch (NoSuchMethodException e) {
202 return null;
203 }
204 }
205
206 private static void checkResourceName(final String name) {
207 if ((name != null) && name.startsWith("/")) {
208 Trace.info(CLASS, "ClassLoaderUtility", "checkResourceName",
209 "resource name not portable: " + name);
210
211 }
212 }
213
214 /**
215 * Get resource file. The resource is located within the file system if it exists already.
216 * If not it is loaded as resource and then saved as a file.
217 *
218 * @param startDirectory Start looking from this directory.
219 * @param resourceDirectoryName Within this directory
220 * (relative to <code>startDirectory</code>).
221 * @param resourceName Look for this resource file.
222 * @return Resource file.
223 */
224 public static File getResourceFile(final File startDirectory,
225 final String resourceDirectoryName, final String resourceName) {
226 final File resourceDir = new File(startDirectory, resourceDirectoryName);
227 final File resource = new File(resourceDir, resourceName);
228 if (!resource.exists()) {
229 final URL url = getResourceUrl(resourceDirectoryName + "/" + resourceName);
230 if (url == null) {
231 Trace.info(ResourceLoaderUtility.class, "getResourceUrlAndMakeLocalCopy",
232 "URL not found for: " + resourceDirectoryName + "/" + resourceName);
233 return null;
234 }
235 try {
236 if (!resourceDir.exists()) {
237 if (!resourceDir.mkdirs()) {
238 Trace.info(ResourceLoaderUtility.class, "getResourceUrlAndMakeLocalCopy",
239 "creation failed: " + resourceDir);
240 }
241 }
242 IoUtility.saveFile(url, resource);
243 } catch (IOException e) {
244 Trace.fatal(ResourceLoaderUtility.class, "getResourceUrlAndMakeLocalCopy",
245 "resource can not be saved", e);
246 }
247 }
248 return resource;
249 }
250
251 }
|