/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 gobblin.util.filesystem; import com.google.common.base.Optional; import java.io.FileNotFoundException; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; public class FileStatusEntry extends FileStatus { static final FileStatusEntry[] EMPTY_ENTRIES = new FileStatusEntry[0]; private final FileStatusEntry parent; private FileStatusEntry[] children; private boolean exists; private final FileSystem fs; public Optional<FileStatus> _fileStatus; public FileStatusEntry(final Path path) throws IOException { this(null, path, path.getFileSystem(new Configuration())); } private FileStatusEntry(final FileStatusEntry parent, final Path path, FileSystem fs) throws IOException { if (path == null) { throw new IllegalArgumentException("Path is missing"); } this.parent = parent; this.fs = fs; this._fileStatus = Optional.fromNullable(this.fs.getFileStatus(path)); } public boolean refresh(final Path path) throws IOException { if (_fileStatus.isPresent()) { Optional<FileStatus> oldStatus = this._fileStatus; try { this._fileStatus = Optional.of(this.fs.getFileStatus(path)); this.exists = this._fileStatus.isPresent(); return (oldStatus.isPresent() != this._fileStatus.isPresent() || oldStatus.get().getModificationTime() != this._fileStatus.get().getModificationTime() || oldStatus.get().isDirectory() != this._fileStatus.get().isDirectory() || oldStatus.get().getLen() != this._fileStatus.get().getLen()); } catch (FileNotFoundException e) { _fileStatus = Optional.absent(); this.exists = false; return true; } } else { if (path.getFileSystem(new Configuration()).exists(path)) { _fileStatus = Optional.of(this.fs.getFileStatus(path)); return true; } else { return false; } } } /** * Create a new child instance. * <p> * Custom implementations should override this method to return * a new instance of the appropriate type. * * @param path The child file * @return a new child instance */ public FileStatusEntry newChildInstance(final Path path) throws IOException { return new FileStatusEntry(this, path, this.fs); } /** * Return the parent entry. * * @return the parent entry */ public FileStatusEntry getParent() { return parent; } /** * Return the level * * @return the level */ public int getLevel() { return parent == null ? 0 : parent.getLevel() + 1; } /** * Return the directory's files. * * @return This directory's files or an empty * array if the file is not a directory or the * directory is empty */ public FileStatusEntry[] getChildren() { return children != null ? children : EMPTY_ENTRIES; } /** * Set the directory's files. * * @param children This directory's files, may be null */ public void setChildren(final FileStatusEntry[] children) { this.children = children; } /** * Indicate whether the file existed the last time it * was checked. * * @return whether the file existed */ public boolean isExists() { return exists; } /** * Return the path from the instance FileStatus variable * @return */ public Path getPath() { return _fileStatus.get().getPath(); } /** * Return whether the path is a directory from the instance FileStatus variable. * @return */ public boolean isDirectory() { return _fileStatus.get().isDirectory(); } /** Compare if this object is equal to another object * @param o the object to be compared. * @return true if two file status has the same path name; false if not. */ @Override public boolean equals(Object o) { if (o == null || this.getClass() != o.getClass()) { return false; } FileStatusEntry other = (FileStatusEntry) o; return this._fileStatus.get().equals(other._fileStatus.get()); } /** * Returns a hash code value for the object, which is defined as * the hash code of the path name. * * @return a hash code value for the path name. */ @Override public int hashCode() { return getPath().hashCode(); } }