View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs2;
18  
19  import java.util.Arrays;
20  import java.util.Iterator;
21  import java.util.Map;
22  import java.util.SortedMap;
23  import java.util.TreeMap;
24  
25  /**
26   * Configures file systems individually with these options.
27   * <p>
28   * To configure a file system, you set properties on a {@link FileSystemOptions} object. Most file systems provide a
29   * {@link FileSystemConfigBuilder} with specific options for that file system.
30   * </p>
31   * <p>
32   * To use the options, pass them to {@link FileSystemManager#resolveFile(String,FileSystemOptions)}. From there, the
33   * options apply to all files that are resolved relative to that file.
34   * </p>
35   *
36   * @see org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder
37   * @see org.apache.commons.vfs2.provider.ftp.FtpFileSystemConfigBuilder
38   * @see org.apache.commons.vfs2.provider.ftps.FtpsFileSystemConfigBuilder
39   * @see org.apache.commons.vfs2.provider.http.HttpFileSystemConfigBuilder
40   * @see org.apache.commons.vfs2.provider.ram.RamFileSystemConfigBuilder
41   * @see org.apache.commons.vfs2.provider.res.ResourceFileSystemConfigBuilder
42   * @see org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder
43   * @see org.apache.commons.vfs2.provider.zip.ZipFileSystemConfigBuilder
44   */
45  public final class FileSystemOptions implements Cloneable, Comparable<FileSystemOptions> {
46  
47      /**
48       * Keys in the options Map.
49       */
50      private static final class FileSystemOptionKey implements Comparable<FileSystemOptionKey> {
51          /** Constant used to create hash code */
52          private static final int HASH = 29;
53  
54          /** The FileSystem class */
55          private final Class<? extends FileSystem> fileSystemClass;
56  
57          /** The option name */
58          private final String name;
59  
60          // TODO: the parameter name suggests that the class should only be a
61          // a FileSystem, however some of the tests pass in DefaultFileSystemConfigBuilder
62          private FileSystemOptionKey(final Class<? extends FileSystem> fileSystemClass, final String name) {
63              this.fileSystemClass = fileSystemClass;
64              this.name = name;
65          }
66  
67          @Override
68          public int compareTo(final FileSystemOptionKey o) {
69              final int ret = fileSystemClass.getName().compareTo(o.fileSystemClass.getName());
70              if (ret != 0) {
71                  return ret;
72              }
73              return name.compareTo(o.name);
74          }
75  
76          @Override
77          public boolean equals(final Object o) {
78              if (this == o) {
79                  return true;
80              }
81              if (o == null || getClass() != o.getClass()) {
82                  return false;
83              }
84  
85              final FileSystemOptionKey that = (FileSystemOptionKey) o;
86  
87              if (!fileSystemClass.equals(that.fileSystemClass)) {
88                  return false;
89              }
90              return name.equals(that.name);
91          }
92  
93          @Override
94          public int hashCode() {
95              int result;
96              result = fileSystemClass.hashCode();
97              return HASH * result + name.hashCode();
98          }
99  
100         @Override
101         public String toString() {
102             return fileSystemClass.getName() + "." + name;
103         }
104     }
105 
106     /** The options */
107     private final Map<FileSystemOptionKey, Object> options;
108 
109     /**
110      * Constructs a new instance.
111      */
112     public FileSystemOptions() {
113         this(new TreeMap<>());
114     }
115 
116     /**
117      * Constructs a new instance with the given options.
118      *
119      * @param options the options.
120      * @since 2.10.0
121      */
122     public FileSystemOptions(final Map<FileSystemOptionKey, Object> options) {
123         this.options = options;
124     }
125 
126     /**
127      * {@inheritDoc}
128      *
129      * @since 2.0
130      */
131     @Override
132     public Object clone() {
133         return new FileSystemOptions(new TreeMap<>(options));
134     }
135 
136     @Override
137     public int compareTo(final FileSystemOptions other) {
138         if (this == other) {
139             // the same instance
140             return 0;
141         }
142 
143         final int propsSz = options == null ? 0 : options.size();
144         final int propsFkSz = other.options == null ? 0 : other.options.size();
145         if (propsSz < propsFkSz) {
146             return -1;
147         }
148         if (propsSz > propsFkSz) {
149             return 1;
150         }
151         if (propsSz == 0) {
152             // props empty
153             return 0;
154         }
155 
156         // ensure proper sequence of options
157         final SortedMap<FileSystemOptionKey, Object> myOptions = options instanceof SortedMap
158                 ? (SortedMap<FileSystemOptionKey, Object>) options
159                 : new TreeMap<>(options);
160         final SortedMap<FileSystemOptionKey, Object> theirOptions = other.options instanceof SortedMap
161                 ? (SortedMap<FileSystemOptionKey, Object>) other.options
162                 : new TreeMap<>(other.options);
163         final Iterator<FileSystemOptionKey> optKeysIter = myOptions.keySet().iterator();
164         final Iterator<FileSystemOptionKey> otherKeysIter = theirOptions.keySet().iterator();
165         while (optKeysIter.hasNext()) {
166             final int comp = optKeysIter.next().compareTo(otherKeysIter.next());
167             if (comp != 0) {
168                 return comp;
169             }
170         }
171 
172         final int hash = Arrays.deepHashCode(myOptions.values().toArray());
173         final int hashFk = Arrays.deepHashCode(theirOptions.values().toArray());
174         return Integer.compare(hash, hashFk);
175 
176         // TODO: compare Entry by Entry ??
177     }
178 
179     @Override
180     public boolean equals(final Object obj) {
181         if (this == obj) {
182             return true;
183         }
184         if (obj == null) {
185             return false;
186         }
187         if (getClass() != obj.getClass()) {
188             return false;
189         }
190         final FileSystemOptions other = (FileSystemOptions) obj;
191         return compareTo(other) == 0;
192     }
193 
194     <T> T getOption(final Class<? extends FileSystem> fileSystemClass, final String name) {
195         return getOptionOrDefault(fileSystemClass, name, null);
196     }
197 
198     <T> T getOptionOrDefault(final Class<? extends FileSystem> fileSystemClass, final String name, final T defaultValue) {
199         final T value = (T) options.getOrDefault(new FileSystemOptionKey(fileSystemClass, name), defaultValue);
200         return value != null ? value : defaultValue;
201     }
202 
203     @Override
204     public int hashCode() {
205         final int prime = 31;
206         int result = 1;
207         if (options == null) {
208             result = prime * result;
209         } else {
210             final SortedMap<FileSystemOptionKey, Object> myOptions = options instanceof SortedMap
211                     ? (SortedMap<FileSystemOptionKey, Object>) options
212                     : new TreeMap<>(options);
213             result = prime * result + myOptions.keySet().hashCode();
214             result = prime * result + Arrays.deepHashCode(myOptions.values().toArray());
215         }
216         return result;
217     }
218 
219     boolean hasOption(final Class<? extends FileSystem> fileSystemClass, final String name) {
220         return options.containsKey(new FileSystemOptionKey(fileSystemClass, name));
221     }
222 
223     void setOption(final Class<? extends FileSystem> fileSystemClass, final String name, final Object value) {
224         options.put(new FileSystemOptionKey(fileSystemClass, name), value);
225     }
226 
227     int size() {
228         return options.size();
229     }
230 
231      @Override
232     public String toString() {
233         return options.toString();
234     }
235 }