blob: cf962add3d57e6214ad1cc79cdf7d87f13e2fc15 [file] [log] [blame]
/*
* 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 org.apache.wayang.core.util.fs;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.wayang.core.api.exception.WayangException;
/**
* {@link FileSystem} implementation for the local file system.
*/
public class LocalFileSystem implements FileSystem {
private static final Logger logger = LogManager.getLogger(LocalFileSystem.class);
/**
* Retrieves a directory that can be used for temporary files.
*
* @return a {@link File} representing the directory
*/
public static File findTempDir() {
try {
final File tempFile = File.createTempFile("wayang", "probe");
tempFile.deleteOnExit();
return tempFile.getParentFile();
} catch (IOException e) {
logger.warn("Could not determine local temp directory.", e);
return null;
}
}
/**
* Converts a {@link File} object to a URL.
*
* @param file that should be converted
* @return the {@link String} representation of the URL
*/
public static String toURL(File file) {
try {
return file.toPath().toUri().toURL().toString();
} catch (MalformedURLException e) {
throw new WayangException(String.format("Could not create URI for %s", file), e);
}
}
/**
* Ensure that there is a directory represented by the given {@link File}.
*
* @param file the directory that should be ensured
*/
public static void ensureDir(File file) {
if (file.exists()) {
if (!file.isDirectory()) {
throw new WayangException(String.format("Could not ensure directory %s: It exists, but is not a directory.", file));
}
} else if (!file.mkdirs()) {
throw new WayangException(String.format("Could not ensure directory %s: It does not exist, but could also not be created.", file));
}
}
/**
* Create an empty file.
*
* @param file that should be created
*/
public static void touch(File file) {
ensureDir(file.getParentFile());
try (FileOutputStream fos = new FileOutputStream(file)) {
} catch (IOException e) {
throw new WayangException(String.format("Could not create %s.", file), e);
}
}
private static File toFile(String fileUrl) throws URISyntaxException, MalformedURLException {
if (fileUrl.startsWith("file:")) {
return new File(new URL(fileUrl).toURI());
} else {
logger.warn("Expect URLs, but got {}. Converting it to file:{}...", fileUrl, fileUrl);
return toFile("file:" + fileUrl);
}
}
@Override
public long getFileSize(String fileUrl) throws FileNotFoundException {
try {
File file = toFile(fileUrl);
return file.length();
} catch (MalformedURLException | URISyntaxException e) {
logger.error("Illegal URL: \"{}\"", fileUrl);
throw new FileNotFoundException("File not found, because the URL is not correct.");
}
}
@Override
public boolean canHandle(String urlAsString) {
if (!urlAsString.startsWith("file:")) return false;
try {
URL url = new URL(urlAsString);
return url.getProtocol().equals("file") &&
(url.getHost().equals("") || url.getHost().equals("localhost"));
} catch (MalformedURLException e) {
logger.error(String.format("Illegal URL: \"%s\"", urlAsString), e);
return false;
}
}
@Override
public InputStream open(String url) throws IOException {
try {
File file = toFile(url);
return new FileInputStream(file);
} catch (URISyntaxException e) {
throw new IOException("Could not process the given URL.", e);
}
}
@Override
public OutputStream create(String url) throws IOException {
return this.create(url, false);
}
@Override
public OutputStream create(String url, Boolean forceCreateParentDirs) throws IOException {
File file = null;
try {
file = toFile(url);
if (forceCreateParentDirs && file.getParentFile()!=null)
file.getParentFile().mkdirs();
return new FileOutputStream(file, false);
} catch (URISyntaxException e) {
throw new IOException("Could not process the given URL.", e);
} catch (IOException e) {
if (file != null) {
file.delete();
}
throw e;
}
}
@Override
public boolean isDirectory(String url) {
try {
return toFile(url).isDirectory();
} catch (URISyntaxException | MalformedURLException e) {
logger.warn("Could not inspect directory.", e);
return false;
}
}
@Override
public Collection<String> listChildren(String url) {
try {
final File[] files = toFile(url).listFiles();
if (files == null) {
return Collections.emptyList();
}
return Arrays.stream(files).map(File::toURI).map(Object::toString).collect(Collectors.toList());
} catch (URISyntaxException | MalformedURLException e) {
logger.warn("Could not inspect directory.", e);
return Collections.emptyList();
}
}
@Override
public boolean delete(String url, boolean isRecursiveDelete) throws IOException {
try {
final File file = toFile(url);
if (!isRecursiveDelete && file.isDirectory()) return false;
return this.delete(file);
} catch (URISyntaxException e) {
throw new IOException("Cannot access file.", e);
}
}
private boolean delete(File file) {
boolean canDelete = !file.isDirectory() || Arrays.stream(file.listFiles()).allMatch(this::delete);
return canDelete && file.delete();
}
}