1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.vfs2.provider;
18
19 import java.io.File;
20 import java.lang.reflect.InvocationTargetException;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.Map;
26 import java.util.concurrent.atomic.AtomicInteger;
27 import java.util.concurrent.atomic.AtomicLong;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.commons.vfs2.CacheStrategy;
32 import org.apache.commons.vfs2.Capability;
33 import org.apache.commons.vfs2.FileListener;
34 import org.apache.commons.vfs2.FileName;
35 import org.apache.commons.vfs2.FileObject;
36 import org.apache.commons.vfs2.FileSelector;
37 import org.apache.commons.vfs2.FileSystem;
38 import org.apache.commons.vfs2.FileSystemConfigBuilder;
39 import org.apache.commons.vfs2.FileSystemException;
40 import org.apache.commons.vfs2.FileSystemManager;
41 import org.apache.commons.vfs2.FileSystemOptions;
42 import org.apache.commons.vfs2.FilesCache;
43 import org.apache.commons.vfs2.VfsLog;
44 import org.apache.commons.vfs2.cache.OnCallRefreshFileObject;
45 import org.apache.commons.vfs2.events.AbstractFileChangeEvent;
46 import org.apache.commons.vfs2.events.ChangedEvent;
47 import org.apache.commons.vfs2.events.CreateEvent;
48 import org.apache.commons.vfs2.events.DeleteEvent;
49 import org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder;
50 import org.apache.commons.vfs2.util.FileObjectUtils;
51 import org.apache.commons.vfs2.util.Messages;
52
53
54
55
56 public abstract class AbstractFileSystem extends AbstractVfsComponent implements FileSystem {
57
58
59 AbstractFileSystem() {
60 this(null, null, null);
61 }
62
63 private static final FileListenerer">FileListener[] EMPTY_FILE_LISTENER_ARRAY = new FileListener[0];
64
65 private static final Log LOG = LogFactory.getLog(AbstractFileSystem.class);
66
67
68
69
70 private final FileName rootName;
71
72
73
74
75
76 private final String rootURI;
77
78 private final Collection<Capability> capabilities = new HashSet<>();
79
80 private final FileObject parentLayer;
81
82
83
84
85 private final Map<FileName, ArrayList<FileListener>> listenerMap = new HashMap<>();
86
87
88
89
90 private final FileSystemOptions fileSystemOptions;
91
92
93
94
95 private final AtomicLong useCount = new AtomicLong();
96
97 private FileSystemKey cacheKey;
98
99
100
101
102 private final AtomicInteger openStreams = new AtomicInteger(0);
103
104 protected AbstractFileSystem(final FileName rootFileName, final FileObject parentLayer,
105 final FileSystemOptions fileSystemOptions) {
106 this.parentLayer = parentLayer;
107 this.rootName = rootFileName;
108 this.fileSystemOptions = fileSystemOptions;
109 final FileSystemConfigBuilder builder = DefaultFileSystemConfigBuilder.getInstance();
110 String uri = builder.getRootURI(fileSystemOptions);
111 if (uri == null) {
112 uri = rootFileName != null ? rootFileName.getURI() : null;
113 }
114 this.rootURI = uri;
115 }
116
117
118
119
120
121
122 @Override
123 public void init() throws FileSystemException {
124 addCapabilities(capabilities);
125 }
126
127
128
129
130 @Override
131 public void close() {
132 closeCommunicationLink();
133 }
134
135
136
137
138 public void closeCommunicationLink() {
139 synchronized (this) {
140 doCloseCommunicationLink();
141 }
142 }
143
144
145
146
147 protected void doCloseCommunicationLink() {
148
149 }
150
151
152
153
154
155
156
157
158
159
160
161 protected abstract FileObject createFile(final AbstractFileName name) throws Exception;
162
163
164
165
166
167
168 protected abstract void addCapabilities(Collection<Capability> caps);
169
170
171
172
173
174
175 @Override
176 public FileName getRootName() {
177 return rootName;
178 }
179
180
181
182
183
184
185
186 @Override
187 public String getRootURI() {
188 return rootURI;
189 }
190
191
192
193
194
195
196 protected void putFileToCache(final FileObject file) {
197 getFilesCache().putFile(file);
198 }
199
200 private FilesCache getFilesCache() {
201 final FilesCache filesCache = getContext().getFileSystemManager().getFilesCache();
202 if (filesCache == null) {
203 throw new RuntimeException(Messages.getString("vfs.provider/files-cache-missing.error"));
204 }
205
206 return filesCache;
207 }
208
209
210
211
212
213
214
215 protected FileObject getFileFromCache(final FileName name) {
216 return getFilesCache().getFile(this, name);
217 }
218
219
220
221
222
223
224 protected void removeFileFromCache(final FileName name) {
225 getFilesCache().removeFile(this, name);
226 }
227
228
229
230
231
232
233
234 @Override
235 public boolean hasCapability(final Capability capability) {
236 return capabilities.contains(capability);
237 }
238
239
240
241
242
243
244
245
246 @Override
247 public Object getAttribute(final String attrName) throws FileSystemException {
248 throw new FileSystemException("vfs.provider/get-attribute-not-supported.error");
249 }
250
251
252
253
254
255
256
257
258 @Override
259 public void setAttribute(final String attrName, final Object value) throws FileSystemException {
260 throw new FileSystemException("vfs.provider/set-attribute-not-supported.error");
261 }
262
263
264
265
266
267
268
269 @Override
270 public FileObject getParentLayer() throws FileSystemException {
271 return parentLayer;
272 }
273
274
275
276
277
278
279
280 @Override
281 public FileObject getRoot() throws FileSystemException {
282 return resolveFile(rootName);
283 }
284
285
286
287
288
289
290
291
292 @Override
293 public FileObject resolveFile(final String nameStr) throws FileSystemException {
294
295 return resolveFile(getFileSystemManager().resolveName(rootName, nameStr));
296 }
297
298
299
300
301
302
303
304
305 @Override
306 public FileObject resolveFile(final FileName name) throws FileSystemException {
307 return resolveFile(name, true);
308 }
309
310 private synchronized FileObject resolveFile(final FileName name, final boolean useCache)
311 throws FileSystemException {
312 if (!rootName.getRootURI().equals(name.getRootURI())) {
313 throw new FileSystemException("vfs.provider/mismatched-fs-for-name.error", name, rootName,
314 name.getRootURI());
315 }
316
317
318 FileObject file;
319 if (useCache) {
320 file = getFileFromCache(name);
321 } else {
322 file = null;
323 }
324
325 if (file == null) {
326 try {
327 file = createFile((AbstractFileName) name);
328 } catch (final Exception e) {
329 throw new FileSystemException("vfs.provider/resolve-file.error", name, e);
330 }
331
332 file = decorateFileObject(file);
333
334
335 if (useCache) {
336 putFileToCache(file);
337 }
338 }
339
340
341
342
343 if (getFileSystemManager().getCacheStrategy().equals(CacheStrategy.ON_RESOLVE)) {
344 file.refresh();
345 }
346 return file;
347 }
348
349 protected FileObject./org/apache/commons/vfs2/FileObject.html#FileObject">FileObject decorateFileObject(FileObject file) throws FileSystemException {
350 if (getFileSystemManager().getCacheStrategy().equals(CacheStrategy.ON_CALL)) {
351 file = new OnCallRefreshFileObject(file);
352 }
353
354 if (getFileSystemManager().getFileObjectDecoratorConst() != null) {
355 try {
356 file = (FileObject) getFileSystemManager().getFileObjectDecoratorConst().newInstance(file);
357 } catch (final InstantiationException | IllegalAccessException | InvocationTargetException e) {
358 throw new FileSystemException("vfs.impl/invalid-decorator.error",
359 getFileSystemManager().getFileObjectDecorator().getName(), e);
360 }
361 }
362
363 return file;
364 }
365
366
367
368
369
370
371
372
373
374 @Override
375 public File replicateFile(final FileObject file, final FileSelector selector) throws FileSystemException {
376 if (!FileObjectUtils.exists(file)) {
377 throw new FileSystemException("vfs.provider/replicate-missing-file.error", file.getName());
378 }
379
380 try {
381 return doReplicateFile(file, selector);
382 } catch (final Exception e) {
383 throw new FileSystemException("vfs.provider/replicate-file.error", file.getName(), e);
384 }
385 }
386
387
388
389
390
391
392 @Override
393 public FileSystemOptions getFileSystemOptions() {
394 return fileSystemOptions;
395 }
396
397
398
399
400
401
402 @Override
403 public FileSystemManager getFileSystemManager() {
404 return getContext().getFileSystemManager();
405 }
406
407
408
409
410
411
412 @Override
413 public double getLastModTimeAccuracy() {
414 return 0;
415 }
416
417
418
419
420
421
422
423
424
425 protected File doReplicateFile(final FileObject file, final FileSelector selector) throws Exception {
426 return getContext().getReplicator().replicateFile(file, selector);
427 }
428
429
430
431
432
433
434
435
436 @Override
437 public void addJunction(final String junctionPoint, final FileObject targetFile) throws FileSystemException {
438 throw new FileSystemException("vfs.provider/junctions-not-supported.error", rootName);
439 }
440
441
442
443
444
445
446
447 @Override
448 public void removeJunction(final String junctionPoint) throws FileSystemException {
449 throw new FileSystemException("vfs.provider/junctions-not-supported.error", rootName);
450 }
451
452
453
454
455
456
457
458 @Override
459 public void addListener(final FileObject file, final FileListener listener) {
460 synchronized (listenerMap) {
461 final ArrayList<FileListener> listeners = listenerMap.computeIfAbsent(file.getName(), k -> new ArrayList<>());
462 listeners.add(listener);
463 }
464 }
465
466
467
468
469
470
471
472 @Override
473 public void removeListener(final FileObject file, final FileListener listener) {
474 synchronized (listenerMap) {
475 final ArrayList<?> listeners = listenerMap.get(file.getName());
476 if (listeners != null) {
477 listeners.remove(listener);
478 if (listeners.isEmpty()) {
479 listenerMap.remove(file.getName());
480 }
481 }
482 }
483 }
484
485
486
487
488
489
490 public void fireFileCreated(final FileObject file) {
491 fireEvent(new CreateEvent(file));
492 }
493
494
495
496
497
498
499 public void fireFileDeleted(final FileObject file) {
500 fireEvent(new DeleteEvent(file));
501 }
502
503
504
505
506
507
508
509
510
511 public void fireFileChanged(final FileObject file) {
512 fireEvent(new ChangedEvent(file));
513 }
514
515
516
517
518
519
520 public boolean isReleaseable() {
521 return useCount.get() < 1;
522 }
523
524 void freeResources() {
525
526 }
527
528
529
530
531 private void fireEvent(final AbstractFileChangeEvent event) {
532 FileListener[] fileListeners = null;
533 final FileObject fileObject = event.getFileObject();
534
535 synchronized (listenerMap) {
536 final ArrayList<?> listeners = listenerMap.get(fileObject.getName());
537 if (listeners != null) {
538 fileListeners = listeners.toArray(EMPTY_FILE_LISTENER_ARRAY);
539 }
540 }
541
542 if (fileListeners != null) {
543 for (final FileListener fileListener : fileListeners) {
544 try {
545 event.notify(fileListener);
546 } catch (final Exception e) {
547 final String message = Messages.getString("vfs.provider/notify-listener.warn", fileObject);
548
549 VfsLog.warn(getLogger(), LOG, message, e);
550 }
551 }
552 }
553 }
554
555 void fileObjectHanded(final FileObject fileObject) {
556 useCount.incrementAndGet();
557 }
558
559 void fileObjectDestroyed(final FileObject fileObject) {
560 useCount.decrementAndGet();
561 }
562
563 void setCacheKey(final FileSystemKey cacheKey) {
564 this.cacheKey = cacheKey;
565 }
566
567 FileSystemKey getCacheKey() {
568 return this.cacheKey;
569 }
570
571 void streamOpened() {
572 openStreams.incrementAndGet();
573 }
574
575 void streamClosed() {
576 if (openStreams.decrementAndGet() == 0) {
577 notifyAllStreamsClosed();
578 }
579 }
580
581
582
583
584 protected void notifyAllStreamsClosed() {
585
586 }
587
588
589
590
591
592
593 public boolean isOpen() {
594 return openStreams.get() > 0;
595 }
596 }