eu.asterics.ape.packaging.Packager.java Source code

Java tutorial

Introduction

Here is the source code for eu.asterics.ape.packaging.Packager.java

Source

package eu.asterics.ape.packaging;

import java.io.*;
import java.net.*;
import java.nio.file.*;
import static java.nio.file.StandardCopyOption.*;
import java.util.*;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.apache.commons.io.FileUtils;
import org.osgi.framework.BundleException;
import org.xml.sax.SAXException;

import eu.asterics.ape.main.APE;
import eu.asterics.ape.main.APEConfigurationException;
import eu.asterics.ape.main.APEProperties;
import eu.asterics.ape.main.Notifier;
import eu.asterics.ape.parse.ModelInspector;
import eu.asterics.mw.are.exceptions.BundleManagementException;
import eu.asterics.mw.are.exceptions.ParseException;
import eu.asterics.mw.model.deployment.IRuntimeModel;
import eu.asterics.mw.services.AstericsErrorHandling;
import eu.asterics.mw.services.ComponentUtils;
import eu.asterics.mw.services.ResourceRegistry;
import eu.asterics.mw.services.ResourceRegistry.RES_TYPE;

import static eu.asterics.ape.main.APEProperties.*;

/*
 *    AsTeRICS - Assistive Technology Rapid Integration and Construction Set
 *
 *
 *        d8888      88888888888       8888888b.  8888888 .d8888b.   .d8888b.
 *       d88888          888           888   Y88b   888  d88P  Y88b d88P  Y88b
 *      d88P888          888           888    888   888  888    888 Y88b.    
 *     d88P 888 .d8888b  888   .d88b.  888   d88P   888  888         "Y888b. 
 *    d88P  888 88K      888  d8P  Y8b 8888888P"    888  888            "Y88b.
 *   d88P   888 "Y8888b. 888  88888888 888 T88b     888  888    888       "888
 *  d8888888888      X88 888  Y8b.     888  T88b    888  Y88b  d88P Y88b  d88P
 * d88P     888  88888P' 888   "Y8888  888   T88b 8888888 "Y8888P"   "Y8888P"
 *
 *
 *                    homepage: http://www.asterics.org
 *
 *     This project has been partly funded by the European Commission,
 *                      Grant Agreement Number 247730
 *  
 *  
 *         Dual License: MIT or GPL v3.0 with "CLASSPATH" exception
 *         (please refer to the folder LICENSE)
 *
 */

/**
 * This class performs the packaging and copying of the AsTeRICS URIs to a given project / build location.
 * 
 *         Author: martin.deinhofer@technikum-wien.at
 *         Date: Oct 30, 2015
 *         Time: 14:30:00 PM
 */

public class Packager {
    public static final String BIN_FOLDER = "bin/";
    public static final String MERGED_FOLDER = "merged/";
    public static final String TEMPLATE_FOLDER = "template/";
    public static final String CUSTOM_FOLDER = "custom/";

    public static final String BIN_ARE_FOLDER = BIN_FOLDER + "ARE/";
    public static final String CUSTOM_BIN_FOLDER = CUSTOM_FOLDER + "bin/";
    public static final String CUSTOM_BIN_ARE_FOLDER = CUSTOM_BIN_FOLDER + "ARE/";
    public static final String CUSTOM_BIN_ARE_MODELS_FOLDER = CUSTOM_BIN_ARE_FOLDER + "models/";

    private APEProperties apeProperties = null;
    private ModelInspector modelInspector = null;
    private File projectDir = null;
    private File buildDir = null;
    private File buildMergedDir = null;

    /**
     * Constructs a Packager and configures it with the given Properties instance.
     * @param apeProperties
     * @param modelInspector TODO
     * @throws URISyntaxException 
     */
    public Packager(APEProperties apeProperties, ModelInspector modelInspector) throws URISyntaxException {
        super();
        this.apeProperties = apeProperties;
        this.modelInspector = modelInspector;
        this.projectDir = new File(apeProperties.getProperty(P_APE_PROJECT_DIR));

        buildDir = ResourceRegistry.resolveRelativeFilePath(projectDir,
                apeProperties.getProperty(APEProperties.P_APE_BUILD_DIR, APEProperties.DEFAULT_BUILD_DIR));
        buildMergedDir = ResourceRegistry.resolveRelativeFilePath(buildDir, MERGED_FOLDER);

        Notifier.info("ApeProp[" + APEProperties.P_APE_BUILD_DIR + "]=" + buildDir);
    }

    /**
     * Copy all files/URIs to project and/or build directories.
     * @throws URISyntaxException
     * @throws MalformedURLException
     * @throws IOException
     * @throws ParseException
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws TransformerException
     * @throws BundleManagementException
     * @throws APEConfigurationException 
     */
    public void copyFiles() throws URISyntaxException, MalformedURLException, IOException, ParseException,
            ParserConfigurationException, SAXException, TransformerException, BundleManagementException,
            APEConfigurationException {
        //
        File buildMergedAREDir = ResourceRegistry.resolveRelativeFilePath(buildMergedDir, BIN_ARE_FOLDER);
        Notifier.info("Copying files to " + buildMergedAREDir);

        Set<URI> modelURIs = modelInspector.getModelURIsFromProperty();
        Notifier.info("Found model URIs: " + modelURIs);
        if (modelURIs.size() == 0) {
            throw new APEConfigurationException("STOPPING: No model URIs found. Please check value of property "
                    + APEProperties.P_APE_MODELS + ": " + apeProperties.getProperty(APEProperties.P_APE_MODELS));
        }

        //get model instances
        Set<IRuntimeModel> modelInstances = modelInspector.getIRuntimeModelsOfModelURIs(modelURIs);

        //Remember all jar URIs we copied, we need this for fetching the respective license URIs afterwards.
        Set<URI> allJarURIs = new HashSet<URI>();
        Set<URI> componentJarURIs = modelInspector.getComponentTypeJarURIsOfModels(modelInstances);
        allJarURIs.addAll(componentJarURIs);
        copyURIs(componentJarURIs, buildMergedAREDir);

        Collection<URI> uriList = copyServices(buildMergedAREDir);
        allJarURIs.addAll(uriList);

        uriList = ResourceRegistry.getInstance().getOtherJarList(false);
        allJarURIs.addAll(uriList);
        copyURIs(uriList, buildMergedAREDir);

        DATA_COPY_MODE dataCopyMode = DATA_COPY_MODE.valueOf(
                apeProperties.getProperty(P_APE_DATA_COPY_MODE, DATA_COPY_MODE.ALL.toString()).toUpperCase());
        Notifier.info("ApeProp[" + P_APE_DATA_COPY_MODE + "]=" + dataCopyMode);
        if (DATA_COPY_MODE.ALL.equals(dataCopyMode)) {
            Notifier.info("Copying all data files");
            uriList = ResourceRegistry.getInstance().getDataList(false);
            copyURIs(uriList, buildMergedAREDir);
        } else if (DATA_COPY_MODE.FOLDER.equals(dataCopyMode) || DATA_COPY_MODE.SINGLE.equals(dataCopyMode)) {
            uriList = modelInspector.getPropertyReferredURIs(modelInstances);
            Notifier.info("Copying the following data files: " + uriList);
            copyURIs(uriList, buildMergedAREDir);
        } else {
            Notifier.info("Don't copy any data files");
        }

        uriList = ResourceRegistry.getInstance().getLicenseURIsofAsTeRICSJarURIs(allJarURIs);
        copyURIs(uriList, buildMergedAREDir);

        uriList = ResourceRegistry.getInstance().getMandatoryProfileConfigFileList(false);
        copyURIs(uriList, buildMergedAREDir);

        uriList = ResourceRegistry.getInstance().getAppImagesList(false);
        copyURIs(uriList, buildMergedAREDir);

        uriList = ResourceRegistry.getInstance().getOtherFilesList(false);
        copyURIs(uriList, buildMergedAREDir);

        copyModels(modelURIs, buildMergedAREDir);

        //Finally copy all custom files from APE.projectDir/bin
        copyCustomFiles(buildDir);
    }

    /**
     * Copies all the custom files of the folder APE.projectDir/bin to APE.buildDir/merged/bin
     * @param buildDir
     */
    public void copyCustomFiles(File buildDir) {
        File customBinDir = ResourceRegistry.resolveRelativeFilePath(projectDir, CUSTOM_BIN_FOLDER);
        File buildMergedBinDir = ResourceRegistry.resolveRelativeFilePath(buildMergedDir, BIN_FOLDER);
        try {
            Notifier.info("Copying custom files from <" + customBinDir + "> to <" + buildMergedBinDir + ">");
            FileUtils.copyDirectory(customBinDir, buildMergedBinDir);
        } catch (IOException e) {
            Notifier.warning(
                    "Could not copy custom files of <" + customBinDir + ">, to <" + buildMergedBinDir + ">", e);
        }
    }

    /**
     * Copies the services jars which are found in either the subfolder APE.projectDir/custom//bin/ARE/profile or in ARE.baseURI/profile 
     * @param targetSubDir
     */
    public Collection<URI> copyServices(File targetSubDir) {
        List<URI> servicesJars = new ArrayList<URI>();

        //Use two-phase approach.
        //1) search in relative custom/bin/ARE/profile folder for files starting with services (excluding config.ini and other files)
        //2) if no files were found there, use the services files of the ARE.baseURI
        File servicesFileDir = ResourceRegistry.resolveRelativeFilePath(projectDir,
                CUSTOM_BIN_ARE_FOLDER + ResourceRegistry.PROFILE_FOLDER);

        FilenameFilter servicesFilesFilter = new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                String lowerName = name.toLowerCase();
                return lowerName.startsWith("services") && lowerName.endsWith(".ini");
            }
        };

        Collection<URI> servicesFilesURIs = ComponentUtils.findFiles(servicesFileDir.toURI(), false, 1,
                servicesFilesFilter);

        URI areBaseURIProfileFolder = ResourceRegistry.resolveRelativeFilePath(
                ResourceRegistry.getInstance().getAREBaseURI(), ResourceRegistry.PROFILE_FOLDER).toURI();
        String message = "Using services files in " + areBaseURIProfileFolder;
        if (servicesFilesURIs.size() == 0) {
            servicesFilesURIs = ComponentUtils.findFiles(areBaseURIProfileFolder, false, 1, servicesFilesFilter);
        } else {
            message = "Using custom services files in " + servicesFileDir;
        }
        Notifier.info(message);
        Notifier.debug("Found services file URIs: " + servicesFilesURIs, null);
        for (URI servicesFile : servicesFilesURIs) {
            try (BufferedReader in = new BufferedReader(new FileReader(new File(servicesFile)));) {
                String path = null;
                while ((path = in.readLine()) != null) {
                    //sanity check, ignore empty lines and .jar entries
                    path = path.trim();
                    //Skipping comments
                    if (path.startsWith("#") || path.isEmpty() || !path.endsWith(".jar")) {
                        continue;
                    }

                    try {
                        URI jarURI = ResourceRegistry.getInstance().getResource(path, RES_TYPE.JAR);
                        servicesJars.add(jarURI);
                        copyURI(jarURI, targetSubDir, false);
                    } catch (URISyntaxException e) {
                        Notifier.warning("Cannot create servicesJarURI for path: " + path, e);
                    } catch (IOException e) {
                        Notifier.warning("Can not copy service jar: : " + path, e);
                    }
                }
            } catch (IOException e) {
                Notifier.warning("Cannot open services-ini file: " + servicesFile, e);
            }
        }
        return servicesJars;
    }

    /**
     * Copy the given models to the given directory. Also automatically resolves subdirs of bin/ARE to appropriate subdirs in a target directory.
     * @param modelURIs
     * @param targetSubDir
     */
    public void copyModels(Set<URI> modelURIs, File targetSubDir) {
        URI customURI = ResourceRegistry.resolveRelativeFilePath(projectDir, CUSTOM_BIN_ARE_MODELS_FOLDER).toURI();
        for (URI modelURI : modelURIs) {
            //Check if it is a model URI based on ARE base URI, if not copy file directly
            try {
                //Don't resolve against ARE.baseURI because we just wanna copy the model files to the bin/ARE/models dir.
                if (ResourceRegistry.isSubURI(customURI, modelURI)) {
                    Notifier.debug(
                            "Don't copy custom model in copyModels, will be copied in copyCustomFiles: " + modelURI,
                            null);
                    continue;
                }
                copyURI(modelURI, targetSubDir, true);
            } catch (URISyntaxException | IOException e) {
                Notifier.warning("Could not copy model: " + modelURI, e);
            }
        }
    }

    /**
     * Copyies all given URIs to the given target directory. Also automatically resolves subdirs of bin/ARE to appropriate subdirs in a target directory.
     * @param srcURIs
     * @param targetDir
     * @throws URISyntaxException
     * @throws IOException
     */
    public void copyURIs(Collection<URI> srcURIs, File targetDir) throws URISyntaxException, IOException {
        for (URI srcURI : srcURIs) {
            copyURI(srcURI, targetDir, true);
        }
    }

    /**
     * Copyies the given srcURI to the given targetDir directory. 
     * @param srcURI
     * @param targetDir
     * @param resolveTargetSubDirs: true: Resolves subdirs of bin/ARE to appropriate subdirs in a target directory.
     * @throws URISyntaxException
     * @throws IOException
     */
    public void copyURI(URI srcURI, File targetDir, boolean resolveAREBaseURISubDirs)
            throws URISyntaxException, IOException {
        try {
            File targetSubDir = targetDir;
            File src = ResourceRegistry.toFile(srcURI);

            //If we should resolve against ARE subfolders
            if (resolveAREBaseURISubDirs) {
                //Only works if the URI contains the currently active ARE.baseURI.
                //Determine relative src dir which will then be resolved against the base target dir.
                File relativeSrc = ResourceRegistry.toFile(ResourceRegistry.getInstance().toRelative(srcURI));

                //Determine parent folder of relativeSrc File
                targetSubDir = src.isDirectory() ? relativeSrc : relativeSrc.getParentFile();

                if (targetSubDir != null) {
                    //Resolve targetSubDir against targetDir
                    targetSubDir = ResourceRegistry.resolveRelativeFilePath(targetDir, targetSubDir.getPath());
                } else {
                    targetSubDir = targetDir;
                }
            }
            //Actually copy file
            Notifier.debug("Copying " + src + " -> " + targetSubDir, null);
            if (src.isDirectory()) {
                FileUtils.copyDirectory(src, targetSubDir);
            } else {
                FileUtils.copyFileToDirectory(src, targetSubDir);
            }
        } catch (MalformedURLException e) {
            //else try if it is a URL that can be fetched from anywhere else.
            Notifier.warning("URL resources not supported so far", e);
        }
    }

    /**
     * Does all steps of a build/make process. Fetching target dir properties, creating project/build directories, copying all URIs.
     * @throws IOException
     * @throws URISyntaxException
     * @throws ParseException
     * @throws ParserConfigurationException
     * @throws SAXException
     * @throws TransformerException
     * @throws BundleManagementException
     * @throws APEConfigurationException 
     */
    public void makeAll() throws IOException, URISyntaxException, ParseException, ParserConfigurationException,
            SAXException, TransformerException, BundleManagementException, APEConfigurationException {
        try {
            Notifier.debug("Deleting APE.buildDir before copying: " + buildDir, null);
            FileUtils.forceDelete(buildDir);
        } catch (IOException e) {
            Notifier.warning("Could not delete APE.buildDir: " + buildDir, e);
        }

        copyFiles();
        Notifier.info("FINISHED copying ARE: Go to the following folder and try it out: " + buildMergedDir);
    }
}