1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.util;
35
36 import info.magnolia.cms.core.Path;
37 import info.magnolia.cms.core.SystemProperty;
38
39 import java.io.File;
40 import java.io.FilenameFilter;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.UnsupportedEncodingException;
44 import java.net.URL;
45 import java.net.URLClassLoader;
46 import java.net.URLDecoder;
47 import java.util.Collection;
48 import java.util.Enumeration;
49 import java.util.HashSet;
50 import java.util.Set;
51 import java.util.jar.JarEntry;
52 import java.util.jar.JarFile;
53 import java.util.regex.Pattern;
54
55 import org.apache.commons.beanutils.BeanUtils;
56 import org.apache.commons.io.FileUtils;
57 import org.apache.commons.io.filefilter.TrueFileFilter;
58 import org.apache.commons.lang.StringUtils;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62
63
64
65
66
67
68
69 public class ClasspathResourcesUtil {
70 private static final Logger log = LoggerFactory.getLogger(ClasspathResourcesUtil.class);
71
72
73
74
75
76
77 public static interface Filter {
78 public boolean accept(String name);
79 }
80
81
82
83
84 public static class PatternFilter implements Filter{
85 private final Pattern pattern;
86
87 public PatternFilter(String pattern) {
88 this.pattern = Pattern.compile(pattern);
89 }
90
91 public boolean accept(String name) {
92 return pattern.matcher(name).matches();
93 }
94 }
95
96 private static boolean isCache() {
97 final String devMode = SystemProperty.getProperty("magnolia.develop");
98 return !"true".equalsIgnoreCase(devMode);
99 }
100
101
102
103
104
105 public static String[] findResources(String regex) {
106 return findResources(new PatternFilter(regex));
107 }
108
109
110
111
112
113
114 public static String[] findResources(Filter filter) {
115 final Set<String> resources = new HashSet<String>();
116 final ClassLoader cl = getCurrentClassLoader();
117
118
119
120 if (cl instanceof URLClassLoader) {
121 final URLClassLoader urlClassLoader = (URLClassLoader) cl;
122 final URL[] urls = urlClassLoader.getURLs();
123 if (urls.length == 1 && urls[0].getPath().endsWith("WEB-INF/classes/")) {
124
125 log.warn("Looks like we're in a JBoss 5 expanded war directory, will attempt to load resources from the file system instead; see MAGNOLIA-2577.");
126 } else {
127 collectFromURLs(resources, urls, filter);
128 return resources.toArray(new String[resources.size()]);
129 }
130 }
131
132 try {
133
134
135
136
137
138 String classpath = BeanUtils.getProperty(cl, "classPath");
139
140 if (StringUtils.isNotEmpty(classpath)) {
141 collectFromClasspathString(resources, classpath, filter);
142 return resources.toArray(new String[resources.size()]);
143 }
144 }
145 catch (Throwable e) {
146
147 }
148
149
150
151 collectFromFileSystem(filter, resources);
152 return resources.toArray(new String[resources.size()]);
153 }
154
155 protected static void collectFromURLs(Collection<String> resources, URL[] urls, Filter filter) {
156
157 for (int j = 0; j < urls.length; j++) {
158 final File tofile = sanitizeToFile(urls[j]);
159 collectFiles(resources, tofile, filter);
160 }
161 }
162
163 protected static void collectFromClasspathString(Collection<String> resources, String classpath, Filter filter) {
164 String[] paths = classpath.split(File.pathSeparator);
165 for (int j = 0; j < paths.length; j++) {
166 final File tofile = new File(paths[j]);
167
168 if (tofile.exists()) {
169 collectFiles(resources, tofile, filter);
170 }
171 }
172 }
173
174 protected static void collectFromFileSystem(Filter filter, Collection<String> resources) {
175 File dir = new File(Path.getAbsoluteFileSystemPath("WEB-INF/lib"));
176 if (dir.exists()) {
177 File[] files = dir.listFiles(new FilenameFilter() {
178 public boolean accept(File file, String name) {
179 return name.endsWith(".jar");
180 }
181 });
182
183 for (int i = 0; i < files.length; i++) {
184 collectFiles(resources, files[i], filter);
185 }
186 }
187
188
189 File classFileDir = new File(Path.getAbsoluteFileSystemPath("WEB-INF/classes"));
190 if (classFileDir.exists()) {
191 collectFiles(resources, classFileDir, filter);
192 }
193 }
194
195 protected static File sanitizeToFile(URL url) {
196 try {
197 String fileUrl = url.getFile();
198
199 fileUrl = URLDecoder.decode(fileUrl, "UTF-8");
200
201
202 fileUrl = StringUtils.removeStart(fileUrl, "file:");
203 fileUrl = StringUtils.removeEnd(fileUrl, "!/");
204 return new File(fileUrl);
205 }
206 catch (UnsupportedEncodingException e) {
207 throw new RuntimeException(e);
208 }
209 }
210
211
212
213
214
215
216
217 private static void collectFiles(Collection<String> resources, File jarOrDir, Filter filter) {
218
219 if (!jarOrDir.exists()) {
220 log.warn("missing file: {}", jarOrDir.getAbsolutePath());
221 return;
222 }
223
224 if (jarOrDir.isDirectory()) {
225 log.debug("looking in dir {}", jarOrDir.getAbsolutePath());
226
227 Collection<File> files = FileUtils.listFiles(jarOrDir, TrueFileFilter.TRUE, TrueFileFilter.TRUE);
228 for (File file : files) {
229 String name = StringUtils.substringAfter(file.getPath(), jarOrDir.getPath());
230
231
232 name = StringUtils.replace(name, "\\", "/");
233 if (!name.startsWith("/")) {
234 name = "/" + name;
235 }
236
237 if (filter.accept(name)) {
238 resources.add(name);
239 }
240 }
241 }
242 else if (jarOrDir.getName().endsWith(".jar")) {
243 log.debug("looking in jar {}", jarOrDir.getAbsolutePath());
244 JarFile jar;
245 try {
246 jar = new JarFile(jarOrDir);
247 }
248 catch (IOException e) {
249 log.error("IOException opening file {}, skipping", jarOrDir.getAbsolutePath());
250 return;
251 }
252 for (Enumeration<JarEntry> em = jar.entries(); em.hasMoreElements();) {
253 JarEntry entry = em.nextElement();
254 if (!entry.isDirectory()) {
255 if (filter.accept("/" + entry.getName())) {
256 resources.add("/" + entry.getName());
257 }
258 }
259 }
260 try {
261 jar.close();
262 }
263 catch (IOException e) {
264 log.error("Failed to close jar file : " + e.getMessage());
265 log.debug("Failed to close jar file", e);
266 }
267 }
268 else {
269 log.debug("Unknown (not jar) file in classpath: {}, skipping.", jarOrDir.getName());
270 }
271
272 }
273
274 public static InputStream getStream(String name) throws IOException {
275 return getStream(name, isCache());
276 }
277
278
279
280
281
282
283
284 public static InputStream getStream(String name, boolean cache) throws IOException {
285 if (cache) {
286 return getCurrentClassLoader().getResourceAsStream(StringUtils.removeStart(name, "/"));
287 }
288
289
290 URL url = getResource(name);
291 if (url != null) {
292 return url.openStream();
293 }
294
295 log.debug("Can't find {}", name);
296 return null;
297 }
298
299
300
301
302
303 private static ClassLoader getCurrentClassLoader() {
304 return Thread.currentThread().getContextClassLoader();
305 }
306
307
308
309
310
311
312
313 public static URL getResource(String name) {
314 return getCurrentClassLoader().getResource(StringUtils.removeStart(name, "/"));
315 }
316
317 }