001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.vfs2; 018 019import java.util.Arrays; 020import java.util.Iterator; 021import java.util.Map; 022import java.util.SortedMap; 023import java.util.TreeMap; 024 025/** 026 * Configures file systems individually with these options. 027 * <p> 028 * To configure a file system, you set properties on a {@link FileSystemOptions} object. Most file systems provide a 029 * {@link FileSystemConfigBuilder} with specific options for that file system. 030 * </p> 031 * <p> 032 * To use the options, pass them to {@link FileSystemManager#resolveFile(String,FileSystemOptions)}. From there, the 033 * options apply to all files that are resolved relative to that file. 034 * </p> 035 * 036 * @see org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder 037 * @see org.apache.commons.vfs2.provider.ftp.FtpFileSystemConfigBuilder 038 * @see org.apache.commons.vfs2.provider.ftps.FtpsFileSystemConfigBuilder 039 * @see org.apache.commons.vfs2.provider.http.HttpFileSystemConfigBuilder 040 * @see org.apache.commons.vfs2.provider.ram.RamFileSystemConfigBuilder 041 * @see org.apache.commons.vfs2.provider.res.ResourceFileSystemConfigBuilder 042 * @see org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder 043 * @see org.apache.commons.vfs2.provider.zip.ZipFileSystemConfigBuilder 044 */ 045public final class FileSystemOptions implements Cloneable, Comparable<FileSystemOptions> { 046 047 /** 048 * Keys in the options Map. 049 */ 050 private static final class FileSystemOptionKey implements Comparable<FileSystemOptionKey> { 051 /** Constant used to create hash code */ 052 private static final int HASH = 29; 053 054 /** The FileSystem class */ 055 private final Class<? extends FileSystem> fileSystemClass; 056 057 /** The option name */ 058 private final String name; 059 060 // TODO: the parameter name suggests that the class should only be a 061 // a FileSystem, however some of the tests pass in DefaultFileSystemConfigBuilder 062 private FileSystemOptionKey(final Class<? extends FileSystem> fileSystemClass, final String name) { 063 this.fileSystemClass = fileSystemClass; 064 this.name = name; 065 } 066 067 @Override 068 public int compareTo(final FileSystemOptionKey o) { 069 final int ret = fileSystemClass.getName().compareTo(o.fileSystemClass.getName()); 070 if (ret != 0) { 071 return ret; 072 } 073 return name.compareTo(o.name); 074 } 075 076 @Override 077 public boolean equals(final Object o) { 078 if (this == o) { 079 return true; 080 } 081 if (o == null || getClass() != o.getClass()) { 082 return false; 083 } 084 085 final FileSystemOptionKey that = (FileSystemOptionKey) o; 086 087 if (!fileSystemClass.equals(that.fileSystemClass)) { 088 return false; 089 } 090 return name.equals(that.name); 091 } 092 093 @Override 094 public int hashCode() { 095 int result; 096 result = fileSystemClass.hashCode(); 097 return HASH * result + name.hashCode(); 098 } 099 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}