/* * Copyright 2013 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.common.jimfs; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileAttributeView; import java.util.Arrays; import java.util.Map; import org.checkerframework.checker.nullness.compatqual.NullableDecl; /** * Abstract provider for handling a specific file attribute view. * * @author Colin Decker */ public abstract class AttributeProvider { /** Returns the view name that's used to get attributes from this provider. */ public abstract String name(); /** Returns the names of other providers that this provider inherits attributes from. */ public ImmutableSet inherits() { return ImmutableSet.of(); } /** Returns the type of the view interface that this provider supports. */ public abstract Class viewType(); /** * Returns a view of the file located by the given lookup callback. The given map contains the * views inherited by this view. */ public abstract FileAttributeView view( FileLookup lookup, ImmutableMap inheritedViews); /** * Returns a map containing the default attribute values for this provider. The keys of the map * are attribute identifier strings (in "view:attribute" form) and the value for each is the * default value that should be set for that attribute when creating a new file. * *

The given map should be in the same format and contains user-provided default values. If the * user provided any default values for attributes handled by this provider, those values should * be checked to ensure they are of the correct type. Additionally, if any changes to a * user-provided attribute are necessary (for example, creating an immutable defensive copy), that * should be done. The resulting values should be included in the result map along with default * values for any attributes the user did not provide a value for. */ public ImmutableMap defaultValues(Map userDefaults) { return ImmutableMap.of(); } /** Returns the set of attributes that are always available from this provider. */ public abstract ImmutableSet fixedAttributes(); /** Returns whether or not this provider supports the given attribute directly. */ public boolean supports(String attribute) { return fixedAttributes().contains(attribute); } /** * Returns the set of attributes supported by this view that are present in the given file. For * most providers, this will be a fixed set of attributes. */ public ImmutableSet attributes(File file) { return fixedAttributes(); } /** * Returns the value of the given attribute in the given file or null if the attribute is not * supported by this provider. */ @NullableDecl public abstract Object get(File file, String attribute); /** * Sets the value of the given attribute in the given file object. The {@code create} parameter * indicates whether or not the value is being set upon creation of a new file via a user-provided * {@code FileAttribute}. * * @throws IllegalArgumentException if the given attribute is one supported by this provider but * it is not allowed to be set by the user * @throws UnsupportedOperationException if the given attribute is one supported by this provider * and is allowed to be set by the user, but not on file creation and {@code create} is true */ public abstract void set(File file, String view, String attribute, Object value, boolean create); // optional /** * Returns the type of file attributes object this provider supports, or null if it doesn't * support reading its attributes as an object. */ @NullableDecl public Class attributesType() { return null; } /** * Reads this provider's attributes from the given file as an attributes object. * * @throws UnsupportedOperationException if this provider does not support reading an attributes * object */ public BasicFileAttributes readAttributes(File file) { throw new UnsupportedOperationException(); } // exception helpers /** Throws a runtime exception indicating that the given attribute cannot be set. */ protected static RuntimeException unsettable(String view, String attribute, boolean create) { // This matches the behavior of the real file system implementations: if the attempt to set the // attribute is being made during file creation, throw UOE even though the attribute is one // that cannot be set under any circumstances checkNotCreate(view, attribute, create); throw new IllegalArgumentException("cannot set attribute '" + view + ":" + attribute + "'"); } /** * Checks that the attribute is not being set by the user on file creation, throwing an * unsupported operation exception if it is. */ protected static void checkNotCreate(String view, String attribute, boolean create) { if (create) { throw new UnsupportedOperationException( "cannot set attribute '" + view + ":" + attribute + "' during file creation"); } } /** * Checks that the given value is of the given type, returning the value if so and throwing an * exception if not. */ protected static T checkType(String view, String attribute, Object value, Class type) { checkNotNull(value); if (type.isInstance(value)) { return type.cast(value); } throw invalidType(view, attribute, value, type); } /** * Throws an illegal argument exception indicating that the given value is not one of the expected * types for the given attribute. */ protected static IllegalArgumentException invalidType( String view, String attribute, Object value, Class... expectedTypes) { Object expected = expectedTypes.length == 1 ? expectedTypes[0] : "one of " + Arrays.toString(expectedTypes); throw new IllegalArgumentException( "invalid type " + value.getClass() + " for attribute '" + view + ":" + attribute + "': expected " + expected); } }