Class MultiFileSystem
- All Implemented Interfaces:
Serializable
This filesystem has no form of storage in and of itself. Rather, it composes and proxies one or more "delegate" filesystems. The result is that of a "layered" sandwich of filesystems, each able to provide files to appear in the merged result. Often the frontmost layer will be writable, and all changes to the filesystem are sent to this layer, but that behavior is configurable.
The layers are ordered so that entries in a filesystem in "front" can override one in "back".
Since it is often not straightforward to arrange layers so that particular overrides work,
as of org.openide.filesystems 7.36
you may set the special file attribute weight
to any Number
on a layer entry.
(If unspecified, the implicit default value is zero.)
A variant with a higher weight will override one with a lower weight even if it is further back.
(The exception is that entries in a writable frontmost layer always override other layers,
regardless of weight.)
Creating a new MultiFileSystem
is easy in the simplest cases: just call MultiFileSystem(FileSystem[])
and pass a list of delegates. If you pass it only read-only delegates, the
composite will also be read-only. Or you may pass it one or more writable filesystems (make sure the first
file system is one of them); then it will be able to act as a writable file system, by default storing all
actual changes on the first file system.
This class is intended to be subclassed more than to be used as is, since typically a user of it will want
finer-grain control over several aspects of its operation. When subclassed, delegates may be changed dynamically
and the "contents" of the composite filesystem will
automatically be updated.
One of the more common methods to override is createWritableOn(java.lang.String)
, which should provide the delegate
filesystem which should be used to store changes to the indicated file (represented as a resource path).
Normally, this is hardcoded to provide the first filesystem (assuming it is writable); subclasses may store
changes on another filesystem, or they may select a filesystem to store changes on according to (for example)
file extension. This could be used to separate source from compiled/deployable files, for instance. Or some
filesystems may prefer to attempt to make changes in whatever filesystem provided the original file, assuming
it is writable; this is also possible, getting information about the file's origin from findSystem(org.openide.filesystems.FileObject)
.
Another likely candidate for overriding is findResourceOn(org.openide.filesystems.FileSystem, java.lang.String)
. Normally this method just looks up
resources by the normal means on delegate filesystems and provides the resultant file objects. However it
could be customized to "warp" the delegates somehow; for example, selecting a different virtual root for one
of them.
notifyMigration(org.openide.filesystems.FileObject)
provides a means for subclasses to update some state (for example, visual
annotations) when the filesystem used to produce a given file changes dynamically. This most often happens
when a file provided by a back delegate is written to, and the result stored on the foremost delegate, but it
could occur in other situations too (e.g. change of delegates, removal of overriding file on underlying front
delegate, etc.).
When new files are added to the MultiFileSystem
, normally they will be physically added to
the foremost delegate, although as previously mentioned they can be customized. When their contents (or
attributes) are changed, by default these changes are again made in the foremost delegate. But what if a file
is deleted? There must be a way to indicate on the foremost delegate that it should not appear in the
composite (even while it remains in one of the delegates). For this reason, MultiFileSystem
uses
"masks" which are simply empty files named according to the file they should hide, but with the suffix
_hidden
. Thus, for example, if there is a file subdir/readme.txt_hidden
in a front
delegate it will hide any files named subdir/readme.txt
in delegates further back. These masks
are automatically created as needed when files are "deleted" from MultiFileSystem
; or delegate
filesystems may explicitly provide them. Normally the mask files are not themselves visible as FileObject
s, since they are an artifact of the deletion logic. However, when nesting
MultiFileSystem
s inside other MultiFileSystem
s, it can be useful to have delegates
be able to mask files not provided by their immediate siblings, but by cousins. For this reason, nested
subclasses may call setPropagateMasks(boolean)
to make the mask files propagate up one or more nesting levels
and thus remain potent against cousin delegates.
To support rollback, two pseudo-attribute is defined since 8.5: revealEntries
typed
as Map<String, FileObject & Callable>
. The attribute is available on a folder, and contains information
on child FileObjects, which have been overriden or masked by the writable layer of the MFS. Map is keyed by
child name, the value is a FileObject that allows access to the masked child attributes and/or content.
The returned FileObjects do not leak its neighbours from the lower layers. The parent, children or siblings are
returned from the MFS, if they exist. The FileObjects can be also casted to Callable<FileObject>
. When
called, the original version of the file is restored on the MultiFileSystem, and the restored instance is returned
as result.
- See Also:
-
Nested Class Summary
Nested classes/interfaces inherited from class org.openide.filesystems.FileSystem
FileSystem.AtomicAction
-
Field Summary
Fields inherited from class org.openide.filesystems.FileSystem
PROP_DISPLAY_NAME, PROP_HIDDEN, PROP_READ_ONLY, PROP_ROOT, PROP_SYSTEM_NAME, PROP_VALID
-
Constructor Summary
ConstructorsModifierConstructorDescriptionprotected
Creates new empty MultiFileSystem.MultiFileSystem
(FileSystem... fileSystems) Creates new MultiFileSystem. -
Method Summary
Modifier and TypeMethodDescriptionvoid
Notifies all encapsulated filesystems in advance to superclass behaviour.protected Set
<? extends FileSystem> createLocksOn
(String name) When a file is about to be locked this method is consulted to choose which delegates should be locked.protected FileSystem
createWritableOn
(String name) Finds the system to create writable version of the file on.protected FileSystem
createWritableOnForRename
(String oldName, String newName) Special case of createWritableOn (@see #createWritableOn).Deprecated.findResource
(String name) Finds a file given its full resource path.protected FileObject
findResourceOn
(FileSystem fs, String res) Finds a resource on given filesystem.protected final FileSystem
findSystem
(FileObject fo) For given file object finds the filesystem that the object is placed on.protected final FileSystem[]
All filesystem that this system delegates to.The name of the filesystem.final boolean
Will mask files that are not used be listed as children?getRoot()
Root of the filesystem.protected static Enumeration
<String> hiddenFiles
(FileObject folder, boolean rec) Finds all hidden files on given filesystem.protected final void
hideResource
(String res, boolean hide) Marks a resource as hidden.boolean
This filesystem is readonly if it has not writable system.protected void
Notification that a file has been marked unimportant.protected void
Notification that a file has migrated from one filesystem to another.void
refresh
(boolean expected) Actually implements contract of FileSystem.refresh().void
Notifies all encapsulated filesystems in advance to superclass behaviour.protected final void
setDelegates
(FileSystem... fileSystems) Changes the filesystems that this system delegates toprotected final void
setPropagateMasks
(boolean pm) Set whether unused mask files should be listed as children.Methods inherited from class org.openide.filesystems.FileSystem
addFileChangeListener, addFileStatusListener, addPropertyChangeListener, addVetoableChangeListener, createTempFile, findExtrasFor, fireFileStatusChanged, firePropertyChange, fireVetoableChange, getDecorator, getSystemName, getTempFolder, isDefault, isValid, removeFileChangeListener, removeFileStatusListener, removePropertyChangeListener, removeVetoableChangeListener, runAtomicAction, setSystemName, toString
-
Constructor Details
-
MultiFileSystem
protected MultiFileSystem()Creates new empty MultiFileSystem. Useful only for subclasses. -
MultiFileSystem
Creates new MultiFileSystem.- Parameters:
fileSystems
- array of filesystems (can contain nulls)
-
-
Method Details
-
refresh
public void refresh(boolean expected) Actually implements contract of FileSystem.refresh().- Overrides:
refresh
in classFileSystem
- Parameters:
expected
- should the file events be marked as expected change or not?- See Also:
-
setDelegates
Changes the filesystems that this system delegates to- Parameters:
fileSystems
- array of filesystems
-
getDelegates
All filesystem that this system delegates to.- Returns:
- the array of delegates
-
getPropagateMasks
public final boolean getPropagateMasks()Will mask files that are not used be listed as children?- Returns:
true
if so
-
setPropagateMasks
protected final void setPropagateMasks(boolean pm) Set whether unused mask files should be listed as children.- Parameters:
pm
-true
if so
-
isReadOnly
public boolean isReadOnly()This filesystem is readonly if it has not writable system.- Specified by:
isReadOnly
in classFileSystem
- Returns:
- true if the system is read-only
-
getDisplayName
The name of the filesystem.- Specified by:
getDisplayName
in classFileSystem
- Returns:
- user presentable name of the filesystem
-
getRoot
Root of the filesystem.- Specified by:
getRoot
in classFileSystem
- Returns:
- root folder of whole filesystem
-
find
Deprecated.Description copied from class:FileSystem
Finds file in the filesystem by name.The default implementation converts dots in the package name into slashes, concatenates the strings, adds any extension prefixed by a dot and calls the
findResource
method.Note: when both of
name
andext
arenull
then name and extension should be ignored and scan should look only for a package.- Overrides:
find
in classFileSystem
- Parameters:
aPackage
- package name where each package component is separated by a dotname
- name of the file (without dots) ornull
if one wants to obtain a folder (package) and not a file in itext
- extension of the file (without leading dot) ornull
if one needs a package and not a file- Returns:
- a file object that represents a file with the given name or
null
if the file does not exist
-
findResource
Description copied from class:FileSystem
Finds a file given its full resource path.- Specified by:
findResource
in classFileSystem
- Parameters:
name
- the resource path, e.g. "dir/subdir/file.ext" or "dir/subdir" or "dir"- Returns:
- a file object with the given path or
null
if no such file exists
-
findSystem
For given file object finds the filesystem that the object is placed on. The object must be created by this filesystem orherwise IllegalArgumentException is thrown.- Parameters:
fo
- file object- Returns:
- the filesystem (from the list we delegate to) the object has file on
- Throws:
IllegalArgumentException
- if the file object is not represented in this filesystem
-
hideResource
Marks a resource as hidden. It will not be listed in the list of files. Uses createMaskOn method to determine on which filesystem to mark the file.- Parameters:
res
- resource name of file to hide or showhide
- true if we should hide the file/false otherwise- Throws:
IOException
- if it is not possible
-
findResourceOn
Finds a resource on given filesystem. The default implementation simply uses FileSystem.findResource, but subclasses may override this method to hide/show some resources.- Parameters:
fs
- the filesystem to scan onres
- the resource name to look for- Returns:
- the file object or null
-
createWritableOn
Finds the system to create writable version of the file on.- Parameters:
name
- name of the file (full)- Returns:
- the first one
- Throws:
IOException
- if the filesystem is readonly
-
createWritableOnForRename
Special case of createWritableOn (@see #createWritableOn).- Parameters:
oldName
- original name of the file (full)newName
- name new of the file (full)- Returns:
- the first one
- Throws:
IOException
- if the filesystem is readonly- Since:
- 1.34
-
createLocksOn
When a file is about to be locked this method is consulted to choose which delegates should be locked. By default this method returns only one filesystem; the same returned by createWritableOn.If an delegate resides on a filesystem returned in the resulting set, it will be locked. All others will remain unlocked.
- Parameters:
name
- the resource name to lock- Returns:
- set of filesystems
- Throws:
IOException
- if the resource cannot be locked
-
notifyMigration
Notification that a file has migrated from one filesystem to another. Usually when somebody writes to file on readonly file system and the file has to be copied to write one.This method allows subclasses to fire for example FileSystem.PROP_STATUS change to notify that annotation of this file should change.
- Parameters:
fo
- file object that change its actual filesystem
-
markUnimportant
Notification that a file has been marked unimportant.- Parameters:
fo
- file object that change its actual filesystem
-
addNotify
public void addNotify()Notifies all encapsulated filesystems in advance to superclass behaviour.- Overrides:
addNotify
in classFileSystem
-
removeNotify
public void removeNotify()Notifies all encapsulated filesystems in advance to superclass behaviour.- Overrides:
removeNotify
in classFileSystem
-