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 public static class PatternFilter implements Filter{
82 private final Pattern pattern;
83
84 public PatternFilter(String pattern) {
85 this.pattern = Pattern.compile(pattern);
86 }
87
88 public boolean accept(String name) {
89 return pattern.matcher(name).matches();
90 }
91 }
92
93 private static boolean isCache() {
94 final String devMode = SystemProperty.getProperty("magnolia.develop");
95 return !"true".equalsIgnoreCase(devMode);
96 }
97
98
99
100
101
102 public static String[] findResources(String regex) {
103 return findResources(new PatternFilter(regex));
104 }
105
106
107
108
109
110
111 public static String[] findResources(Filter filter) {
112 final Set<String> resources = new HashSet<String>();
113 final ClassLoader cl = getCurrentClassLoader();
114
115
116
117 if (cl instanceof URLClassLoader) {
118 final URLClassLoader urlClassLoader = (URLClassLoader) cl;
119 final URL[] urls = urlClassLoader.getURLs();
120 if (urls.length == 1 && urls[0].getPath().endsWith("WEB-INF/classes/")) {
121
122 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.");
123 } else {
124 collectFromURLs(resources, urls, filter);
125 return resources.toArray(new String[resources.size()]);
126 }
127 }
128
129 try {
130
131
132
133
134
135 String classpath = BeanUtils.getProperty(cl, "classPath");
136
137 if (StringUtils.isNotEmpty(classpath)) {
138 collectFromClasspathString(resources, classpath, filter);
139 return resources.toArray(new String[resources.size()]);
140 }
141 }
142 catch (Throwable e) {
143
144 }
145
146
147
148 collectFromFileSystem(filter, resources);
149 return resources.toArray(new String[resources.size()]);
150 }
151
152 protected static void collectFromURLs(Collection<String> resources, URL[] urls, Filter filter) {
153
154 for (int j = 0; j < urls.length; j++) {
155 final File tofile = sanitizeToFile(urls[j]);
156 collectFiles(resources, tofile, filter);
157 }
158 }
159
160 protected static void collectFromClasspathString(Collection<String> resources, String classpath, Filter filter) {
161 String[] paths = classpath.split(File.pathSeparator);
162 for (int j = 0; j < paths.length; j++) {
163 final File tofile = new File(paths[j]);
164
165 if (tofile.exists()) {
166 collectFiles(resources, tofile, filter);
167 }
168 }
169 }
170
171 protected static void collectFromFileSystem(Filter filter, Collection<String> resources) {
172 File dir = new File(Path.getAbsoluteFileSystemPath("WEB-INF/lib"));
173 if (dir.exists()) {
174 File[] files = dir.listFiles(new FilenameFilter() {
175 public boolean accept(File file, String name) {
176 return name.endsWith(".jar");
177 }
178 });
179
180 for (int i = 0; i < files.length; i++) {
181 collectFiles(resources, files[i], filter);
182 }
183 }
184
185
186 File classFileDir = new File(Path.getAbsoluteFileSystemPath("WEB-INF/classes"));
187 if (classFileDir.exists()) {
188 collectFiles(resources, classFileDir, filter);
189 }
190 }
191
192 protected static File sanitizeToFile(URL url) {
193 try {
194 String fileUrl = url.getFile();
195
196 fileUrl = URLDecoder.decode(fileUrl, "UTF-8");
197
198
199 fileUrl = StringUtils.removeStart(fileUrl, "file:");
200 fileUrl = StringUtils.removeEnd(fileUrl, "!/");
201 return new File(fileUrl);
202 }
203 catch (UnsupportedEncodingException e) {
204 throw new RuntimeException(e);
205 }
206 }
207
208
209
210
211
212
213
214 private static void collectFiles(Collection<String> resources, File jarOrDir, Filter filter) {
215
216 if (!jarOrDir.exists()) {
217 log.warn("missing file: {}", jarOrDir.getAbsolutePath());
218 return;
219 }
220
221 if (jarOrDir.isDirectory()) {
222 log.debug("looking in dir {}", jarOrDir.getAbsolutePath());
223
224 Collection<File> files = FileUtils.listFiles(jarOrDir, TrueFileFilter.TRUE, TrueFileFilter.TRUE);
225 for (File file : files) {
226 String name = StringUtils.substringAfter(file.getPath(), jarOrDir.getPath());
227
228
229 name = StringUtils.replace(name, "\\", "/");
230 if (!name.startsWith("/")) {
231 name = "/" + name;
232 }
233
234 if (filter.accept(name)) {
235 resources.add(name);
236 }
237 }
238 }
239 else if (jarOrDir.getName().endsWith(".jar")) {
240 log.debug("looking in jar {}", jarOrDir.getAbsolutePath());
241 JarFile jar;
242 try {
243 jar = new JarFile(jarOrDir);
244 }
245 catch (IOException e) {
246 log.error("IOException opening file {}, skipping", jarOrDir.getAbsolutePath());
247 return;
248 }
249 for (Enumeration<JarEntry> em = jar.entries(); em.hasMoreElements();) {
250 JarEntry entry = em.nextElement();
251 if (!entry.isDirectory()) {
252 if (filter.accept("/" + entry.getName())) {
253 resources.add("/" + entry.getName());
254 }
255 }
256 }
257 try {
258 jar.close();
259 }
260 catch (IOException e) {
261 log.error("Failed to close jar file : " + e.getMessage());
262 log.debug("Failed to close jar file", e);
263 }
264 }
265 else {
266 log.debug("Unknown (not jar) file in classpath: {}, skipping.", jarOrDir.getName());
267 }
268
269 }
270
271 public static InputStream getStream(String name) throws IOException {
272 return getStream(name, isCache());
273 }
274
275
276
277
278
279
280
281 public static InputStream getStream(String name, boolean cache) throws IOException {
282 if (cache) {
283 return getCurrentClassLoader().getResourceAsStream(StringUtils.removeStart(name, "/"));
284 }
285
286
287 URL url = getResource(name);
288 if (url != null) {
289 return url.openStream();
290 }
291
292 log.debug("Can't find {}", name);
293 return null;
294 }
295
296
297
298
299
300 private static ClassLoader getCurrentClassLoader() {
301 return Thread.currentThread().getContextClassLoader();
302 }
303
304
305
306
307
308
309
310 public static URL getResource(String name) {
311 return getCurrentClassLoader().getResource(StringUtils.removeStart(name, "/"));
312 }
313
314 }