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