/******************************************************************************* * Copyright (c) 2011, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.orion.internal.server.core.tasks; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.orion.server.core.IOUtilities; import org.eclipse.orion.server.core.LogHelper; import org.eclipse.orion.server.core.ServerConstants; import org.eclipse.orion.server.core.resources.Base64; import org.eclipse.orion.server.core.resources.FileLocker; /** * A facility for reading/writing information about long running tasks. This store will need to be reimplemented by * different server implementations if they do not support bare file access. This class intentionally does not * understand representations of tasks, to make it more easily pluggable in the future. */ public class TaskStore { private final File root; private static final String FILENAME_LOCK = ".lock"; //$NON-NLS-1$ private static final String FILENAME_TEMP = "temp"; //$NON-NLS-1$ public TaskStore(File root) { this.root = root; LogHelper.log(new Status(IStatus.INFO, ServerConstants.PI_SERVER_CORE, "Tasks metadata location is " + root.toString())); //$NON-NLS-1$ if (!root.exists()) { LogHelper.log(new Status(IStatus.INFO, ServerConstants.PI_SERVER_CORE, "Creating tasks folder " + root.toString())); //$NON-NLS-1$ if (!this.root.mkdirs()) { LogHelper.log(new Status(IStatus.ERROR, ServerConstants.PI_SERVER_CORE, "Problem creating tasks folder " + root.toString())); //$NON-NLS-1$ } } } private String getUserDirectory(String userId) { return new String(Base64.encode(userId.getBytes())); } private String getUserName(String userDirectoryName) { try { return new String(Base64.decode(userDirectoryName.getBytes())); } catch (Exception e) { return null; // if this is not encoded user name than return null } } /** * Returns a string representation of the task with the given id, or <code>null</code> if no such task exists. * * @param td * description of the task to read */ public String readTask(TaskDescription td) { File directory = new File(root, getUserDirectory(td.getUserId())); if (!directory.exists()) return null; FileLocker locker = new FileLocker(new File(directory, FILENAME_LOCK)); try { locker.lock(); if (!td.isKeep()) { directory = new File(directory, FILENAME_TEMP); if (!directory.exists()) return null; } File taskFile = new File(directory, td.getTaskId()); if (!taskFile.exists()) return null; StringWriter writer; FileReader reader = null; try { reader = new FileReader(taskFile); writer = new StringWriter(); IOUtilities.pipe(reader, writer, true, false); return writer.toString(); } finally { if (reader != null) try { reader.close(); } catch (IOException e) { LogHelper.log(e); return null; } } } catch (IOException e) { LogHelper.log(e); return null; } finally { locker.release(); } } /** * Writes task representation * * @param td * description of the task to write * @param representation * string representation or the task */ public void writeTask(TaskDescription td, String representation) { File directory = new File(root, getUserDirectory(td.getUserId())); if (!directory.exists()) { directory.mkdir(); } FileLocker locker = new FileLocker(new File(directory, FILENAME_LOCK)); try { locker.lock(); if (!td.isKeep()) { directory = new File(directory, FILENAME_TEMP); if (!directory.exists()) directory.mkdir(); } File taskFile = new File(directory, td.getTaskId()); FileWriter writer = new FileWriter(taskFile); StringReader reader = new StringReader(representation); IOUtilities.pipe(reader, writer, true, true); } catch (IOException e) { LogHelper.log(e); } finally { locker.release(); } } /** * Removes given task from the list. This doesn't consider task status, it is caller's responsibility to make sure * if task tracking can be stopped. This function does not stop the task. * * @param td * description of the task to remove * @return <code>true</code> if task was removed, <code>false</code> otherwise. */ public boolean removeTask(TaskDescription td) { File directory = new File(root, getUserDirectory(td.getUserId())); if (!directory.exists()) return false; FileLocker locker = new FileLocker(new File(directory, FILENAME_LOCK)); try { locker.lock(); if (!td.isKeep()) { directory = new File(directory, FILENAME_TEMP); if (!directory.exists()) return false; } File taskFile = new File(directory, td.getTaskId()); if (!taskFile.exists()) return false; return taskFile.delete(); } catch (IOException e) { LogHelper.log(e); return false; } finally { locker.release(); } } private void delete(File f) throws IOException { if (f.isDirectory()) { for (File c : f.listFiles()) delete(c); } if (!f.delete()) LogHelper.log(new Status(IStatus.ERROR, ServerConstants.PI_SERVER_CORE, "Cannot delete file " + f.getName())); //$NON-NLS-1$ } public void removeAllTempTasks() { File[] children = root.listFiles(); // listFiles returns null in case of IO exception if (children == null) return; for (File userDirectory : children) { if (userDirectory.isDirectory()) { removeAllTempTasks(userDirectory); } } } private void removeAllTempTasks(File userDirectory) { if (!userDirectory.exists()) return; FileLocker locker = new FileLocker(new File(userDirectory, FILENAME_LOCK)); try { locker.lock(); File directory = new File(userDirectory, FILENAME_TEMP); if (!directory.exists()) return; delete(directory); } catch (IOException e) { LogHelper.log(e); } finally { locker.release(); } } private List<TaskDescription> internalReadAllTasksDescriptions(File userDirectory, boolean includeTempTasks) { List<TaskDescription> result = new ArrayList<TaskDescription>(); String userId = getUserName(userDirectory.getName()); if (userId == null) { return result; // this is not a user directory } for (File taskFile : userDirectory.listFiles()) { if (!taskFile.isFile() || taskFile.getName().equals(FILENAME_LOCK)) { continue; } result.add(new TaskDescription(userId, taskFile.getName(), true)); } if (includeTempTasks) { File tempDir = new File(userDirectory, FILENAME_TEMP); if (tempDir.exists() && tempDir.isDirectory()) { for (File taskFile : tempDir.listFiles()) { if (!taskFile.isFile() || taskFile.getName().equals(FILENAME_LOCK)) { continue; } result.add(new TaskDescription(userId, taskFile.getName(), false)); } } } return result; } /** * Returns all tasks owned by a given user. * * @param userId * id of a user that is an owner of tasks * @return a list of tasks tracked for this user */ public List<TaskDescription> readAllTasks(String userId) { File userDirectory = new File(root, getUserDirectory(userId)); if (!userDirectory.exists()) return new ArrayList<TaskDescription>(); FileLocker locker = new FileLocker(new File(userDirectory, FILENAME_LOCK)); try { locker.lock(); return internalReadAllTasksDescriptions(userDirectory, false); } catch (IOException e) { LogHelper.log(e); return new ArrayList<TaskDescription>(); } finally { locker.release(); } } public List<TaskDescription> readAllTasks() { return readAllTasks(false); } public List<TaskDescription> readAllTasks(boolean includeTempTasks) { List<TaskDescription> result = new ArrayList<TaskDescription>(); if (root.exists() && root.isDirectory()) { for (File userDirectory : root.listFiles()) { FileLocker locker = new FileLocker(new File(userDirectory, FILENAME_LOCK)); try { locker.lock(); if (userDirectory.isDirectory()) { result.addAll(internalReadAllTasksDescriptions(userDirectory, includeTempTasks)); } } catch (IOException e) { LogHelper.log(e); } finally { locker.release(); } } } else { LogHelper.log(new Status(IStatus.ERROR, ServerConstants.PI_SERVER_CORE, "Tasks folder is not a directory " + root.toString())); //$NON-NLS-1$ } return result; } }