Package eu.planets_project.ifr.core.services.migration.genericwrapper2

Source Code of eu.planets_project.ifr.core.services.migration.genericwrapper2.PRCommandBuilder

/**
*
*/
package eu.planets_project.ifr.core.services.migration.genericwrapper2;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Logger;

import eu.planets_project.ifr.core.services.migration.genericwrapper2.exceptions.ConfigurationException;
import eu.planets_project.ifr.core.services.migration.genericwrapper2.exceptions.MigrationException;
import eu.planets_project.services.datatypes.Parameter;
import eu.planets_project.services.utils.ProcessRunner;

/**
* This utility class provides methods for the building a command to be executed
* with the <code>{@link ProcessRunner}</code>.
*
* @author Thomas Skou Hansen &lt;tsh@statsbiblioteket.dk&gt;
*/
class PRCommandBuilder {

    private final Logger log = Logger.getLogger(PRCommandBuilder.class
            .getName());

    private final Collection<Parameter> environmentParameters;

    /**
     * Create a <code>PRCommandBuilder</code> for construction of commands,
     * using the environment parameters specified by
     * <code>environmentParameters</code>.
     *
     * @param envrionmentParameters
     *            A parameter collection containing environment information such
     *            as absolute paths to executables used in the commands to be
     *            built.
     */
    PRCommandBuilder(Collection<Parameter> environmentParameters) {
        this.environmentParameters = environmentParameters;
    }

    /**
     * TODO: Revisit this documentation....
     *
     * Build a command to be executed with the
     * <code>{@link ProcessRunner}</code>based on a
     * <code>{@link CommandLine}</code> instrance, a
     * <code>{@link ToolPresets}</code> instance and a collection of
     * <code>{@link Parameter}</code> instances provided by the caller.
     *
     * @param commandLineTemplate
     * @param toolPresets
     * @param toolParameters
     * @param tempFileMappings
     * @return
     * @throws MigrationException
     *             if any non-configuration related errors are encountered.
     * @throws ConfigurationException
     *             if any configuration related errors are encountered.
     */
    List<String> buildCommand(MigrationPath migrationPath,
            Collection<Parameter> toolParameters,
            Map<String, File> tempFileMappings) throws MigrationException,
            ConfigurationException {

        final CommandLine commandLine = migrationPath.getCommandLine();

        // Get a complete list of identifiers used in the command line.
        final Set<String> commandLineIdentifiers = getIdentifiers(commandLine);

        // Get the key-value pairs from toolParameters that are used in the
        // command line.
        Map<String, String> identifierMap = getRelevantParameterMappings(
                commandLineIdentifiers, toolParameters);

        // Overwrite any previous registered identifier mappings with a preset
        // if a preset has been specified in the tool parameters or add settings
        // from the default preset if no parameters were specified by the
        // caller.
        identifierMap = addPresetParameters(identifierMap, toolParameters,
                migrationPath.getToolPresets());

        identifierMap = addTempFileMappings(identifierMap, tempFileMappings);

        // TODO: Check the parameters and filename mappings for injection
        // attacks by sanity checking the parameters -
        // throw exception in case of failure. However, it may be safe omitting
        // the test for the file name mappings, as they are solely based on the
        // configuration file and what the generic wrapper is doing.

        // Verify that all identifiers in commandLineIdentifiers are associated
        // with a value in identifierMap
        if (!identifierMap.keySet().containsAll(commandLineIdentifiers)) {
            commandLineIdentifiers.removeAll(identifierMap.keySet());
            throw new ConfigurationException("Cannot build the command line. "
                    + "Missing values for these identifiers: "
                    + commandLineIdentifiers);
        }

        // Replace the identifiers in the command line fragments with their
        // associated value (parameter, temp. file path etc.).
        final List<String> executableCommandLine = new ArrayList<String>();

        executableCommandLine.add(commandLine.getCommand());
        executableCommandLine.addAll(commandLine.getParameters());

        for (int commandFragmentIdx = 0; commandFragmentIdx < executableCommandLine
                .size(); commandFragmentIdx++) {

            final String commandFragment = executableCommandLine
                    .get(commandFragmentIdx);

            final StringTokenizer stringTokenizer = new StringTokenizer(
                    commandFragment, "#");

            String substitudedString = "";

            while (stringTokenizer.hasMoreTokens()) {

                String token = stringTokenizer.nextToken();

                int identifierEnd = token.indexOf(' ');

                // Handle identifiers enclosed in double quotes.
                final int quotePos = token.indexOf('\"') == -1 ? identifierEnd
                        : token.indexOf('\"');
                identifierEnd = (identifierEnd < quotePos)
                        && (identifierEnd != -1) ? identifierEnd : quotePos;

                if (identifierEnd == -1) {
                    identifierEnd = token.length();
                }

                final String identifier = token.substring(0, identifierEnd);

                final String identifierValue = identifierMap.get(identifier);
                if (identifierValue != null) {
                    substitudedString += identifierValue
                            + token.substring(identifierEnd);
                } else {
                    substitudedString += token;
                }
            }

            // Replace the command line fragment with the one where the
            // identifiers have been replaced with their respective values.
            executableCommandLine.remove(commandFragmentIdx);
            executableCommandLine.add(commandFragmentIdx, substitudedString);
        }

        return executableCommandLine;
    }

    /**
     * Add the temporary file mappings from <code>tempFileMappings</code> to the
     * <code>identifierMap</code> and throw an exception if any mapping in
     * <code>identifierMap</code> is about to be overwritten.
     *
     * @param identifierMap
     *            A key-value map to add label-file name mappings to.
     * @param tempFileMappings
     *            A key-value map containing labels associated with file paths.
     * @return <code>identifierMap</code> having the
     *         <code>tempFileMappings</code> added.
     * @throws MigrationException
     *             if any key-value mapping in <code>identifierMap</code> would
     *             be overwritten by this operation or if any problems are
     *             encountered while handling the temporary files.
     */
    private Map<String, String> addTempFileMappings(
            Map<String, String> identifierMap,
            Map<String, File> tempFileMappings) throws MigrationException {

        for (String tempFileLabel : tempFileMappings.keySet()) {
            if (identifierMap.containsKey(tempFileLabel)) {
                throw new MigrationException(String.format(
                        "The identifier map already contains an element with "
                                + "the key '%s'. Cannot add the temporay file "
                                + "mapping '%s = %s'.", tempFileLabel,
                        tempFileLabel, tempFileMappings.get(tempFileLabel)));
            }

            try {
                identifierMap.put(tempFileLabel, tempFileMappings.get(
                        tempFileLabel).getCanonicalPath());
            } catch (SecurityException se) {
                throw new MigrationException(
                        String.format(
                                "Failed accessing the canonical file path of the "
                                        + "temporary file labeled '%s'",
                                tempFileLabel), se);
            } catch (IOException ioe) {
                throw new MigrationException(
                        String.format(
                                "Failed accessing the canonical file path of the "
                                        + "temporary file labeled '%s'",
                                tempFileLabel), ioe);
            }
        }

        return identifierMap;
    }

    /**
     * Pick all key-value pairs from the parameters in
     * <code>toolParameters</code> and <code>environmentParameters</code> (given
     * at construction time), for each parameter which name exists in
     * <code>relevantIdentifiers</code>. If a parameter has been assigned a
     * value both in <code>toolParameters</code> and in the
     * <code>environmentParameters</code> then the parameter value from
     * <code>environmentParameters</code> is chosen.
     *
     * @param relevantIdentifiers
     *            A set of identifiers to look for in
     *            <code>toolParameters</code>.
     * @param toolParameters
     *            A collection of <code>Parameter</code> instances to pick
     *            key-value pairs from.
     * @return A <code>Map</code> containing all the key-value pairs for each
     *         <code>Parameter</code> in <code>toolParameters</code> which name
     *         exists in <code>relevantIdentifiers</code>.
     */
    private Map<String, String> getRelevantParameterMappings(
            Set<String> relevantIdentifiers,
            Collection<Parameter> toolParameters) {

        // Add all parameters from toolParameters that are listed in
        // relevantIdentifiers.
        final HashMap<String, String> parameterMappings = new HashMap<String, String>();
        for (Parameter parameter : toolParameters) {
            if (relevantIdentifiers.contains(parameter.getName())) {
                parameterMappings
                        .put(parameter.getName(), parameter.getValue());
            }
        }

        // Add all parameters from the attribute environmentParameters that are
        // listed in relevantIdentifiers.
        for (Parameter environmentParameter : environmentParameters) {
            if (relevantIdentifiers.contains(environmentParameter.getName())) {
                parameterMappings.put(environmentParameter.getName(),
                        environmentParameter.getValue());
            }
        }

        return parameterMappings;
    }

    /**
     * TODO: Revisit doc....
     *
     * Add the <code>toolParameters</code> and a parameter set (a set of preset
     * settings) from <code>toolPresets</code> if <code>toolParameters</code>
     * has a preset variable set.
     * <p/>
     * If any of the parameters in <code>toolParameters</code> are used in a
     * selected preset, then these parameter values will be overwritten and if
     * more than one preset is specified by <code>toolParameters</code> then an
     * exception will be thrown.
     *
     * @param identifierMap
     *            A map to add the parameter name and value pairs to.
     * @param toolParameters
     *            A collection of <code>Parameter</code> instances to add to
     *            <code>identifierMap</code> as key-value pairs.
     * @param toolPresets
     *            A number of predefined tool presets to search for any preset
     *            specified in <code>toolParameters</code>.
     * @return <code>identifierMap</code> with all relevant parameters added.
     * @throws ConfigurationException
     */
    private Map<String, String> addPresetParameters(
            Map<String, String> identifierMap,
            Collection<Parameter> toolParameters, ToolPresets toolPresets)
            throws ConfigurationException {

        // See if the parameters specifies that a preset should be applied.
        PresetSetting presetSetting = null;
        String presetCategoryID = null;
        if (toolParameters.isEmpty()) {
            // No parameters have been specified. See if there is a default
            // preset available.
            presetCategoryID = toolPresets.getDefaultPresetID();
            if (presetCategoryID != null) {
                presetSetting = toolPresets.getPreset(presetCategoryID)
                        .getDefaultSetting();
            }
        } else {
            // We have parameters. See if any of them specifies that a preset
            // should be applied.
            final Collection<String> presetCategories = toolPresets
                    .getToolPresetNames();
            for (Parameter parameter : toolParameters) {
                if (presetCategories.contains(parameter.getName())) {
                    // The parameter name specifies a valid preset category.
                    if (presetSetting == null) {
                        presetCategoryID = parameter.getName();
                        final Preset preset = toolPresets
                                .getPreset(presetCategoryID);
                        presetSetting = preset.getSetting(parameter.getValue());
                        if (presetSetting == null) {
                            throw new ConfigurationException(String.format(
                                    "The preset '%s = %s' has not been defined"
                                            + " in the configuration.",
                                    parameter.getName(), parameter.getValue()));
                        }
                    } else {
                        throw new ConfigurationException(String.format(
                                "More than one preset was specified in the "
                                        + "parameters. Found '%s"
                                        + " = %s' and '%s = %s'.",
                                presetCategoryID, presetSetting.getName(),
                                parameter.getName(), parameter.getValue()));
                    }
                }
            }
        }

        // Add the parameters from any selected preset, thus overriding any
        // parameters provided by toolParameters.
        if (presetSetting != null) {
            for (Parameter parameter : presetSetting.getParameters()) {

                final String previousValue = identifierMap.put(parameter
                        .getName(), parameter.getValue());
                if (previousValue != null) {
                    log
                            .warning(String
                                    .format(
                                            "The parameter '%s' was specified"
                                                    + "by the caller while also specifying usage of "
                                                    + "the preset '%s = %s'. The specified value: '%s'"
                                                    + " has now been overwritten with the value: '%s'"
                                                    + " from the preset.",
                                            parameter.getName(),
                                            presetCategoryID, presetSetting
                                                    .getName(), previousValue,
                                            parameter.getValue()));
                }
            }
        }

        return identifierMap;
    }

    /**
     * Get the names of all identifiers (all words with a leading '#') of the
     * form <code>#myIdentifier</code> found in the parameters in
     * <code>commandLine</code>. If the previous example was found in the
     * string, then the returned set would contain the string
     * &quot;myIdentifier&quot;.
     *
     * @param commandLine
     *            a <code>CommandLine</code> instance to find identifiers in.
     * @return a <code>Set</code> containing the identifiers found.
     */
    private Set<String> getIdentifiers(CommandLine commandLine) {

        final Set<String> foundIdentifiers = new HashSet<String>();
        final List<String> commandParameterStrings = new ArrayList<String>();
        commandParameterStrings.addAll(commandLine.getParameters());
        commandParameterStrings.add(commandLine.getCommand());

        for (String stringWithIdentifiers : commandParameterStrings) {

            StringTokenizer stringTokenizer = new StringTokenizer(
                    stringWithIdentifiers);

            while (stringTokenizer.hasMoreTokens()) {
                String token = stringTokenizer.nextToken();
                if (token.charAt(0) == '#') {
                    token = token.substring(1);
                    foundIdentifiers.add(token);
                }
            }
        }

        return foundIdentifiers;
    }

}
TOP

Related Classes of eu.planets_project.ifr.core.services.migration.genericwrapper2.PRCommandBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.