View Javadoc
1   /*
2    * Copyright (C) 2005-2015 Schlichtherle IT Services.
3    * All rights reserved. Use is subject to license terms.
4    */
5   package net.java.truevfs.kernel.spec;
6   
7   import java.io.IOException;
8   import java.lang.annotation.Inherited;
9   import java.util.Map;
10  import javax.annotation.CheckForNull;
11  import javax.annotation.Nullable;
12  import net.java.truecommons.cio.Entry;
13  import net.java.truecommons.cio.Entry.Access;
14  import net.java.truecommons.cio.Entry.Type;
15  import net.java.truecommons.cio.InputSocket;
16  import net.java.truecommons.cio.OutputSocket;
17  import net.java.truecommons.shed.BitField;
18  import net.java.truecommons.shed.ImplementationsShouldExtend;
19  import static net.java.truevfs.kernel.spec.FsAssertion.Level.*;
20  
21  /**
22   * Provides read/write access to a file system.
23   *
24   * <h3>General Properties</h3>
25   * <p>
26   * The {@link FsModel#getMountPoint() mount point} of the
27   * {@linkplain #getModel() file system model}
28   * addresses the file system accessed by this controller.
29   * Where the methods of this abstract class accept a
30   * {@link FsNodeName file system node name} as a parameter, this MUST get
31   * resolved against the {@link FsModel#getMountPoint() mount point} URI of this
32   * controller's file system model.
33    * <p>
34   * As of TrueVFS 0.10, application level transactions are not supported,
35   * that is, multiple file system operations cannot get composed into a single
36   * application level transaction - support for this feature may be added in a
37   * future version.
38   * <p>
39   * However, individual file system operations do come with assertions about
40   * their atomicity, consistency, isolation and durability.
41   * Each method of this interface which is expected to access the file system
42   * (rather than just memory) is annotated with an {@link FsAssertion}.
43   * The annotation is {@link Inherited}, so the assertion forms part of the
44   * contract which any implementation of this interface should comply to.
45   * <p>
46   * Note that file system controllers are generally allowed to buffer any
47   * changes made to their file system.
48   * This is generally true for file system controllers which operate on archive
49   * files.
50   * This means that all changes made to the file system via this interface may
51   * not be entirely durable until they get committed by calling {@link #sync}.
52   * The annotations account for this stipulation by leaving the
53   * {@link FsAssertion#durable() durability} property undefined.
54   * <p>
55   * An implementation which wants to buffer its changes until {@code sync} gets
56   * called needs to notify the {@linkplain FsManager file system manager} by
57   * calling {@link FsModel#setMounted setMounted(true)} on the controller's
58   * file system model before the first change is commenced.
59   * Likewise, when {@code sync} gets called, the controller needs to notify the
60   * file system manager by calling {@code setMounted(false)} on the controller's
61   * file system model if and only if the {@code sync} has been successfully
62   * completed.
63   * This protocol enables proper management of the controller's life cycle.
64   * <p>
65   * Implementations should be safe for multi-threaded access.
66   *
67   * @see    FsManager
68   * @see    FsModel
69   * @see    <a href="http://www.ietf.org/rfc/rfc2119.txt">RFC 2119: Key words for use in RFCs to Indicate Requirement Levels</a>
70   * @author Christian Schlichtherle
71   */
72  @ImplementationsShouldExtend(FsAbstractController.class)
73  public interface FsController {
74  
75      /**
76       * Returns the controller for the parent file system or {@code null} if
77       * and only if this file system is not federated, i.e. not a member of
78       * another file system.
79       * Multiple invocations must return the same object.
80       *
81       * @return The nullable controller for the parent file system.
82       */
83      @Nullable FsController getParent();
84  
85      /**
86       * Returns the file system model.
87       *
88       * @return The file system model.
89       */
90      FsModel getModel();
91  
92      /**
93       * Returns the file system node for the given {@code name} or {@code null}
94       * if it doesn't exist.
95       * Modifying the returned node does not show any effect on the file system
96       * and should result in an {@link UnsupportedOperationException}.
97       *
98       * @param  options the options for accessing the file system node.
99       * @param  name the name of the file system node.
100      * @return A file system node or {@code null} if no file system node
101      *         exists for the given name.
102      * @throws IOException on any I/O error.
103      */
104     @FsAssertion(atomic=YES, consistent=YES, isolated=YES, durable=NOT_APPLICABLE)
105     @CheckForNull FsNode node(
106             BitField<FsAccessOption> options,
107             FsNodeName name)
108     throws IOException;
109 
110     /**
111      * Checks if the file system node for the given {@code name} exists when
112      * constrained by the given access {@code options} and permits the given
113      * access {@code types}.
114      *
115      * @param  options the options for accessing the file system node.
116      * @param  name the name of the file system node.
117      * @param  types the types of the desired access.
118      * @throws IOException on any I/O error.
119      */
120     @FsAssertion(atomic=YES, consistent=YES, isolated=YES, durable=NOT_APPLICABLE)
121     void checkAccess(
122             BitField<FsAccessOption> options,
123             FsNodeName name,
124             BitField<Access> types)
125     throws IOException;
126 
127     /**
128      * Sets the named file system node as read-only.
129      * This method will fail for typical archive file system controller
130      * implementations because they do not support it.
131      *
132      * @param  options the options for accessing the file system node.
133      * @param  name the name of the file system node.
134      * @throws IOException on any I/O error or if this operation is not
135      *         supported.
136      */
137     @FsAssertion(atomic=YES, consistent=YES, isolated=YES)
138     void setReadOnly(BitField<FsAccessOption> options, FsNodeName name)
139     throws IOException;
140 
141     /**
142      * Makes an attempt to set the last access time of all types in the given
143      * map for the file system node with the given name.
144      * If {@code false} is returned or an {@link IOException} is thrown, then
145      * still some of the last access times may have been set.
146      * Whether or not this is an atomic operation is specific to the
147      * implementation.
148      *
149      * @param  options the options for accessing the file system node.
150      * @param  name the name of the file system node.
151      * @param  times the access times.
152      * @return {@code true} if and only if setting the access time for all
153      *         types in {@code times} succeeded.
154      * @throws IOException on any I/O error.
155      * @throws NullPointerException if any key or value in the map is
156      *         {@code null}.
157      */
158     @FsAssertion(atomic=NO, consistent=YES, isolated=YES)
159     boolean setTime(
160             BitField<FsAccessOption> options,
161             FsNodeName name,
162             Map<Access, Long> times)
163     throws IOException;
164 
165     /**
166      * Makes an attempt to set the last access time of all types in the given
167      * bit field for the file system node with the given name.
168      * If {@code false} is returned or an {@link IOException} is thrown, then
169      * still some of the last access times may have been set.
170      *
171      * @param  options the options for accessing the file system node.
172      * @param  name the name of the file system node.
173      * @param  types the access types.
174      * @param  value the last access time.
175      * @return {@code true} if and only if setting the access time for all
176      *         types in {@code types} succeeded.
177      * @throws IOException on any I/O error.
178      */
179     @FsAssertion(atomic=NO, consistent=YES, isolated=YES)
180     boolean setTime(
181             BitField<FsAccessOption> options,
182             FsNodeName name,
183             BitField<Access> types,
184             long value)
185     throws IOException;
186 
187     /**
188      * Returns an input socket for reading the contents of the file system
189      * node addressed by the given name from the file system.
190      * Note that the assertions for this file system operation equally apply to
191      * any channel or stream created by the returned input socket!
192      *
193      * @param  options the options for accessing the file system node.
194      * @param  name the name of the file system node.
195      * @return An {@code InputSocket}.
196      */
197     @FsAssertion(atomic=YES, consistent=YES, isolated=YES, durable=NOT_APPLICABLE)
198     InputSocket<? extends Entry> input(
199             BitField<FsAccessOption> options,
200             FsNodeName name);
201 
202     /**
203      * Returns an output socket for writing the contents of the node addressed
204      * by the given name to the file system.
205      * Note that the assertions for this file system operation equally apply to
206      * any channel or stream created by the returned output socket!
207      *
208      * @param  options the options for accessing the file system node.
209      *         If {@link FsAccessOption#CREATE_PARENTS} is set, any missing
210      *         parent directories shall get created with an undefined last
211      *         modification time.
212      * @param  name the name of the file system node.
213      * @param  template if not {@code null}, then the file system node
214      *         at the end of the chain shall inherit as much properties from
215      *         this node as possible - with the exception of its name and type.
216      * @return An {@code OutputSocket}.
217      */
218     @FsAssertion(atomic=YES, consistent=YES, isolated=YES)
219     OutputSocket<? extends Entry> output(
220             BitField<FsAccessOption> options,
221             FsNodeName name,
222             @CheckForNull Entry template);
223 
224     /**
225      * Creates or replaces and finally links a chain of one or more entries
226      * for the given node {@code name} into the file system.
227      *
228      * @param  options the options for accessing the file system node.
229      *         If {@link FsAccessOption#CREATE_PARENTS} is set, any missing
230      *         parent directories shall get created with an undefined last
231      *         modification time.
232      * @param  name the name of the file system node.
233      * @param  type the file system node type.
234      * @param  template if not {@code null}, then the file system node
235      *         at the end of the chain shall inherit as much properties from
236      *         this node as possible - with the exception of its name and type.
237      * @throws IOException on any I/O error, including but not limited to
238      *         these reasons:
239      *         <ul>
240      *         <li>The file system is read only.
241      *         <li>{@code name} contains characters which are not
242      *             supported by the file system.
243      *         <li>The node already exists and either the option
244      *             {@link FsAccessOption#EXCLUSIVE} is set or the node is a
245      *             directory.
246      *         <li>The node exists as a different type.
247      *         <li>A parent node exists but is not a directory.
248      *         <li>A parent node is missing and {@code createParents} is
249      *             {@code false}.
250      *         </ul>
251      */
252     @FsAssertion(atomic=YES, consistent=YES, isolated=YES)
253     void make(
254             BitField<FsAccessOption> options,
255             FsNodeName name,
256             Type type,
257             @CheckForNull Entry template)
258     throws IOException;
259 
260     /**
261      * Removes the named file system node from the file system.
262      * If the named file system node is a directory, it must be empty.
263      *
264      * @param  options the options for accessing the file system node.
265      * @param  name the name of the file system node.
266      * @throws IOException on any I/O error.
267      */
268     @FsAssertion(atomic=YES, consistent=YES, isolated=YES)
269     void unlink(BitField<FsAccessOption> options, FsNodeName name)
270     throws IOException;
271 
272     /**
273      * Commits all unsynchronized changes to the contents of this file system
274      * to its parent file system,
275      * releases the associated resources (e.g. target archive files) for
276      * access by third parties (e.g. other processes), cleans up any temporary
277      * allocated resources (e.g. temporary files) and purges any cached data.
278      * Note that temporary resources may get allocated even if the federated
279      * file systems were accessed read-only.
280      * If this is not a federated file system, i.e. if its not a member of a
281      * parent file system, then nothing happens.
282      * Otherwise, the state of this file system controller is reset.
283      * <p>
284      * An implementation may ignore calls to this method if its stateless.
285      *
286      * @param  options the options for synchronizing the file system.
287      * @throws FsSyncWarningException if <em>only</em> warning conditions
288      *         apply.
289      *         This implies that the respective parent file system has been
290      *         synchronized with constraints, e.g. if an unclosed archive entry
291      *         stream gets forcibly closed.
292      * @throws FsSyncException if any error conditions apply.
293      */
294     @FsAssertion(atomic=NO, consistent=YES, isolated=YES)
295     void sync(BitField<FsSyncOption> options) throws FsSyncException;
296 
297     /**
298      * A factory for {@linkplain FsController file system controllers}.
299      * <p>
300      * Implementations should be safe for multi-threaded access.
301      *
302      * @param  <Context> The type of the calling context.
303      * @since  TrueVFS 0.11
304      * @author Christian Schlichtherle
305      */
306     interface Factory<Context> {
307 
308         /**
309          * Returns a new file system controller for the mount point of the
310          * given file system model.
311          * This is a pure function without side effects.
312          * <p>
313          * When called, you may assert the following precondition:
314          * <pre>{@code
315          * assert null == parent
316          *         ? null == model.getParent()
317          *         : parent.getModel().equals(model.getParent())
318          * }</pre>
319          *
320          * @param  context the calling context.
321          * @param  model the file system model.
322          * @param  parent the nullable parent file system controller.
323          * @return A new file system controller for the mount point of the
324          *         given file system model.
325          */
326         FsController newController(
327                 Context context,
328                 FsModel model,
329                 @CheckForNull FsController parent);
330     }
331 }