1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.jimfs; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.collect.ImmutableMap; 22 import com.google.common.collect.ImmutableSet; 23 import java.nio.file.attribute.BasicFileAttributes; 24 import java.nio.file.attribute.FileAttributeView; 25 import java.util.Arrays; 26 import java.util.Map; 27 import org.checkerframework.checker.nullness.compatqual.NullableDecl; 28 29 /** 30 * Abstract provider for handling a specific file attribute view. 31 * 32 * @author Colin Decker 33 */ 34 public abstract class AttributeProvider { 35 36 /** Returns the view name that's used to get attributes from this provider. */ name()37 public abstract String name(); 38 39 /** Returns the names of other providers that this provider inherits attributes from. */ inherits()40 public ImmutableSet<String> inherits() { 41 return ImmutableSet.of(); 42 } 43 44 /** Returns the type of the view interface that this provider supports. */ viewType()45 public abstract Class<? extends FileAttributeView> viewType(); 46 47 /** 48 * Returns a view of the file located by the given lookup callback. The given map contains the 49 * views inherited by this view. 50 */ view( FileLookup lookup, ImmutableMap<String, FileAttributeView> inheritedViews)51 public abstract FileAttributeView view( 52 FileLookup lookup, ImmutableMap<String, FileAttributeView> inheritedViews); 53 54 /** 55 * Returns a map containing the default attribute values for this provider. The keys of the map 56 * are attribute identifier strings (in "view:attribute" form) and the value for each is the 57 * default value that should be set for that attribute when creating a new file. 58 * 59 * <p>The given map should be in the same format and contains user-provided default values. If the 60 * user provided any default values for attributes handled by this provider, those values should 61 * be checked to ensure they are of the correct type. Additionally, if any changes to a 62 * user-provided attribute are necessary (for example, creating an immutable defensive copy), that 63 * should be done. The resulting values should be included in the result map along with default 64 * values for any attributes the user did not provide a value for. 65 */ defaultValues(Map<String, ?> userDefaults)66 public ImmutableMap<String, ?> defaultValues(Map<String, ?> userDefaults) { 67 return ImmutableMap.of(); 68 } 69 70 /** Returns the set of attributes that are always available from this provider. */ fixedAttributes()71 public abstract ImmutableSet<String> fixedAttributes(); 72 73 /** Returns whether or not this provider supports the given attribute directly. */ supports(String attribute)74 public boolean supports(String attribute) { 75 return fixedAttributes().contains(attribute); 76 } 77 78 /** 79 * Returns the set of attributes supported by this view that are present in the given file. For 80 * most providers, this will be a fixed set of attributes. 81 */ attributes(File file)82 public ImmutableSet<String> attributes(File file) { 83 return fixedAttributes(); 84 } 85 86 /** 87 * Returns the value of the given attribute in the given file or null if the attribute is not 88 * supported by this provider. 89 */ 90 @NullableDecl get(File file, String attribute)91 public abstract Object get(File file, String attribute); 92 93 /** 94 * Sets the value of the given attribute in the given file object. The {@code create} parameter 95 * indicates whether or not the value is being set upon creation of a new file via a user-provided 96 * {@code FileAttribute}. 97 * 98 * @throws IllegalArgumentException if the given attribute is one supported by this provider but 99 * it is not allowed to be set by the user 100 * @throws UnsupportedOperationException if the given attribute is one supported by this provider 101 * and is allowed to be set by the user, but not on file creation and {@code create} is true 102 */ set(File file, String view, String attribute, Object value, boolean create)103 public abstract void set(File file, String view, String attribute, Object value, boolean create); 104 105 // optional 106 107 /** 108 * Returns the type of file attributes object this provider supports, or null if it doesn't 109 * support reading its attributes as an object. 110 */ 111 @NullableDecl attributesType()112 public Class<? extends BasicFileAttributes> attributesType() { 113 return null; 114 } 115 116 /** 117 * Reads this provider's attributes from the given file as an attributes object. 118 * 119 * @throws UnsupportedOperationException if this provider does not support reading an attributes 120 * object 121 */ readAttributes(File file)122 public BasicFileAttributes readAttributes(File file) { 123 throw new UnsupportedOperationException(); 124 } 125 126 // exception helpers 127 128 /** Throws a runtime exception indicating that the given attribute cannot be set. */ unsettable(String view, String attribute, boolean create)129 protected static RuntimeException unsettable(String view, String attribute, boolean create) { 130 // This matches the behavior of the real file system implementations: if the attempt to set the 131 // attribute is being made during file creation, throw UOE even though the attribute is one 132 // that cannot be set under any circumstances 133 checkNotCreate(view, attribute, create); 134 throw new IllegalArgumentException("cannot set attribute '" + view + ":" + attribute + "'"); 135 } 136 137 /** 138 * Checks that the attribute is not being set by the user on file creation, throwing an 139 * unsupported operation exception if it is. 140 */ checkNotCreate(String view, String attribute, boolean create)141 protected static void checkNotCreate(String view, String attribute, boolean create) { 142 if (create) { 143 throw new UnsupportedOperationException( 144 "cannot set attribute '" + view + ":" + attribute + "' during file creation"); 145 } 146 } 147 148 /** 149 * Checks that the given value is of the given type, returning the value if so and throwing an 150 * exception if not. 151 */ checkType(String view, String attribute, Object value, Class<T> type)152 protected static <T> T checkType(String view, String attribute, Object value, Class<T> type) { 153 checkNotNull(value); 154 if (type.isInstance(value)) { 155 return type.cast(value); 156 } 157 158 throw invalidType(view, attribute, value, type); 159 } 160 161 /** 162 * Throws an illegal argument exception indicating that the given value is not one of the expected 163 * types for the given attribute. 164 */ invalidType( String view, String attribute, Object value, Class<?>... expectedTypes)165 protected static IllegalArgumentException invalidType( 166 String view, String attribute, Object value, Class<?>... expectedTypes) { 167 Object expected = 168 expectedTypes.length == 1 ? expectedTypes[0] : "one of " + Arrays.toString(expectedTypes); 169 throw new IllegalArgumentException( 170 "invalid type " 171 + value.getClass() 172 + " for attribute '" 173 + view 174 + ":" 175 + attribute 176 + "': expected " 177 + expected); 178 } 179 } 180