/* * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0 * (the "License"). You may not use this work except in compliance with the License, which is * available at www.apache.org/licenses/LICENSE-2.0 * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied, as more fully set forth in the License. * * See the NOTICE file distributed with this work for information regarding copyright ownership. */ package alluxio.underfs; import alluxio.AlluxioURI; import alluxio.collections.Pair; import alluxio.underfs.options.CreateOptions; import alluxio.underfs.options.DeleteOptions; import alluxio.underfs.options.ListOptions; import alluxio.underfs.options.MkdirsOptions; import alluxio.underfs.options.OpenOptions; import alluxio.util.io.PathUtils; import com.google.common.base.Preconditions; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Queue; import javax.annotation.concurrent.ThreadSafe; /** * A base abstract {@link UnderFileSystem}. */ @ThreadSafe public abstract class BaseUnderFileSystem implements UnderFileSystem { /** The UFS {@link AlluxioURI} used to create this {@link BaseUnderFileSystem}. */ protected final AlluxioURI mUri; /** A map of property names to values. */ protected HashMap<String, String> mProperties = new HashMap<>(); /** * Constructs an {@link BaseUnderFileSystem}. * * @param uri the {@link AlluxioURI} used to create this ufs */ protected BaseUnderFileSystem(AlluxioURI uri) { mUri = Preconditions.checkNotNull(uri); } @Override public void configureProperties() throws IOException { // Default implementation does not update any properties. } @Override public OutputStream create(String path) throws IOException { return create(path, CreateOptions.defaults().setCreateParent(true)); } @Override public boolean deleteDirectory(String path) throws IOException { return deleteDirectory(path, DeleteOptions.defaults()); } @Override public boolean exists(String path) throws IOException { return isFile(path) || isDirectory(path); } @Override public Map<String, String> getProperties() { return Collections.unmodifiableMap(mProperties); } @Override public UfsStatus[] listStatus(String path, ListOptions options) throws IOException { if (!options.isRecursive()) { return listStatus(path); } path = validatePath(path); List<UfsStatus> returnPaths = new ArrayList<>(); // Each element is a pair of (full path, UfsStatus) Queue<Pair<String, UfsStatus>> pathsToProcess = new ArrayDeque<>(); // We call list initially, so we can return null if the path doesn't denote a directory UfsStatus[] statuses = listStatus(path); if (statuses == null) { return null; } else { for (UfsStatus status : statuses) { pathsToProcess.add(new Pair<>(PathUtils.concatPath(path, status.getName()), status)); } } while (!pathsToProcess.isEmpty()) { final Pair<String, UfsStatus> pathToProcessPair = pathsToProcess.remove(); final String pathToProcess = pathToProcessPair.getFirst(); UfsStatus pathStatus = pathToProcessPair.getSecond(); returnPaths.add(pathStatus.setName(pathToProcess.substring(path.length() + 1))); if (pathStatus.isDirectory()) { // Add all of its subpaths UfsStatus[] children = listStatus(pathToProcess); if (children != null) { for (UfsStatus child : children) { pathsToProcess.add( new Pair<>(PathUtils.concatPath(pathToProcess, child.getName()), child)); } } } } return returnPaths.toArray(new UfsStatus[returnPaths.size()]); } @Override public InputStream open(String path) throws IOException { return open(path, OpenOptions.defaults()); } @Override public boolean mkdirs(String path) throws IOException { return mkdirs(path, MkdirsOptions.defaults()); } @Override public AlluxioURI resolveUri(AlluxioURI ufsBaseUri, String alluxioPath) { return new AlluxioURI(ufsBaseUri.getScheme(), ufsBaseUri.getAuthority(), PathUtils.concatPath(ufsBaseUri.getPath(), alluxioPath), ufsBaseUri.getQueryMap()); } @Override public void setProperties(Map<String, String> properties) { mProperties.clear(); mProperties.putAll(properties); } /** * Clean the path by creating a URI and turning it back to a string. * * @param path the path to validate * @return validated path */ protected static String validatePath(String path) { return new AlluxioURI(path).toString(); } }