1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs2.impl;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.MalformedURLException;
22 import java.net.URL;
23 import java.util.ArrayList;
24 import java.util.Enumeration;
25 import java.util.Objects;
26
27 import javax.xml.parsers.DocumentBuilder;
28 import javax.xml.parsers.DocumentBuilderFactory;
29 import javax.xml.parsers.ParserConfigurationException;
30
31 import org.apache.commons.io.IOUtils;
32 import org.apache.commons.lang3.ArrayUtils;
33 import org.apache.commons.lang3.StringUtils;
34 import org.apache.commons.vfs2.FileSystemException;
35 import org.apache.commons.vfs2.VfsLog;
36 import org.apache.commons.vfs2.operations.FileOperationProvider;
37 import org.apache.commons.vfs2.provider.FileProvider;
38 import org.apache.commons.vfs2.util.Messages;
39 import org.w3c.dom.Element;
40 import org.w3c.dom.NodeList;
41
42
43
44
45
46
47
48
49
50 public class StandardFileSystemManager extends DefaultFileSystemManager {
51 private static final String CONFIG_RESOURCE = "providers.xml";
52 private static final String PLUGIN_CONFIG_RESOURCE = "META-INF/vfs-providers.xml";
53
54 private URL configUri;
55 private ClassLoader classLoader;
56
57
58
59
60 public StandardFileSystemManager() {
61
62 }
63
64
65
66
67
68
69 private void addExtensionMap(final Element map) {
70 final String extension = map.getAttribute("extension");
71 final String scheme = map.getAttribute("scheme");
72 if (!StringUtils.isEmpty(scheme)) {
73 addExtensionMap(extension, scheme);
74 }
75 }
76
77
78
79
80
81
82 private void addMimeTypeMap(final Element map) {
83 final String mimeType = map.getAttribute("mime-type");
84 final String scheme = map.getAttribute("scheme");
85 addMimeTypeMap(mimeType, scheme);
86 }
87
88
89
90
91 private void addOperationProvider(final Element providerDef) throws FileSystemException {
92 final String className = providerDef.getAttribute("class-name");
93
94
95 final String[] schemas = getSchemas(providerDef);
96 for (final String schema : schemas) {
97 if (hasProvider(schema)) {
98 final FileOperationProvider operationProvider = (FileOperationProvider) createInstance(className);
99 addOperationProvider(schema, operationProvider);
100 }
101 }
102 }
103
104
105
106
107
108
109
110
111 private void addProvider(final Element providerDef, final boolean isDefault) throws FileSystemException {
112 final String className = providerDef.getAttribute("class-name");
113
114
115 final String[] requiredSchemes = getRequiredSchemes(providerDef);
116 for (final String requiredScheme : requiredSchemes) {
117 if (!hasProvider(requiredScheme)) {
118 final String msg = Messages.getString("vfs.impl/skipping-provider-scheme.debug", className,
119 requiredScheme);
120 VfsLog.debug(getLogger(), getLogger(), msg);
121 return;
122 }
123 }
124
125
126 final String[] requiredClasses = getRequiredClasses(providerDef);
127 for (final String requiredClass : requiredClasses) {
128 if (!findClass(requiredClass)) {
129 final String msg = Messages.getString("vfs.impl/skipping-provider.debug", className, requiredClass);
130 VfsLog.debug(getLogger(), getLogger(), msg);
131 return;
132 }
133 }
134
135
136 final FileProvider provider = (FileProvider) createInstance(className);
137 final String[] schemas = getSchemas(providerDef);
138 if (schemas.length > 0) {
139 addProvider(schemas, provider);
140 }
141
142
143 if (isDefault) {
144 setDefaultProvider(provider);
145 }
146 }
147
148
149
150
151
152
153
154 private void configure(final Element config) throws FileSystemException {
155
156 final NodeList providers = config.getElementsByTagName("provider");
157 final int count = providers.getLength();
158 for (int i = 0; i < count; i++) {
159 final Element provider = (Element) providers.item(i);
160 addProvider(provider, false);
161 }
162
163
164 final NodeList operationProviders = config.getElementsByTagName("operationProvider");
165 for (int i = 0; i < operationProviders.getLength(); i++) {
166 final Element operationProvider = (Element) operationProviders.item(i);
167 addOperationProvider(operationProvider);
168 }
169
170
171 final NodeList defProviders = config.getElementsByTagName("default-provider");
172 if (defProviders.getLength() > 0) {
173 final Element provider = (Element) defProviders.item(0);
174 addProvider(provider, true);
175 }
176
177
178 final NodeList mimeTypes = config.getElementsByTagName("mime-type-map");
179 for (int i = 0; i < mimeTypes.getLength(); i++) {
180 final Element map = (Element) mimeTypes.item(i);
181 addMimeTypeMap(map);
182 }
183
184
185 final NodeList extensions = config.getElementsByTagName("extension-map");
186 for (int i = 0; i < extensions.getLength(); i++) {
187 final Element map = (Element) extensions.item(i);
188 addExtensionMap(map);
189 }
190 }
191
192
193
194
195
196
197
198 private void configure(final URL configUri) throws FileSystemException {
199 InputStream configStream = null;
200 try {
201
202
203 final DocumentBuilder builder = createDocumentBuilder();
204 configStream = configUri.openStream();
205 final Element config = builder.parse(configStream).getDocumentElement();
206
207 configure(config);
208 } catch (final Exception e) {
209 throw new FileSystemException("vfs.impl/load-config.error", configUri.toString(), e);
210 } finally {
211 IOUtils.closeQuietly(configStream, e -> getLogger().warn(e.getLocalizedMessage(), e));
212 }
213 }
214
215
216
217
218
219
220
221
222
223 protected void configurePlugins() throws FileSystemException {
224 final Enumeration<URL> enumResources;
225 try {
226 enumResources = enumerateResources(PLUGIN_CONFIG_RESOURCE);
227 } catch (final IOException e) {
228 throw new FileSystemException(e);
229 }
230
231 while (enumResources.hasMoreElements()) {
232 configure(enumResources.nextElement());
233 }
234 }
235
236
237
238
239
240
241 protected DefaultFileReplicator createDefaultFileReplicator() {
242 return new DefaultFileReplicator();
243 }
244
245
246
247
248
249
250
251 private DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
252 final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
253 factory.setIgnoringElementContentWhitespace(true);
254 factory.setIgnoringComments(true);
255 factory.setExpandEntityReferences(true);
256 return factory.newDocumentBuilder();
257 }
258
259
260
261
262 private Object createInstance(final String className) throws FileSystemException {
263 try {
264 return loadClass(className).getConstructor().newInstance();
265 } catch (final Exception e) {
266 throw new FileSystemException("vfs.impl/create-provider.error", className, e);
267 }
268 }
269
270
271
272
273
274
275
276 private Enumeration<URL> enumerateResources(final String name) throws IOException {
277 Enumeration<URL> enumeration = findClassLoader().getResources(name);
278 if (enumeration == null || !enumeration.hasMoreElements()) {
279 enumeration = getValidClassLoader(getClass()).getResources(name);
280 }
281 return enumeration;
282 }
283
284
285
286
287 private boolean findClass(final String className) {
288 try {
289 loadClass(className);
290 return true;
291 } catch (final ClassNotFoundException e) {
292 return false;
293 }
294 }
295
296
297
298
299
300
301 private ClassLoader findClassLoader() {
302 if (classLoader != null) {
303 return classLoader;
304 }
305 final ClassLoader cl = Thread.currentThread().getContextClassLoader();
306 if (cl != null) {
307 return cl;
308 }
309 return getValidClassLoader(getClass());
310 }
311
312
313
314
315 private String[] getRequiredClasses(final Element providerDef) {
316 final ArrayList<String> classes = new ArrayList<>();
317 final NodeList deps = providerDef.getElementsByTagName("if-available");
318 final int count = deps.getLength();
319 for (int i = 0; i < count; i++) {
320 final Element dep = (Element) deps.item(i);
321 final String className = dep.getAttribute("class-name");
322 if (!StringUtils.isEmpty(className)) {
323 classes.add(className);
324 }
325 }
326 return classes.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
327 }
328
329
330
331
332 private String[] getRequiredSchemes(final Element providerDef) {
333 final ArrayList<String> schemes = new ArrayList<>();
334 final NodeList deps = providerDef.getElementsByTagName("if-available");
335 final int count = deps.getLength();
336 for (int i = 0; i < count; i++) {
337 final Element dep = (Element) deps.item(i);
338 final String scheme = dep.getAttribute("scheme");
339 if (!StringUtils.isEmpty(scheme)) {
340 schemes.add(scheme);
341 }
342 }
343 return schemes.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
344 }
345
346
347
348
349 private String[] getSchemas(final Element provider) {
350 final ArrayList<String> schemas = new ArrayList<>();
351 final NodeList schemaElements = provider.getElementsByTagName("scheme");
352 final int count = schemaElements.getLength();
353 for (int i = 0; i < count; i++) {
354 final Element scheme = (Element) schemaElements.item(i);
355 schemas.add(scheme.getAttribute("name"));
356 }
357 return schemas.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
358 }
359
360 private ClassLoader getValidClassLoader(final Class<?> clazz) {
361 return validateClassLoader(clazz.getClassLoader(), clazz);
362 }
363
364
365
366
367
368
369 @Override
370 public void init() throws FileSystemException {
371
372 final DefaultFileReplicator replicator = createDefaultFileReplicator();
373 setReplicator(new PrivilegedFileReplicator(replicator));
374 setTemporaryFileStore(replicator);
375
376 if (configUri == null) {
377
378 final URL url = getClass().getResource(CONFIG_RESOURCE);
379 FileSystemException.requireNonNull(url, "vfs.impl/find-config-file.error", CONFIG_RESOURCE);
380 configUri = url;
381 }
382
383 configure(configUri);
384 configurePlugins();
385
386
387 super.init();
388 }
389
390
391
392
393
394
395
396 private Class<?> loadClass(final String className) throws ClassNotFoundException {
397 try {
398 return findClassLoader().loadClass(className);
399 } catch (final ClassNotFoundException e) {
400 return getValidClassLoader(getClass()).loadClass(className);
401 }
402 }
403
404
405
406
407
408
409 public void setClassLoader(final ClassLoader classLoader) {
410 this.classLoader = classLoader;
411 }
412
413
414
415
416
417
418 public void setConfiguration(final String configUri) {
419 try {
420 setConfiguration(new URL(configUri));
421 } catch (final MalformedURLException e) {
422 getLogger().warn(e.getLocalizedMessage(), e);
423 }
424 }
425
426
427
428
429
430
431 public void setConfiguration(final URL configUri) {
432 this.configUri = configUri;
433 }
434
435 private ClassLoader validateClassLoader(final ClassLoader clazzLoader, final Class<?> clazz) {
436 return Objects.requireNonNull(clazzLoader, "The class loader for " + clazz
437 + " is null; some Java implementations use null for the bootstrap class loader.");
438 }
439
440 }