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