org.alfresco.extension.wcmdeployment.NaiveFilesystemDeploymentTarget.java Source code

Java tutorial

Introduction

Here is the source code for org.alfresco.extension.wcmdeployment.NaiveFilesystemDeploymentTarget.java

Source

/*
 * Copyright (C) 2005-2010 Alfresco Software Limited.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * 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 General Public License for more details.
    
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    
 * As a special exception to the terms and conditions of version 2.0 of 
 * the GPL, you may redistribute this Program in connection with Free/Libre 
 * and Open Source Software ("FLOSS") applications as described in Alfresco's 
 * FLOSS exception.  You should have received a copy of the text describing 
 * the FLOSS exception, and it is also available here: 
 * http://www.alfresco.com/legal/licensing"
 */

package org.alfresco.extension.wcmdeployment;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Serializable;
import java.io.Writer;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.alfresco.deployment.DeploymentTarget;
import org.alfresco.deployment.FileDescriptor;
import org.alfresco.deployment.FileType;
import org.alfresco.deployment.impl.DeploymentException;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * ####TODO: Add description
 *
 * @author Peter Monks (peter.monks@alfresco.com)
 * @version $Id$
 */
public class NaiveFilesystemDeploymentTarget implements DeploymentTarget {
    private final static Log log = LogFactory.getLog(NaiveFilesystemDeploymentTarget.class);

    private final static String DEFAULT_BASE_DIRECTORY = "./naivetarget/";
    private final static String DEFAULT_METADATA_DIRECTORY = "./naivemetadata/";
    private final static String VERSION_FILENAME = "version.txt";

    private File baseDirectory = null;
    private File metadataDirectory = null;

    private ConcurrentMap<String, Map<String, Object>> deployments = null;

    public void init() {
        log.trace("NaiveFilesystemDeploymentTarget.init()");

        if (baseDirectory == null) {
            baseDirectory = new File(DEFAULT_BASE_DIRECTORY);
            mkdirs(baseDirectory);
        }

        if (metadataDirectory == null) {
            metadataDirectory = new File(DEFAULT_METADATA_DIRECTORY);
            mkdirs(metadataDirectory);
        }

        deployments = new ConcurrentHashMap<String, Map<String, Object>>();
    }

    /**
     * @see org.alfresco.deployment.DeploymentTarget#begin(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String)
     */
    public String begin(final String target, final String storeName, final int version, final String user,
            final char[] password) {
        log.trace("NaiveFilesystemDeploymentTarget.begin(" + target + ", " + storeName + ", " + version + ")");
        String result = GUID.generate();

        File targetDirectory = new File(baseDirectory, target);
        File storeDirectory = new File(targetDirectory, storeName);
        mkdirs(storeDirectory);

        File targetMetaDirectory = new File(metadataDirectory, target);
        File storeMetaDirectory = new File(targetMetaDirectory, storeName);
        mkdirs(storeMetaDirectory);

        Map<String, Object> deploymentState = new HashMap<String, Object>();

        deploymentState.put("target", target);
        deploymentState.put("store", storeName);
        deploymentState.put("version", Integer.valueOf(version));
        deploymentState.put("directory", storeDirectory);
        deploymentState.put("metaDirectory", storeMetaDirectory);

        if (deployments.putIfAbsent(result, deploymentState) != null) {
            throw new IllegalStateException("A deployment to this target is already in progress.");
        }

        return (result);
    }

    /**
     * @see org.alfresco.deployment.DeploymentTarget#prepare(java.lang.String)
     */
    public void prepare(final String ticket) throws DeploymentException {
        log.trace("NaiveFilesystemDeploymentTarget.prepare(" + ticket + ")");

        // Note: MongoDB isn't transactional, so this is a NO-OP
    }

    /**
     * @see org.alfresco.deployment.DeploymentTarget#createDirectory(java.lang.String, java.lang.String, java.lang.String, java.util.Set, java.util.Map)
     */
    public void createDirectory(final String ticket, final String path, final String guid,
            final Set<String> aspects, final Map<String, Serializable> properties) throws DeploymentException {
        log.trace("NaiveFilesystemDeploymentTarget.createDirectory(" + ticket + ", " + path + ")");

        File newDirectory = new File(getBaseDirectory(ticket), path);
        mkdirs(newDirectory);
    }

    /**
     * @see org.alfresco.deployment.DeploymentTarget#delete(java.lang.String, java.lang.String)
     */
    public void delete(final String ticket, final String path) throws DeploymentException {
        log.trace("NaiveFilesystemDeploymentTarget.delete(" + ticket + ", " + path + ")");

        File pathFile = new File(getBaseDirectory(ticket), path);

        if (pathFile.exists()) {
            if (!pathFile.delete()) {
                throw new DeploymentException("Unable to delete path '" + getPath(pathFile) + "'.");
            }
        }
    }

    /**
     * @see org.alfresco.deployment.DeploymentTarget#getCurrentVersion(java.lang.String, java.lang.String)
     */
    public int getCurrentVersion(final String target, final String storeName) {
        log.trace("NaiveFilesystemDeploymentTarget.getCurrentVersion(" + target + ", " + storeName + ")");
        int result = 0;

        File targetMetaDirectory = new File(metadataDirectory, target);
        File storeMetaDirectory = new File(targetMetaDirectory, storeName);
        File versionFile = new File(storeMetaDirectory, VERSION_FILENAME);

        if (versionFile.exists()) {
            CharBuffer buffer = CharBuffer.allocate(16);
            Reader reader = null;

            try {
                reader = new InputStreamReader(new FileInputStream(versionFile));
                reader.read(buffer);

                result = Integer.valueOf(buffer.toString().trim());
            } catch (final IOException ioe) {
                log.warn("Unable to retrieve version infomation from '" + getPath(versionFile) + "'.", ioe);
            } catch (final NumberFormatException nfe) {
                log.warn("Unable to parse version number '" + buffer.toString() + "'.", nfe);
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException ioe) {
                        // *Gulp* - if this occurs there's not a lot else we can do but swallow it...
                    }
                }
            }
        }

        return (result);
    }

    /**
     * @see org.alfresco.deployment.DeploymentTarget#getListing(java.lang.String, java.lang.String)
     */
    public List<FileDescriptor> getListing(final String ticket, final String parentPath)
            throws DeploymentException {
        log.trace("NaiveFilesystemDeploymentTarget.getListing(" + ticket + ", " + parentPath + ")");

        List<FileDescriptor> result = new ArrayList<FileDescriptor>();

        File parentPathFile = new File(getBaseDirectory(ticket), parentPath);

        if (parentPathFile.exists()) {
            File[] children = parentPathFile.listFiles();

            for (File child : children) {
                result.add(new FileDescriptor(child.getPath(), child.isDirectory() ? FileType.DIR : FileType.FILE,
                        null)); // Note: use of file GUID here is bogus!!
            }
        }

        return (result);
    }

    /**
     * @see org.alfresco.deployment.DeploymentTarget#send(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.util.Set, java.util.Map)
     */
    public OutputStream send(final String ticket, final String path, final String guid, final String encoding,
            final String mimeType, final Set<String> aspects, final Map<String, Serializable> props)
            throws DeploymentException {
        log.trace("NaiveFilesystemDeploymentTarget.send(" + ticket + ", " + path + ")");

        OutputStream result = null;

        File outputFile = new File(getBaseDirectory(ticket), path);

        try {
            if (!outputFile.exists()) {
                if (!outputFile.createNewFile()) {
                    throw new DeploymentException("Unable to create file '" + getPath(outputFile) + "'.");
                }
            }

            //####TEST!!!!
            result = new BufferedOutputStream(new NoopOutputStream());
            //result = new BufferedOutputStream(new FileOutputStream(outputFile));
        } catch (IOException ioe) {
            throw new DeploymentException("I/O error opening file '" + getPath(outputFile) + "' for write.", ioe);
        }

        return (result);
    }

    /**
     * @see org.alfresco.deployment.DeploymentTarget#updateDirectory(java.lang.String, java.lang.String, java.lang.String, java.util.Set, java.util.Map)
     */
    public void updateDirectory(final String ticket, final String path, final String guid,
            final Set<String> aspects, final Map<String, Serializable> properties) throws DeploymentException {
        log.trace("NaiveFilesystemDeploymentTarget.updateDirectory()");

        // NO-OP - we're ignoring directory aspects and properties in this DeploymentTarget
    }

    /**
     * @see org.alfresco.deployment.DeploymentTarget#commit(java.lang.String)
     */
    public void commit(final String ticket) {
        log.trace("NaiveFilesystemDeploymentTarget.commit(" + ticket + ")");

        // Update the version number then clear out the transient deployment state
        if (deployments.containsKey(ticket)) // WARNING WARNING WARNING: Not thread safe (non-atomic test-then-set)
        {
            setVersion(getMetaDirectory(ticket), getVersion(ticket));
            deployments.remove(ticket);
        }
    }

    /**
     * Filesystem isn't transactional, so this is effectively a NO-OP.
     * 
     * @see org.alfresco.deployment.DeploymentTarget#abort(java.lang.String)
     */
    public void abort(final String ticket) {
        log.trace("NaiveFilesystemDeploymentTarget.abort(" + ticket + ")");

        // Clear out the transient deployment state
        if (deployments.containsKey(ticket)) // WARNING WARNING WARNING: Not thread safe (non-atomic test-then-set)
        {
            deployments.remove(ticket);
        }
    }

    /**
     * @param baseDirectory the baseDirectory to set
     */
    public void setBaseDirectory(final File baseDirectory) {
        this.baseDirectory = baseDirectory;
    }

    /**
     * @param metadataDirectory the metadataDirectory to set
     */
    public void setMetadataDirectory(final File metadataDirectory) {
        this.metadataDirectory = metadataDirectory;
    }

    private void setVersion(final File metaDirectory, final int version) {
        Writer writer = null;
        File versionFile = new File(metaDirectory, VERSION_FILENAME);

        // Create the version file if it doesn't already exist
        if (!versionFile.exists()) {
            try {
                versionFile.createNewFile();
            } catch (IOException ioe) {
                // Checked exceptions suxors
                throw new DeploymentException("Unable to create version file.", ioe);
            }
        }

        // Write the version number to it
        try {
            writer = new OutputStreamWriter(new FileOutputStream(versionFile));
            writer.write(version);
            writer.flush();
        } catch (IOException ioe) {
            log.error("Unable to record version " + version + " in '" + getPath(versionFile) + "'.", ioe);
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException ioe) {
                    // *Gulp* - if this occurs there's not a lot else we can do but swallow it...
                }
            }
        }
    }

    private void mkdirs(final File newDirectory) {
        if (!newDirectory.exists()) {
            if (!newDirectory.mkdirs()) {
                throw new DeploymentException(
                        "Unable to create non-existent directory '" + getPath(newDirectory) + "'.");
            }
        }
    }

    private String getPath(final File file) {
        String result = null;

        try {
            result = file.getCanonicalPath();
        } catch (IOException ioe) {
            result = file.getAbsolutePath();
        }

        return (result);
    }

    private File getBaseDirectory(final String ticket) {
        return ((File) deployments.get(ticket).get("directory"));
    }

    private File getMetaDirectory(final String ticket) {
        return ((File) deployments.get(ticket).get("metaDirectory"));
    }

    private int getVersion(final String ticket) {
        return ((Integer) deployments.get(ticket).get("version"));
    }

}