/* * Copyright 2014 Eediom 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 org.araqne.storage.hdfs; import java.io.IOException; import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; import org.araqne.storage.api.FilePath; import org.araqne.storage.api.FilePathNameFilter; import org.araqne.storage.api.StorageInputStream; import org.araqne.storage.api.StorageOutputStream; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.LocatedFileStatus; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.RemoteIterator; import org.apache.hadoop.fs.permission.FsAction; import org.apache.hadoop.fs.permission.FsPermission; public class HDFSFilePath implements FilePath { static final String PROTOCOL_NAME = "hdfs"; static final String PROTOCOL_STRING = "hdfs://"; private final HDFSCluster root; private final Path path; public HDFSFilePath(HDFSCluster root, String path) { this(root, new Path(path)); } public HDFSFilePath(HDFSCluster root, Path path) { this.root = root; this.path = path; } HDFSCluster getRoot() { return root; } @Override public int compareTo(FilePath o) { if (o instanceof HDFSFilePath) { HDFSFilePath rhs = (HDFSFilePath) o; int r = root.getAlias().compareTo(rhs.root.getAlias()); if (r != 0) return r; else return path.compareTo(rhs.path); } return getProtocol().compareTo(o.getProtocol()); } @Override public String getProtocol() { return PROTOCOL_NAME; } @Override public String getAbsolutePath() throws SecurityException { return root.toString() + path.toUri().toString(); } @Override public String getCanonicalPath() throws IOException, SecurityException { return getAbsolutePath(); } @Override public String getName() { return path.getName(); } @Override public boolean exists() throws SecurityException { try { return root.getFileSystem().exists(path); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } } @Override public boolean mkdirs() throws SecurityException { try { return root.getFileSystem().mkdirs(path); } catch (IOException e) { } return false; } @Override public boolean delete() throws SecurityException { try { return root.getFileSystem().delete(path, true); } catch (IOException e) { } return false; } @Override public boolean renameTo(FilePath dest) throws SecurityException { if (!(dest instanceof HDFSFilePath)) return false; HDFSFilePath destPath = (HDFSFilePath) dest; if (!root.equals(destPath.root)) return false; try { return root.getFileSystem().rename(path, destPath.path); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } } @Override public boolean isDirectory() throws SecurityException { try { return root.getFileSystem().isDirectory(path); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } } @Override public boolean isFile() throws SecurityException { try { return root.getFileSystem().isFile(path); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } } @Override public boolean canRead() throws SecurityException { String username = System.getProperty("user.name"); FileStatus fs; try { fs = root.getFileSystem().getFileStatus(path); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } FsPermission permission = fs.getPermission(); // TODO handle user group FsAction action = (username.equals(fs.getOwner()))? permission.getUserAction(): permission.getOtherAction(); return action.and(FsAction.READ).equals(FsAction.READ); } @Override public boolean canWrite() throws SecurityException { String username = System.getProperty("user.name"); FileStatus fs; try { fs = root.getFileSystem().getFileStatus(path); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } FsPermission permission = fs.getPermission(); // TODO handle user group FsAction action = (username.equals(fs.getOwner()))? permission.getUserAction(): permission.getOtherAction(); return action.and(FsAction.WRITE).equals(FsAction.WRITE); } @Override public char getSeperatorChar() { return Path.SEPARATOR_CHAR; } @Override public long length() throws SecurityException { try { return root.getFileSystem().getFileStatus(path).getLen(); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } } @Override public FilePath[] listFiles() throws SecurityException { List<FilePath> ret = new ArrayList<FilePath>(); if (!this.exists()) return (FilePath[]) (ret.toArray(new FilePath[0])); try { RemoteIterator<LocatedFileStatus> it = root.getFileSystem().listFiles(path, false); while (it.hasNext()) { ret.add(new HDFSFilePath(root, it.next().getPath())); } } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } return (FilePath[]) (ret.toArray(new FilePath[0])); } @Override public FilePath[] listFiles(FilePathNameFilter filter) throws SecurityException { List<FilePath> ret = new ArrayList<FilePath>(); if (!this.exists()) return (FilePath[]) (ret.toArray(new FilePath[0])); try { RemoteIterator<LocatedFileStatus> it = root.getFileSystem().listFiles(path, false); while (it.hasNext()) { FilePath curr = new HDFSFilePath(root, it.next().getPath()); if (filter.accept(this, curr.getName())) ret.add(curr); } } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } return (FilePath[]) (ret.toArray(new FilePath[0])); } @Override public StorageInputStream newInputStream() throws IOException { return new HDFSFileInputStream(this, root.getFileSystem().open(path)); } @Override public StorageOutputStream newOutputStream(boolean append) throws IOException { return new HDFSFileOutputStream(this, append? root.getFileSystem().append(path): root.getFileSystem().create(path)); } @Override public FilePath newFilePath(String child) { return new HDFSFilePath(root, new Path(path, child)); } private static final SecureRandom random = new SecureRandom(); @Override public FilePath createTempFilePath(String prefix, String suffix) throws IOException, IllegalArgumentException, SecurityException { long n = random.nextLong(); // handle corner case n = (n == Long.MIN_VALUE)? 0: Math.abs(n); String name = prefix + Long.toString(n) + suffix; return newFilePath(name); } @Override public FilePath getParentFilePath() throws SecurityException { Path parentPath = path.getParent(); if (parentPath == null) return null; return new HDFSFilePath(root, parentPath); } @Override public FilePath getAbsoluteFilePath() throws SecurityException { return this; } @Override public long getFreeSpace() throws SecurityException { try { return root.getFileSystem().getStatus(path).getRemaining(); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } } @Override public long getUsableSpace() throws SecurityException { try { return root.getFileSystem().getStatus(path).getRemaining(); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } } @Override public long getTotalSpace() throws SecurityException { try { return root.getFileSystem().getStatus(path).getCapacity(); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } } @Override public String toString() { return root.toString() + path.toString(); } @Override public boolean isNotEmpty() throws IOException { if (!exists()) return false; StorageInputStream is = null; try { is = newInputStream(); return is.available() > 0; } finally { if (is != null) is.close(); } } @Override public boolean deleteOnExit() throws SecurityException { try { return root.getFileSystem().deleteOnExit(path); } catch (IOException e) { throw new IllegalStateException("Unexpected IOException", e); } } @Override public long lastModified() throws SecurityException, IOException { FileStatus fileStatus = root.getFileSystem().getFileStatus(path); return fileStatus.getModificationTime(); } @Override public void touch() throws SecurityException, IOException { throw new UnsupportedOperationException(); } @Override public void setExecutable(boolean executable, boolean ownerOnly) throws SecurityException { throw new UnsupportedOperationException(); } @Override public void setWritable(boolean writable, boolean ownerOnly) throws SecurityException { throw new UnsupportedOperationException(); } @Override public void setReadable(boolean readable, boolean ownerOnly) throws SecurityException { throw new UnsupportedOperationException(); } }