com.c4om.autoconf.ulysses.configanalyzer.packager.CompressedFileConfigurationPackager.java Source code

Java tutorial

Introduction

Here is the source code for com.c4om.autoconf.ulysses.configanalyzer.packager.CompressedFileConfigurationPackager.java

Source

/*
Copyright 2014 Universidad Politcnica de Madrid - Center for Open Middleware (http://www.centeropenmiddleware.com)
    
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    
http://www.apache.org/licenses/LICENSE-2.0
    
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.c4om.autoconf.ulysses.configanalyzer.packager;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;

import com.c4om.autoconf.ulysses.configanalyzer.core.datastructures.ConfigurationAnalysisContext;
import com.c4om.autoconf.ulysses.configanalyzer.core.datastructures.ConfigurationPackage;
import com.c4om.autoconf.ulysses.configanalyzer.core.datastructures.ExtractedConfiguration;
import com.c4om.autoconf.ulysses.configanalyzer.core.exceptions.ConfigurationPackagingException;
import com.c4om.autoconf.ulysses.interfaces.Target;

/**
 * Abstract class for any packager that generates a compressed file.
 * Interface method ({@link ConfigurationPackager#packageConfigurations(ConfigurationAnalysisContext, Target)}) 
 * is implemented at this class and NEEDS NOT to be overridden. Thus, it is declared final. 
 * The task of classes extending this one is to implement the abstract methods with the 
 * actual implementation-dependent process and its details.
 * @author Pablo Alonso Rodrguez (Center for Open Middleware - UPM)
 *
 */
public abstract class CompressedFileConfigurationPackager implements ConfigurationPackager {

    /**
     * The destination folder of the compressed file
     */
    private File destinationFolder;

    /**
     * File patterns that match all the files to be included into the package. They must be relative to 
     * the particular temporary directory related to the application.
     */
    private List<String> filesToInclude;

    /**
     * This method provides the file extension of the compressed files (without dot). 
     * This extension must also be a valid package type, as specified by {@link ConfigurationPackage#getType()}
     * @return the extension of compressed files, without dot.
     */
    protected abstract String getExtension();

    /**
     * This method should perform the actual implementation-dependent compression process.
     * The content to package is described by a rootFolder and a list of subpaths relative 
     * to it, which point to the files to be packaged. If the compressed file format allows 
     * folder storage, the folder structure inside the compressed file will preserve the 
     * subpaths.
     * Resulting compressed file will be written to the path specified at zipFile parameter.
     * @param rootFolder the root folder to which entries are relative
     * @param entries subpaths pointing to the files to store.
     * @param zipFile the path to the compressed file.
     * @throws IOException if any IO error occurs.
     */
    protected abstract void compressFiles(File rootFolder, List<String> entries, File zipFile) throws IOException;

    /**
     * It takes an absolute {@link File} and returns a {@link File} relative to
     * another given base {@link File}.
     * 
     * @param absoluteFile the absolute File
     * @param baseFile the base File
     * @return a File relative to baseFile, pointing to the same file than
     *         absoluteFile
     */
    protected static File relativizeFile(File absoluteFile, File baseFile) {
        Path absolutePath = absoluteFile.toPath();
        Path basePath = baseFile.toPath();
        Path relativePath = basePath.relativize(absolutePath);
        return relativePath.toFile();
    }

    /**
     * This method returns a list of subpaths to all the files of a given directory (and its subdirectories).
     * If a file is provided, it returns a singleton list with the path to the file.
     * @param file the directory or file
     * @return the list of subpaths
     */
    protected static List<String> getSubPathsRecursive(File file, File baseFile) {
        if (!(file.isAbsolute())) {
            throw new IllegalArgumentException(
                    "The provided File object must be absolute. The provided one +(" + file + ") is not.");
        }
        if (file.isDirectory()) {
            Collection<File> files = FileUtils.listFiles(file, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
            List<String> result = new ArrayList<>();
            for (File currentFile : files) {
                result.add(relativizeFile(currentFile, baseFile).getPath());
            }
            return result;
        } else {
            return Collections.singletonList(relativizeFile(file, baseFile).getPath());
        }
    }

    /**
     * Constructor
     * @param destinationFolder the folder to place the zip files
     * @param filesToInclude the name of the folder where the configuration is stored (inside the temporary folder).
     */
    public CompressedFileConfigurationPackager(File destinationFolder, List<String> filesToInclude) {
        this.destinationFolder = destinationFolder;
        this.filesToInclude = filesToInclude;
    }

    /**
     * This method is declared final because subclases MUST NOT override it (they must limit to implement the other abstract methods).
     * @see com.c4om.autoconf.ulysses.interfaces.configanalyzer.packager.ConfigurationPackager#packageConfigurations(com.c4om.autoconf.ulysses.interfaces.configanalyzer.core.datastructures.ConfigurationAnalysisContext, com.c4om.autoconf.ulysses.interfaces.Target)
     */
    @Override
    public final void packageConfigurations(ConfigurationAnalysisContext context, Target target)
            throws ConfigurationPackagingException {

        for (ExtractedConfiguration<?> extractedConfiguration : context
                .getExtractedConfigurationsFiltered(target)) {
            if (!(extractedConfiguration.getConfigurationData().get(0) instanceof File)) {
                continue;
            }

            @SuppressWarnings("unchecked")
            List<File> configurationFiles = (List<File>) extractedConfiguration.getConfigurationData();
            List<File> desiredConfigurationFiles = FileFilterUtils
                    .filterList(new SuffixFileFilter(this.filesToInclude), configurationFiles);
            File actualRootFolder = configurationFiles.get(0).getParentFile();

            List<String> entries = new ArrayList<>();
            for (File desiredConfigurationFile : desiredConfigurationFiles) {
                entries.addAll(getSubPathsRecursive(desiredConfigurationFile, actualRootFolder));
            }
            File compressedFile = new File(destinationFolder,
                    extractedConfiguration.getId() + "." + getExtension());
            try {
                compressFiles(actualRootFolder, entries, compressedFile);
                ConfigurationPackage generatedPackage = new ConfigurationPackage(extractedConfiguration.getId(),
                        compressedFile, getExtension(), target);
                context.getConfigurationPackages().add(generatedPackage);
            } catch (IOException e) {
                throw new ConfigurationPackagingException(e);
            }
        }
    }

}