19 package org.sleuthkit.autopsy.modules.embeddedfileextractor;
 
   21 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
   23 import java.io.IOException;
 
   24 import java.util.ArrayList;
 
   25 import java.util.List;
 
   26 import java.util.concurrent.Callable;
 
   27 import java.util.concurrent.ScheduledThreadPoolExecutor;
 
   28 import java.util.concurrent.TimeUnit;
 
   30 import java.util.logging.Logger;
 
   52 class FileTaskExecutor {
 
   54     private static final int MIN_THREADS_IN_POOL = 4;
 
   55     private static final int MAX_THREADS_IN_POOL = Integer.MAX_VALUE; 
 
   56     private static final String FILE_IO_TASK_THREAD_NAME = 
"file-io-executor-task-%d";
 
   57     private static final String FILE_EXISTS_TASK_DESC_FMT_STR = 
"Checking if %s already exists";
 
   58     private static final String MKDIRS_TASK_DESC_FMT_STR = 
"Making directory %s";
 
   59     private static final String NEW_FILE_TASK_DESC_FMT_STR = 
"Creating new file %s";
 
   60     private static final String FILE_OPS_LOG_NAME = 
"efe_file_ops";
 
   61     private static final Logger logger = ApplicationLoggers.getLogger(FILE_OPS_LOG_NAME);
 
   62     private final ScheduledThreadPoolExecutor executor;
 
   63     private final TaskTerminator terminator;
 
   88     FileTaskExecutor(IngestJobContext context) {
 
   89         executor = 
new ScheduledThreadPoolExecutor(MIN_THREADS_IN_POOL, 
new ThreadFactoryBuilder().setNameFormat(FILE_IO_TASK_THREAD_NAME).build());
 
   90         executor.setMaximumPoolSize(MAX_THREADS_IN_POOL);
 
   91         if (context != null) {
 
   92             terminator = 
new TaskTerminator(context);
 
  111     boolean exists(
final File file) 
throws FileTaskFailedException, InterruptedException {
 
  112         Callable<Boolean> task = () -> {
 
  113             return file.exists();
 
  115         return attemptTask(task, String.format(FILE_EXISTS_TASK_DESC_FMT_STR, file.getPath()));
 
  131     boolean mkdirs(
final File file) 
throws FileTaskFailedException, InterruptedException {
 
  132         Callable<Boolean> task = () -> {
 
  133             return file.mkdirs();
 
  135         return attemptTask(task, String.format(MKDIRS_TASK_DESC_FMT_STR, file.getPath()));
 
  150     boolean createNewFile(
final File file) 
throws FileTaskFailedException, InterruptedException {
 
  151         Callable<Boolean> task = () -> {
 
  152             return file.createNewFile();
 
  154         return attemptTask(task, String.format(NEW_FILE_TASK_DESC_FMT_STR, file.getPath()));
 
  169     private boolean attemptTask(Callable<Boolean> task, String taskDesc) 
throws FileTaskFailedException, InterruptedException {
 
  170         List<TaskRetryUtil.TaskAttempt> attempts = 
new ArrayList<>();
 
  171         attempts.add(
new TaskRetryUtil.TaskAttempt(0L, 10L, TimeUnit.MINUTES));
 
  172         attempts.add(
new TaskRetryUtil.TaskAttempt(5L, 10L, TimeUnit.MINUTES));
 
  173         attempts.add(
new TaskRetryUtil.TaskAttempt(10L, 10L, TimeUnit.MINUTES));
 
  174         attempts.add(
new TaskRetryUtil.TaskAttempt(15L, 10L, TimeUnit.MINUTES));
 
  175         Boolean success = TaskRetryUtil.attemptTask(task, attempts, executor, terminator, logger, taskDesc);
 
  176         if (success == null) {
 
  177             throw new FileTaskFailedException(taskDesc + 
" failed");
 
  193         executor.shutdownNow();
 
  229     static final class FileTaskFailedException 
extends Exception {
 
  231         private static final long serialVersionUID = 1L;
 
  238         private FileTaskFailedException(String message) {
 
  248         private FileTaskFailedException(String message, Throwable cause) {
 
  249             super(message, cause);
 
boolean fileIngestIsCancelled()