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.hdfs.HdfsFileSystemConfigBuilder
40   * @see org.apache.commons.vfs2.provider.http.HttpFileSystemConfigBuilder
41   * @see org.apache.commons.vfs2.provider.webdav.WebdavFileSystemConfigBuilder
42   * @see org.apache.commons.vfs2.provider.ram.RamFileSystemConfigBuilder
43   * @see org.apache.commons.vfs2.provider.res.ResourceFileSystemConfigBuilder
44   * @see org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder
45   * @see org.apache.commons.vfs2.provider.zip.ZipFileSystemConfigBuilder
46   *
47   */
48  public final class FileSystemOptions implements Cloneable {
49  
50      /** The options */
51      private final Map<FileSystemOptionKey, Object> options;
52  
53      /**
54       * Creates a new instance.
55       */
56      public FileSystemOptions() {
57          this(new TreeMap<FileSystemOptionKey, Object>());
58      }
59  
60      protected FileSystemOptions(final Map<FileSystemOptionKey, Object> options) {
61          this.options = options;
62      }
63  
64      /**
65       * Keys in the options Map.
66       */
67      private static final class FileSystemOptionKey implements Comparable<FileSystemOptionKey> {
68          /** Constant used to create hashcode */
69          private static final int HASH = 29;
70  
71          /** The FileSystem class */
72          private final Class<? extends FileSystem> fileSystemClass;
73  
74          /** The option name */
75          private final String name;
76  
77          // TODO: the parameter name suggests that the class should only be a
78          // a FileSystem, however some of the tests pass in DefaultFileSystemConfigBuilder
79          private FileSystemOptionKey(final Class<? extends FileSystem> fileSystemClass, final String name) {
80              this.fileSystemClass = fileSystemClass;
81              this.name = name;
82          }
83  
84          @Override
85          public int compareTo(final FileSystemOptionKey o) {
86              final int ret = fileSystemClass.getName().compareTo(o.fileSystemClass.getName());
87              if (ret != 0) {
88                  return ret;
89              }
90              return name.compareTo(o.name);
91          }
92  
93          @Override
94          public boolean equals(final Object o) {
95              if (this == o) {
96                  return true;
97              }
98              if (o == null || getClass() != o.getClass()) {
99                  return false;
100             }
101 
102             final FileSystemOptionKey that = (FileSystemOptionKey) o;
103 
104             if (!fileSystemClass.equals(that.fileSystemClass)) {
105                 return false;
106             }
107             if (!name.equals(that.name)) {
108                 return false;
109             }
110 
111             return true;
112         }
113 
114         @Override
115         public int hashCode() {
116             int result;
117             result = fileSystemClass.hashCode();
118             result = HASH * result + name.hashCode();
119             return result;
120         }
121 
122         @Override
123         public String toString() {
124             return fileSystemClass.getName() + "." + name;
125         }
126     }
127 
128     void setOption(final Class<? extends FileSystem> fileSystemClass, final String name, final Object value) {
129         options.put(new FileSystemOptionKey(fileSystemClass, name), value);
130     }
131 
132     Object getOption(final Class<? extends FileSystem> fileSystemClass, final String name) {
133         final FileSystemOptionKey key = new FileSystemOptionKey(fileSystemClass, name);
134         return options.get(key);
135     }
136 
137     boolean hasOption(final Class<? extends FileSystem> fileSystemClass, final String name) {
138         final FileSystemOptionKey key = new FileSystemOptionKey(fileSystemClass, name);
139         return options.containsKey(key);
140     }
141 
142     public int compareTo(final FileSystemOptions other) {
143         if (this == other) {
144             // the same instance
145             return 0;
146         }
147 
148         final int propsSz = options == null ? 0 : options.size();
149         final int propsFkSz = other.options == null ? 0 : other.options.size();
150         if (propsSz < propsFkSz) {
151             return -1;
152         }
153         if (propsSz > propsFkSz) {
154             return 1;
155         }
156         if (propsSz == 0) {
157             // props empty
158             return 0;
159         }
160 
161         // ensure proper sequence of options
162         final SortedMap<FileSystemOptionKey, Object> myOptions = options instanceof SortedMap
163                 ? (SortedMap<FileSystemOptionKey, Object>) options
164                 : new TreeMap<>(options);
165         final SortedMap<FileSystemOptionKey, Object> theirOptions = other.options instanceof SortedMap
166                 ? (SortedMap<FileSystemOptionKey, Object>) other.options
167                 : new TreeMap<>(other.options);
168         final Iterator<FileSystemOptionKey> optKeysIter = myOptions.keySet().iterator();
169         final Iterator<FileSystemOptionKey> otherKeysIter = theirOptions.keySet().iterator();
170         while (optKeysIter.hasNext()) {
171             final int comp = optKeysIter.next().compareTo(otherKeysIter.next());
172             if (comp != 0) {
173                 return comp;
174             }
175         }
176 
177         final Object[] array = new Object[propsSz];
178         final int hash = Arrays.deepHashCode(myOptions.values().toArray(array));
179         final int hashFk = Arrays.deepHashCode(theirOptions.values().toArray(array));
180         if (hash < hashFk) {
181             return -1;
182         }
183         if (hash > hashFk) {
184             return 1;
185         }
186 
187         // TODO: compare Entry by Entry ??
188         return 0;
189     }
190 
191     @Override
192     public int hashCode() {
193         final int prime = 31;
194         int result = 1;
195         if (options == null) {
196             result = prime * result;
197         } else {
198             final SortedMap<FileSystemOptionKey, Object> myOptions = options instanceof SortedMap
199                     ? (SortedMap<FileSystemOptionKey, Object>) options
200                     : new TreeMap<>(options);
201             result = prime * result + myOptions.keySet().hashCode();
202             result = prime * result + Arrays.deepHashCode(myOptions.values().toArray(new Object[options.size()]));
203         }
204         return result;
205     }
206 
207     @Override
208     public boolean equals(final Object obj) {
209         if (this == obj) {
210             return true;
211         }
212         if (obj == null) {
213             return false;
214         }
215         if (getClass() != obj.getClass()) {
216             return false;
217         }
218         final FileSystemOptions./org/apache/commons/vfs2/FileSystemOptions.html#FileSystemOptions">FileSystemOptions other = (FileSystemOptions) obj;
219         return compareTo(other) == 0;
220     }
221 
222     /**
223      * {@inheritDoc}
224      *
225      * @since 2.0
226      */
227     @Override
228     public Object clone() {
229         return new FileSystemOptions(new TreeMap<>(options));
230     }
231 
232     @Override
233     public String toString() {
234         return options.toString();
235     }
236 }