/*
* Created on 18/ott/2011
* Copyright 2011 by Andrea Vacondio (andrea.vacondio@gmail.com).
*
* This file is part of the Sejda source code
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sejda.core.support.io;
import static org.apache.commons.lang3.SystemUtils.IS_OS_UNIX;
import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS;
import static org.apache.commons.lang3.SystemUtils.JAVA_IO_TMPDIR;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.SystemUtils;
import org.sejda.model.exception.TaskIOException;
import org.sejda.model.exception.TaskOutputVisitException;
import org.sejda.model.output.DirectoryTaskOutput;
import org.sejda.model.output.FileOrDirectoryTaskOutput;
import org.sejda.model.output.FileTaskOutput;
import org.sejda.model.output.TaskOutput;
import org.sejda.model.output.TaskOutputDispatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Provides IO utility methods.
*
* @author Andrea Vacondio
*
*/
public final class IOUtils {
private static final Logger LOG = LoggerFactory.getLogger(IOUtils.class);
private IOUtils() {
// hide
}
private static final String BUFFER_NAME = "sejdaTmp";
/**
* Creates a temp file trying to find the best location based on the task output.
*
* @param taskOut
* @return
* @throws TaskIOException
*/
public static File createTemporaryBuffer(TaskOutput taskOut) throws TaskIOException {
TmpBufferLocationFinder bufferLocationFinder = new TmpBufferLocationFinder();
try {
taskOut.accept(bufferLocationFinder);
File buffer = tmpFile(bufferLocationFinder.bufferLocation).toFile();
buffer.deleteOnExit();
return buffer;
} catch (TaskOutputVisitException | IOException e) {
throw new TaskIOException("Unable to create temporary buffer", e);
}
}
private static Path tmpFile(Path location) throws IOException {
if (IS_OS_UNIX) {
return Files.createTempFile(location, "." + BUFFER_NAME, null);
}
return hide(Files.createTempFile(location, BUFFER_NAME, null));
}
/**
* Sets the hidden attribute to true on Win platform
*
* @param path
* @return
* @throws IOException
*/
public static Path hide(Path path) throws IOException {
if (IS_OS_WINDOWS) {
Files.setAttribute(path, "dos:hidden", Boolean.TRUE);
}
return path;
}
/**
* Sets the hidden attribute to false on Win platform
*
* @param path
* @return
* @throws IOException
*/
public static Path unhide(Path path) throws IOException {
if (IS_OS_WINDOWS) {
Files.setAttribute(path, "dos:hidden", Boolean.FALSE);
}
return path;
}
/**
* @return a temporary file
* @throws TaskIOException
*/
public static File createTemporaryBuffer() throws TaskIOException {
return createTemporaryBuffer(".tmp");
}
public static File createTemporaryBuffer(String extension) throws TaskIOException {
try {
File buffer = File.createTempFile(BUFFER_NAME, extension);
buffer.deleteOnExit();
return buffer;
} catch (IOException e) {
throw new TaskIOException("Unable to create temporary buffer", e);
}
}
public static File createTemporaryBufferWithName(String filename) throws TaskIOException {
try {
File tmpDir = createTemporaryFolder();
File buffer = new File(tmpDir, filename);
boolean created = buffer.createNewFile();
if(!created) throw new IOException("Could not create new file: " + buffer.getAbsolutePath());
buffer.deleteOnExit();
return buffer;
} catch (IllegalStateException | IOException e) {
throw new TaskIOException("Unable to create temporary buffer", e);
}
}
private static final int TEMP_DIR_ATTEMPTS = 1000;
public static File createTemporaryFolder() {
File baseDir = SystemUtils.getJavaIoTmpDir();
String baseName = new StringBuilder(BUFFER_NAME).append(System.currentTimeMillis()).append("-").toString();
for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
File tempDir = new File(baseDir, baseName + counter);
if (tempDir.mkdir()) {
return tempDir;
}
}
throw new IllegalStateException("Failed to create directory within " + TEMP_DIR_ATTEMPTS + " attempts (tried "
+ baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')');
}
public static File findNewNameThatDoesNotExist(File output) throws IOException {
File newNamedOutput;
int count = 1;
int maxTries = 100;
String basename = FilenameUtils.getBaseName(output.getName());
String extension = FilenameUtils.getExtension(output.getName());
do {
String newName = String.format("%s(%d).%s", basename, count, extension);
newNamedOutput = new File(output.getParent(), newName);
count++;
} while (count < maxTries && newNamedOutput.exists());
if (newNamedOutput.exists()) {
LOG.warn("Unable to generate a new filename that does not exist, path was {}", output);
throw new IOException(
String.format("Unable to generate a new filename that does not exist, path was %s", output));
}
return newNamedOutput;
}
/**
* Component trying to find the best location for the temporary buffer based on the task output location
*
* @author Andrea Vacondio
*/
private static class TmpBufferLocationFinder implements TaskOutputDispatcher {
private Path bufferLocation = Paths.get(JAVA_IO_TMPDIR);
@Override
public void dispatch(FileTaskOutput output) {
Path dest = output.getDestination().toPath().getParent();
if (Files.exists(dest)) {
bufferLocation = dest;
}
}
@Override
public void dispatch(DirectoryTaskOutput output) {
Path dest = output.getDestination().toPath();
if (Files.exists(dest)) {
bufferLocation = dest;
}
}
@Override
public void dispatch(FileOrDirectoryTaskOutput output) {
Path dest = output.getDestination().toPath();
if (Files.exists(dest)) {
if (Files.isDirectory(dest)) {
bufferLocation = dest;
} else {
bufferLocation = dest.getParent();
}
}
}
}
}