org.alfresco.bm.file.AbstractTestFileService.java Source code

Java tutorial

Introduction

Here is the source code for org.alfresco.bm.file.AbstractTestFileService.java

Source

/*
 * Copyright (C) 2005-2014 Alfresco Software Limited.
 *
 * This file is part of Alfresco
 *
 * Alfresco is free software: you can redistribute it and/or modify
 * it 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.
 *
 * Alfresco 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 */
package org.alfresco.bm.file;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;

/**
 * Abstract service implementation of {@link FileDataService} based on MongoDB.
 *
 * @author Derek Hulley
 * @since 1.4
 */
public abstract class AbstractTestFileService implements TestFileService, InitializingBean {
    private static final String PROPERTIES_FILE = "TestFileService.properties";
    private static final String PROPERTY_FILESET = "fileset";

    private static Log logger = LogFactory.getLog(AbstractTestFileService.class);

    private final FileDataService fileDataService;
    private final String localDir;

    private File mirrorDir;
    private String fileset;

    public AbstractTestFileService(FileDataService fileDataService, String localDir) {
        this.fileDataService = fileDataService;
        this.localDir = localDir;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        indexFileData();
    }

    /**
     * Get the data mirror path (relative to the root location).  This is implementation-specific
     * as it depends on the way in which data is stored in the remote location.
     * 
     * @return              a relative path in which local files will be mirrored
     */
    protected abstract String getMirrorPath();

    /**
     * Provides a safe method to get the directory where physical files are mirrored.
     * This method is static and synchronized as access to the mirror directory
     * is VM-wide 
     */
    private static synchronized File initMirrorDir(String localDir, String mirrorPath) {
        // Check that the local directory exists
        File localStorage = new File(localDir);
        if (localStorage.exists() && !localStorage.isDirectory()) {
            throw new RuntimeException(
                    "Local directory property ('localDir') is not a valid directory: " + localStorage);
        }
        // Attempt to make the storage
        if (!localStorage.exists()) {
            localStorage.mkdirs();
        }
        if (!localStorage.exists() || !localStorage.isDirectory()) {
            throw new RuntimeException("Failed to create local storage folder: " + localStorage);
        }
        // Create the local directory to mirror the server path
        File mirrorFolder = new File(localDir, mirrorPath);
        try {
            mirrorFolder.mkdirs();
        } catch (Throwable e) {
            throw new RuntimeException("Failed to create mirror folder: " + mirrorFolder, e);
        }
        // Done
        return mirrorFolder;
    }

    /**
     * Looks for a {@link #PROPERTIES_FILE properties file} containing the name of the fileset that
     * this server uses.  The fileset is therefore unique to every local data location.
     */
    private static synchronized String getFileset(File mirrorDir) {
        Properties properties = new Properties();
        // See if there is a file with the properties present
        File propsFile = new File(mirrorDir, PROPERTIES_FILE);
        if (propsFile.exists()) {
            if (propsFile.isDirectory()) {
                throw new RuntimeException(
                        "Expected to find a properties file but found a directory: " + propsFile);
            }
            // Just read the server's unique key from it
            properties = new Properties();
            FileReader reader = null;
            try {
                reader = new FileReader(propsFile);
                properties.load(reader);
            } catch (IOException e) {
                throw new RuntimeException("Failed to load properties from file: " + propsFile, e);
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                    }
                }
            }
        }

        // Read the property
        String fileset = properties.getProperty(PROPERTY_FILESET);
        if (fileset == null) {
            // We must write a value into the file
            fileset = UUID.randomUUID().toString();
            properties.put(PROPERTY_FILESET, fileset);
            // Write the properties back
            FileWriter writer = null;
            try {
                writer = new FileWriter(propsFile);
                properties.store(writer, "Auto-generated fileset name");
            } catch (IOException e) {
                throw new RuntimeException("Failed to write fileset to properties file: " + propsFile, e);
            } finally {
                if (writer != null) {
                    try {
                        writer.close();
                    } catch (IOException e) {
                    }
                }
            }
        }
        // Done
        return fileset;
    }

    /**
     * List all files on the remote server
     * 
     * @return          a list of data with the {@link FileData#getRemoteName() remote name} populated
     */
    protected abstract List<FileData> listRemoteFiles();

    /**
     * Initialize the service by indexing the files on the FTP server
     */
    private void indexFileData() {
        // Get the local path (implementation-specific)
        String mirrorPath = getMirrorPath();
        // Make sure that the mirror directory is present
        mirrorDir = initMirrorDir(localDir, mirrorPath);

        // Get the fileset
        fileset = getFileset(mirrorDir);

        // Get a listing of the files
        List<FileData> remoteFileDatas = listRemoteFiles();
        if (remoteFileDatas.size() == 0) {
            throw new RuntimeException("No remote tests files: " + this);
        }

        // Index each of the files
        for (FileData remoteFileData : remoteFileDatas) {
            if (logger.isDebugEnabled()) {
                logger.debug("Processing details of remote file: " + remoteFileData);
            }

            String remoteName = remoteFileData.getRemoteName();
            String extension = FileData.getExtension(remoteName);
            long remoteSize = remoteFileData.getSize();

            // Check if the file is already present in the index
            FileData fileData = fileDataService.findFile(fileset, remoteName);
            String localName = null;
            if (fileData != null) {
                localName = fileData.getLocalName();
                // Check that the sizes match
                if (fileData.getSize() != remoteSize) {
                    // Size difference, so remove file index
                    fileDataService.removeFile(fileset, remoteName);
                    // and remove local file
                    File localFile = new File(mirrorDir, localName);
                    if (localFile.exists()) {
                        localFile.delete();
                    }
                }
                // Check that the local file, if it exists, is of the correct size
                File localFile = new File(mirrorDir, localName);
                if (localFile.exists() && localFile.length() != fileData.getSize()) {
                    // Local file is incorrect
                    localFile.delete();
                }
            } else {
                localName = UUID.randomUUID().toString() + "." + extension;

                fileData = new FileData();
                fileData.setFileset(fileset);
                fileData.setRemoteName(remoteName);
                fileData.setLocalName(localName);
                fileData.setExtension(extension);
                fileData.setSize(remoteSize);
                // Create the index data
                fileDataService.createNewFileData(fileData);
            }
        }
        // Done
    }

    /**
     * Download the file represented from the remote location to the local file.
     * Note that all stream closures must be handled internally but IO errors
     * can be allowed out.
     * 
     * @param fileData          data containing details of the remote file
     * @param localFile         the local file to write to
     * @throws IOException      will be handled by the calling code
     */
    protected abstract void downloadRemoteFile(FileData fileData, File localFile) throws IOException;

    @Override
    public File getFileByName(String filename) {
        FileData fileData = fileDataService.findFile(fileset, filename);
        return getFile(fileData);
    }

    @Override
    public File getFile() {
        FileData fileData = fileDataService.getRandomFile(fileset);
        return getFile(fileData);
    }

    @Override
    public File getFile(String extension) {
        FileData fileData = fileDataService.getRandomFile(fileset, extension);
        return getFile(fileData);
    }

    /**
     * Resolve the given file data into a real file
     */
    private File getFile(FileData fileData) {
        if (fileData == null) {
            return null;
        }
        // We have some data.
        // Do we already have it locally?
        File localFile = new File(mirrorDir, fileData.getLocalName());
        // Download the file, if required
        if (!localFile.exists()) {
            try {
                downloadRemoteFile(fileData, localFile);
            } catch (Exception e) {
                // Unable to get the remote file
                String remoteName = fileData.getRemoteName();
                fileDataService.removeFile(fileset, remoteName);
                try {
                    localFile.delete();
                } catch (Exception ee) {
                }
                throw new RuntimeException("Failed to download file from remote server: " + this, e);
            }
        }
        // Done
        return localFile;
    }

    /**
     * Test file name for JUnit testing
     * 
     * @since 2.1.1
     */
    private String testFileName = null;

    /**
     * Sets test file name for JUnit testing
     * 
     * @since 2.1.1
     */
    public void setTestFileName(String testFileName) {
        this.testFileName = testFileName;
    }

    /**
     * @return (String) Test file name for JUnit testing
     * @since 2.1.1
     */
    public String getTestFileName() {
        return this.testFileName;
    }
}