eu.esdihumboldt.hale.common.headless.impl.WorkspaceServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for eu.esdihumboldt.hale.common.headless.impl.WorkspaceServiceImpl.java

Source

/*
 * Copyright (c) 2012 Data Harmonisation Panel
 * 
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution. If not, see <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *     Data Harmonisation Panel <http://www.dhpanel.eu>
 */

package eu.esdihumboldt.hale.common.headless.impl;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.io.FileUtils;
import org.joda.time.DateTime;
import org.joda.time.ReadableDuration;

import de.fhg.igd.slf4jplus.ALogger;
import de.fhg.igd.slf4jplus.ALoggerFactory;
import eu.esdihumboldt.hale.common.headless.WorkspaceService;
import eu.esdihumboldt.util.PlatformUtil;
import eu.esdihumboldt.util.PropertiesFile;

/**
 * Default implementation of the {@link WorkspaceService}.
 * 
 * @author Simon Templer
 */
public class WorkspaceServiceImpl implements WorkspaceService {

    /**
     * Prefix of property names that are part of the external workspace
     * settings.
     */
    private static final String PROPERTY_SETTING_PREFIX = "setting_";

    /**
     * Suffix of the configuration file for a workspace folder, that is placed
     * alongside it in {@link #parentDir}.
     */
    private static final String CONFIG_FILE_SUFFIX = ".lease";

    /**
     * The property in the configuration file that states the end date of the
     * workspace lease time.
     */
    private static final String PROPERTY_LEASE_END = "leaseEnd";

    private static final ALogger log = ALoggerFactory.getLogger(WorkspaceServiceImpl.class);

    private final File parentDir;

    /**
     * Create a workspace service instance.
     * 
     * @param workspacesDir the base directory for workspaces, if the location
     *            does not exist or is not accessible, a default location inside
     *            the platform instance location is used
     */
    public WorkspaceServiceImpl(File workspacesDir) {
        if (workspacesDir == null || !workspacesDir.exists()) {
            // use default location
            workspacesDir = PlatformUtil.getInstanceLocation();
            if (workspacesDir != null) {
                if (!workspacesDir.exists()) {
                    workspacesDir.mkdirs();
                }
            } else {
                log.error("No instance location, can't initialize workspace service.");
            }
        }
        parentDir = workspacesDir;

        if (parentDir != null) {
            log.info("Workspaces location is " + parentDir.getAbsolutePath());
        }
    }

    /**
     * @see WorkspaceService#leaseWorkspace(ReadableDuration)
     */
    @Override
    public String leaseWorkspace(ReadableDuration duration) {
        File workspace = newFolder();

        DateTime leaseEnd = DateTime.now().plus(duration);

        File configFile = configFile(workspace);

        PropertiesFile props;
        try {
            props = new PropertiesFile(configFile);
            props.setProperty(PROPERTY_LEASE_END, leaseEnd.toString());
            props.save();
        } catch (IOException e) {
            throw new IllegalStateException("Can't write to workspace folder", e);
        }

        log.info("Leasing workspace " + workspace.getName() + " until " + leaseEnd.toString());

        return workspace.getName();
    }

    /**
     * @see WorkspaceService#getWorkspaceFolder(String)
     */
    @Override
    public File getWorkspaceFolder(String id) throws FileNotFoundException {
        if (id == null || id.isEmpty()) {
            throw new FileNotFoundException("Invalid workspace ID");
        }

        File workspace = new File(parentDir, id);
        if (!workspace.exists() || !configFile(workspace).exists()) {
            throw new FileNotFoundException("Workspace does not exist");
        }
        return workspace;
    }

    /**
     * @see WorkspaceService#getLeaseEnd(String)
     */
    @Override
    public DateTime getLeaseEnd(String workspaceId) throws IOException {
        PropertiesFile config = getConfiguration(workspaceId);
        String leaseEnd = config.getProperty(PROPERTY_LEASE_END);
        return DateTime.parse(leaseEnd);
    }

    private PropertiesFile getConfiguration(String workspaceId) throws IOException {
        File configFile = configFile(getWorkspaceFolder(workspaceId));
        if (configFile.exists()) {
            return new PropertiesFile(configFile);
        }

        throw new FileNotFoundException("Workspace configuration file missing");
    }

    /**
     * @see WorkspaceService#getSettings(String)
     */
    @Override
    public Map<String, String> getSettings(String workspaceId) throws IOException {
        PropertiesFile config;
        synchronized (this) { // TODO better locking, read/write, based in
            // workspaceId?!
            config = getConfiguration(workspaceId);
        }
        @SuppressWarnings("unchecked")
        Enumeration<String> enProps = (Enumeration<String>) config.propertyNames();

        Map<String, String> result = new HashMap<String, String>();
        while (enProps.hasMoreElements()) {
            String property = enProps.nextElement();
            if (property.startsWith(PROPERTY_SETTING_PREFIX)) {
                result.put(property.substring(PROPERTY_SETTING_PREFIX.length()), config.getProperty(property));
            }
        }

        return result;
    }

    /**
     * @see WorkspaceService#set(String, String, String)
     */
    @Override
    public void set(String workspaceId, String setting, String value) throws IOException {
        synchronized (this) { // TODO better locking, read/write, based on
            // workspaceId?!
            PropertiesFile config = getConfiguration(workspaceId);

            String key = PROPERTY_SETTING_PREFIX + setting;

            if (value == null) {
                config.remove(key);
            } else {
                config.setProperty(key, value);
            }

            config.save();
        }
    }

    /**
     * @see WorkspaceService#deleteWorkspace(String)
     */
    @Override
    public void deleteWorkspace(String id) {
        try {
            File workspace = getWorkspaceFolder(id);

            // delete folder
            FileUtils.deleteDirectory(workspace);
            // delete configuration file
            configFile(workspace).delete();

            log.info("Removed workspace " + workspace.getName() + ".");
        } catch (IOException e) {
            log.error("Error deleting workspace folder", e);
        }
    }

    /**
     * Triggers the service scanning for workspace folders where the lease time
     * has ended and deletes them.
     */
    public void trigger() {
        for (File candidate : parentDir.listFiles(new FileFilter() {

            @Override
            public boolean accept(File file) {
                return !file.isHidden() && file.isDirectory() && configFile(file).exists();
            }

        })) {
            // retrieve lease end time
            DateTime leaseEnd = null;
            try {
                PropertiesFile configFile = new PropertiesFile(configFile(candidate));
                leaseEnd = DateTime.parse(configFile.getProperty(PROPERTY_LEASE_END));
            } catch (Exception e) {
                log.error("Failed to retrieve workspace folder lease end time.", e);
            }

            if (leaseEnd != null) {
                if (leaseEnd.isBeforeNow()) {
                    // delete folder
                    try {
                        FileUtils.deleteDirectory(candidate);
                    } catch (IOException e) {
                        log.error("Error deleting workspace folder", e);
                    }

                    if (candidate.exists()) {
                        log.error("Failed to delete workspace folder, leaving it for next time.");
                    } else {
                        configFile(candidate).delete();
                        log.info("Removed workspace " + candidate.getName() + " after lease expired.");
                    }
                }
            }
        }
    }

    private File configFile(File workspace) {
        return new File(workspace.getParentFile(), workspace.getName() + CONFIG_FILE_SUFFIX);
    }

    private synchronized File newFolder() {
        File folder = null;
        while (folder == null || folder.exists()) {
            folder = new File(parentDir, UUID.randomUUID().toString());
        }
        folder.mkdirs();
        return folder;
    }

}