com.google.cloud.hadoop.gcsio.FileInfo.java Source code

Java tutorial

Introduction

Here is the source code for com.google.cloud.hadoop.gcsio.FileInfo.java

Source

/**
 * Copyright 2013 Google Inc. All Rights Reserved.
 * 
 * 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.cloud.hadoop.gcsio;

import com.google.api.client.util.Clock;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.primitives.Longs;
import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Contains information about a file or a directory.
 *
 * Note:
 * This class wraps GoogleCloudStorageItemInfo, adds file system specific information and hides
 * bucket/object specific information. The wrapped type should not be visible to callers of
 * GoogleCloudStorageFileSystem because it exposes non-file system information (eg, buckets).
 */
public class FileInfo {

    private static final Logger LOG = LoggerFactory.getLogger(FileInfo.class);

    // Info about the root path.
    public static final FileInfo ROOT_INFO = new FileInfo(GoogleCloudStorageFileSystem.GCS_ROOT,
            GoogleCloudStorageItemInfo.ROOT_INFO);

    // The metadata key used for storing a custom modification time.
    // The name and value of this attribute count towards storage pricing.
    public static final String FILE_MODIFICATION_TIMESTAMP_KEY = "system.gcsfs_mts";

    // Path of this file or directory.
    private final URI path;

    // Information about the underlying GCS item.
    private final GoogleCloudStorageItemInfo itemInfo;

    // Custom file attributes, including those used for storing custom modification times, etc
    private final Map<String, byte[]> attributes;

    /**
     * Constructs an instance of FileInfo.
     *
     * @param itemInfo Information about the underlying item.
     */
    private FileInfo(URI path, GoogleCloudStorageItemInfo itemInfo) {
        this.itemInfo = itemInfo;

        // Construct the path once.
        this.path = path;
        Preconditions.checkArgument(itemInfo.getMetadata() != null);

        this.attributes = itemInfo.getMetadata();
    }

    /**
     * Gets the path of this file or directory.
     */
    public URI getPath() {
        return path;
    }

    /**
     * Indicates whether this item is a directory.
     */
    public boolean isDirectory() {
        return isDirectory(itemInfo);
    }

    /**
     * Indicates whether {@code itemInfo} is a directory; static version of {@link #isDirectory()}
     * to avoid having to create a FileInfo object just to use this logic.
     */
    static boolean isDirectory(GoogleCloudStorageItemInfo itemInfo) {
        return isGlobalRoot(itemInfo) || itemInfo.isBucket() || objectHasDirectoryPath(itemInfo.getObjectName());
    }

    /**
     * Indicates whether this instance has information about the unique, shared root of the
     * underlying storage system.
     */
    public boolean isGlobalRoot() {
        return isGlobalRoot(itemInfo);
    }

    /**
     * Static version of {@link #isGlobalRoot()} to allow sharing this logic without creating
     * unnecessary FileInfo instances.
     */
    static boolean isGlobalRoot(GoogleCloudStorageItemInfo itemInfo) {
        return itemInfo.isRoot() && itemInfo.exists();
    }

    /**
     * Gets creation time of this item.
     *
     * Time is expressed as milliseconds since January 1, 1970 UTC.
     */
    public long getCreationTime() {
        return itemInfo.getCreationTime();
    }

    /**
     * Gets the size of this file or directory.
     *
     * For files, size is in number of bytes.
     * For directories size is 0.
     * For items that do not exist, size is -1.
     */
    public long getSize() {
        return itemInfo.getSize();
    }

    /**
     * Gets the modification time of this file if one is set, otherwise the value of
     * {@link #getCreationTime()} is returned.
     *
     * Time is expressed as milliseconds since January 1, 1970 UTC.
     */
    public long getModificationTime() {
        if (attributes.containsKey(FILE_MODIFICATION_TIMESTAMP_KEY)
                && attributes.get(FILE_MODIFICATION_TIMESTAMP_KEY) != null) {
            try {
                return Longs.fromByteArray(attributes.get(FILE_MODIFICATION_TIMESTAMP_KEY));
            } catch (IllegalArgumentException iae) {
                LOG.debug("Failed to parse modification time '{}' millis for object {}",
                        attributes.get(FILE_MODIFICATION_TIMESTAMP_KEY), itemInfo.getObjectName());
            }
        }
        return getCreationTime();
    }

    /**
     * Retrieve file attributes for this file.
     * @return A map of file attributes
     */
    public Map<String, byte[]> getAttributes() {
        return attributes;
    }

    /**
     * Indicates whether this file or directory exists.
     */
    public boolean exists() {
        return itemInfo.exists();
    }

    /**
     * Gets string representation of this instance.
     */
    public String toString() {
        if (exists()) {
            return String.format("%s: created on: %s", getPath(), (new Date(getCreationTime())).toString());
        } else {
            return String.format("%s: exists: no", getPath());
        }
    }

    /**
     * Gets information about the underlying item.
     */
    public GoogleCloudStorageItemInfo getItemInfo() {
        return itemInfo;
    }

    /**
     * Indicates whether the given object name looks like a directory path.
     *
     * @param objectName Name of the object to inspect.
     * @return Whether the given object name looks like a directory path.
     */
    static boolean objectHasDirectoryPath(String objectName) {
        return StorageResourceId.objectHasDirectoryPath(objectName);
    }

    /**
     * Converts the given object name to look like a directory path.
     * If the object name already looks like a directory path then
     * this call is a no-op.
     *
     * If the object name is null or empty, it is returned as-is.
     *
     * @param objectName Name of the object to inspect.
     * @return Directory path for the given path.
     */
    static String convertToDirectoryPath(String objectName) {
        return StorageResourceId.convertToDirectoryPath(objectName);
    }

    /**
     * Add a key and value representing the current time, as determined by the passed clock, to the
     * passed attributes dictionary.
     * @param attributes The file attributes map to update
     * @param clock The clock to retrieve the current time from
     */
    public static void addModificationTimeToAttributes(Map<String, byte[]> attributes, Clock clock) {
        attributes.put(FILE_MODIFICATION_TIMESTAMP_KEY, Longs.toByteArray(clock.currentTimeMillis()));
    }

    /**
     * Converts the given object name to look like a file path.
     * If the object name already looks like a file path then
     * this call is a no-op.
     *
     * If the object name is null or empty, it is returned as-is.
     *
     * @param objectName Name of the object to inspect.
     * @return File path for the given path.
     */
    public static String convertToFilePath(String objectName) {
        if (!Strings.isNullOrEmpty(objectName)) {
            if (objectHasDirectoryPath(objectName)) {
                objectName = objectName.substring(0, objectName.length() - 1);
            }
        }
        return objectName;
    }

    /**
     * Handy factory method for constructing a FileInfo from a GoogleCloudStorageItemInfo while
     * potentially returning a singleton instead of really constructing an object for cases like ROOT.
     */
    public static FileInfo fromItemInfo(PathCodec pathCodec, GoogleCloudStorageItemInfo itemInfo) {
        if (itemInfo.isRoot()) {
            return ROOT_INFO;
        } else {
            URI path = pathCodec.getPath(itemInfo.getBucketName(), itemInfo.getObjectName(), true);
            return new FileInfo(path, itemInfo);
        }
    }

    /**
     * Handy factory method for constructing a list of FileInfo from a list of
     * GoogleCloudStorageItemInfo.
     */
    public static List<FileInfo> fromItemInfos(PathCodec pathCodec, List<GoogleCloudStorageItemInfo> itemInfos) {
        List<FileInfo> fileInfos = new ArrayList<>();
        for (GoogleCloudStorageItemInfo itemInfo : itemInfos) {
            fileInfos.add(fromItemInfo(pathCodec, itemInfo));
        }
        return fileInfos;
    }

    /**
     * Indicates whether the given path looks like a directory path.
     *
     * @param path Path to inspect.
     * @return Whether the path looks like a directory path.
     */
    public static boolean isDirectoryPath(URI path) {
        return (path != null) && path.toString().endsWith(GoogleCloudStorage.PATH_DELIMITER);
    }

    /**
     * Converts the given resourceId to look like a directory path.
     * If the path already looks like a directory path then
     * this call is a no-op.
     *
     * @param resourceId StorageResourceId to convert.
     * @return A resourceId with a directory path corresponding to the given resourceId.
     */
    public static StorageResourceId convertToDirectoryPath(StorageResourceId resourceId) {
        if (resourceId.isStorageObject()) {
            if (!objectHasDirectoryPath(resourceId.getObjectName())) {
                resourceId = new StorageResourceId(resourceId.getBucketName(),
                        convertToDirectoryPath(resourceId.getObjectName()));
            }
        }
        return resourceId;
    }

    /**
     * Converts the given path to look like a directory path.
     * If the path already looks like a directory path then
     * this call is a no-op.
     *
     * @param path Path to convert.
     * @return Directory path for the given path.
     */
    public static URI convertToDirectoryPath(PathCodec pathCodec, URI path) {
        StorageResourceId resourceId = pathCodec.validatePathAndGetId(path, true);

        if (resourceId.isStorageObject()) {
            if (!objectHasDirectoryPath(resourceId.getObjectName())) {
                resourceId = convertToDirectoryPath(resourceId);
                path = pathCodec.getPath(resourceId.getBucketName(), resourceId.getObjectName(),
                        false /* allow empty name */);
            }
        }
        return path;
    }
}