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   * To use the options, pass them to {@link FileSystemManager#resolveFile(String,FileSystemOptions)}. From there, the
32   * options apply to all files that are resolved relative to that file.
33   *
34   * @see org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder
35   * @see org.apache.commons.vfs2.provider.ftp.FtpFileSystemConfigBuilder
36   * @see org.apache.commons.vfs2.provider.ftps.FtpsFileSystemConfigBuilder
37   * @see org.apache.commons.vfs2.provider.hdfs.HdfsFileSystemConfigBuilder
38   * @see org.apache.commons.vfs2.provider.http.HttpFileSystemConfigBuilder
39   * @see org.apache.commons.vfs2.provider.webdav.WebdavFileSystemConfigBuilder
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   *
44   */
45  public final class FileSystemOptions implements Cloneable
46  {
47      /** The options */
48      private final Map<FileSystemOptionKey, Object> options;
49  
50      /**
51       * Creates a new instance.
52       */
53      public FileSystemOptions()
54      {
55          this(new TreeMap<FileSystemOptionKey, Object>());
56      }
57  
58      protected FileSystemOptions(final Map<FileSystemOptionKey, Object> options)
59      {
60          this.options = options;
61      }
62  
63      /**
64       * Keys in the options Map.
65       */
66      private static final class FileSystemOptionKey implements Comparable<FileSystemOptionKey>
67      {
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          {
81              this.fileSystemClass = fileSystemClass;
82              this.name = name;
83          }
84  
85          @Override
86          public int compareTo(final FileSystemOptionKey o)
87          {
88              final int ret = fileSystemClass.getName().compareTo(o.fileSystemClass.getName());
89              if (ret != 0)
90              {
91                  return ret;
92              }
93              return name.compareTo(o.name);
94          }
95  
96          @Override
97          public boolean equals(final Object o)
98          {
99              if (this == o)
100             {
101                 return true;
102             }
103             if (o == null || getClass() != o.getClass())
104             {
105                 return false;
106             }
107 
108             final FileSystemOptionKey that = (FileSystemOptionKey) o;
109 
110             if (!fileSystemClass.equals(that.fileSystemClass))
111             {
112                 return false;
113             }
114             if (!name.equals(that.name))
115             {
116                 return false;
117             }
118 
119             return true;
120         }
121 
122         @Override
123         public int hashCode()
124         {
125             int result;
126             result = fileSystemClass.hashCode();
127             result = HASH * result + name.hashCode();
128             return result;
129         }
130 
131         @Override
132         public String toString()
133         {
134             return fileSystemClass.getName()+"."+name;
135         }
136     }
137 
138     void setOption(final Class<? extends FileSystem> fileSystemClass, final String name, final Object value)
139     {
140         options.put(new FileSystemOptionKey(fileSystemClass, name), value);
141     }
142 
143     Object getOption(final Class<? extends FileSystem> fileSystemClass, final String name)
144     {
145         final FileSystemOptionKey key = new FileSystemOptionKey(fileSystemClass, name);
146         return options.get(key);
147     }
148 
149     boolean hasOption(final Class<? extends FileSystem> fileSystemClass, final String name)
150     {
151         final FileSystemOptionKey key = new FileSystemOptionKey(fileSystemClass, name);
152         return options.containsKey(key);
153     }
154 
155     public int compareTo(final FileSystemOptions other)
156     {
157         if (this == other)
158         {
159             // the same instance
160             return 0;
161         }
162 
163         final int propsSz = options == null ? 0 : options.size();
164         final int propsFkSz = other.options == null ? 0 : other.options.size();
165         if (propsSz < propsFkSz)
166         {
167             return -1;
168         }
169         if (propsSz > propsFkSz)
170         {
171             return 1;
172         }
173         if (propsSz == 0)
174         {
175             // props empty
176             return 0;
177         }
178 
179         // ensure proper sequence of options
180         final SortedMap<FileSystemOptionKey, Object> myOptions =
181               options instanceof SortedMap
182             ? (SortedMap<FileSystemOptionKey, Object>)options
183             : new TreeMap<FileSystemOptionKey, Object>(options);
184         final SortedMap<FileSystemOptionKey, Object> theirOptions =
185               other.options instanceof SortedMap
186             ? (SortedMap<FileSystemOptionKey, Object>)other.options
187             : new TreeMap<FileSystemOptionKey, Object>(other.options);
188         final Iterator<FileSystemOptionKey> optKeysIter = myOptions.keySet().iterator();
189         final Iterator<FileSystemOptionKey> otherKeysIter = theirOptions.keySet().iterator();
190         while(optKeysIter.hasNext()) {
191             int comp = optKeysIter.next().compareTo(otherKeysIter.next());
192             if (comp != 0) {
193                 return comp;
194             }
195         }
196 
197         Object[] array = new Object[propsSz];
198         final int hash = Arrays.deepHashCode(myOptions.values().toArray(array));
199         final int hashFk = Arrays.deepHashCode(theirOptions.values().toArray(array));
200         if (hash < hashFk)
201         {
202             return -1;
203         }
204         if (hash > hashFk)
205         {
206             return 1;
207         }
208 
209         // TODO: compare Entry by Entry ??
210         return 0;
211     }
212 
213     @Override
214     public int hashCode()
215     {
216         final int prime = 31;
217         int result = 1;
218         if (options == null) {
219             result = prime * result;
220         } else {
221             final SortedMap<FileSystemOptionKey, Object> myOptions =
222                 options instanceof SortedMap
223               ? (SortedMap<FileSystemOptionKey, Object>)options
224               : new TreeMap<FileSystemOptionKey, Object>(options);
225             result = prime * result + myOptions.keySet().hashCode();
226             result = prime * result + Arrays.deepHashCode(myOptions.values().toArray(new Object[options.size()]));
227         }
228         return result;
229     }
230 
231     @Override
232     public boolean equals(Object obj)
233     {
234         if (this == obj) {
235             return true;
236         }
237         if (obj == null) {
238             return false;
239         }
240         if (getClass() != obj.getClass()) {
241             return false;
242         }
243         FileSystemOptions other = (FileSystemOptions)obj;
244         return compareTo(other) == 0;
245     }
246 
247 
248     /**
249      * {@inheritDoc}
250      *
251      * @since 2.0
252      */
253     @Override
254     public Object clone()
255     {
256         return new FileSystemOptions(new TreeMap<FileSystemOptionKey, Object>(options));
257     }
258 
259     @Override
260     public String toString()
261     {
262         return options.toString();
263     }
264 }