io.cloudslang.lang.compiler.modeller.transformers.SeqStepsTransformer.java Source code

Java tutorial

Introduction

Here is the source code for io.cloudslang.lang.compiler.modeller.transformers.SeqStepsTransformer.java

Source

/*******************************************************************************
 * (c) Copyright 2016 Hewlett-Packard Development Company, L.P.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0 which accompany this distribution.
 *
 * The Apache License is available at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *******************************************************************************/
package io.cloudslang.lang.compiler.modeller.transformers;

import io.cloudslang.lang.compiler.modeller.model.SeqStep;
import io.cloudslang.lang.compiler.modeller.result.BasicTransformModellingResult;
import io.cloudslang.lang.compiler.modeller.result.TransformModellingResult;
import io.cloudslang.lang.entities.SensitivityLevel;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import static com.google.common.collect.Sets.newHashSet;
import static io.cloudslang.lang.compiler.CompilerConstants.DEFAULT_SENSITIVITY_LEVEL;
import static io.cloudslang.lang.compiler.SlangTextualKeys.SEQ_STEP_ACTION_KEY;
import static io.cloudslang.lang.compiler.SlangTextualKeys.SEQ_STEP_ARGS_KEY;
import static io.cloudslang.lang.compiler.SlangTextualKeys.SEQ_STEP_DEFAULT_ARGS_KEY;
import static io.cloudslang.lang.compiler.SlangTextualKeys.SEQ_STEP_HIGHLIGHT_ID_KEY;
import static io.cloudslang.lang.compiler.SlangTextualKeys.SEQ_STEP_ID_KEY;
import static io.cloudslang.lang.compiler.SlangTextualKeys.SEQ_STEP_NAME_KEY;
import static io.cloudslang.lang.compiler.SlangTextualKeys.SEQ_STEP_PATH_KEY;
import static io.cloudslang.lang.compiler.SlangTextualKeys.SEQ_STEP_SNAPSHOT_KEY;
import static io.cloudslang.lang.entities.ScoreLangConstants.SEQ_ASSIGNMENT_ACTION;
import static java.util.regex.Pattern.compile;
import static org.apache.commons.collections4.CollectionUtils.isNotEmpty;
import static org.apache.commons.lang.StringUtils.isEmpty;

public class SeqStepsTransformer extends AbstractTransformer
        implements Transformer<List<Map<String, Map<String, String>>>, ArrayList<SeqStep>> {
    private static final String SEQ_OPERATION_HAS_MISSING_TAGS = "Sequential operation step has the following missing tags: ";
    private static final Pattern OUTPUT_ASSIGNMENT = compile("Parameter\\(\"[^\"]+\"\\)");

    private static final Set<String> MANDATORY_KEY_SET = newHashSet(SEQ_STEP_ID_KEY, SEQ_STEP_PATH_KEY,
            SEQ_STEP_ACTION_KEY);
    private static final Set<String> WAIT_MANDATORY_KEYS = newHashSet(SEQ_STEP_ID_KEY, SEQ_STEP_ACTION_KEY,
            SEQ_STEP_DEFAULT_ARGS_KEY);
    private static final Set<String> WAIT_OPTIONAL_KEY_SET = newHashSet(SEQ_STEP_ARGS_KEY);
    private static final Set<String> OPTIONAL_KEY_SET = newHashSet(SEQ_STEP_ARGS_KEY, SEQ_STEP_DEFAULT_ARGS_KEY,
            SEQ_STEP_HIGHLIGHT_ID_KEY, SEQ_STEP_SNAPSHOT_KEY, SEQ_STEP_NAME_KEY);

    private static final String FOUND_DUPLICATE_STEP_WITH_ID = "Found duplicate step with id '%s' for sequential operation step.";
    private static final String INVALID_ASSIGNMENT_OPERATION = "Found invalid assignment operation for sequential operation step with id '%s'.";
    private static final String SEQ_OPERATION_HAS_EMPTY_TAGS = "Sequential operation step has the following empty tags: ";
    private static final String SEQ_OPERATION_ILLEGAL_TAGS = "Sequential operation step has the following illegal tags: ";

    private static final String WAIT = "Wait";
    private static final String WAIT_INVALID_ARG = "Invalid argument for 'Wait': %s.";
    private static final String WAIT_PARAM_REQUIRED = "Parameter required for 'Wait'.";

    private static final Pattern WAIT_ARGS = compile("\"\\d+[ \\t]*(,[ \\t]*\\d+)?\"");

    @Override
    public TransformModellingResult<ArrayList<SeqStep>> transform(List<Map<String, Map<String, String>>> rawData) {
        return transform(rawData, DEFAULT_SENSITIVITY_LEVEL);
    }

    @Override
    public TransformModellingResult<ArrayList<SeqStep>> transform(List<Map<String, Map<String, String>>> rawData,
            SensitivityLevel sensitivityLevel) {
        List<RuntimeException> errors = new ArrayList<>();
        ArrayList<SeqStep> transformedData = new ArrayList<>();

        if (isNotEmpty(rawData)) {
            Set<String> ids = new HashSet<>();
            for (Map<String, Map<String, String>> mapStep : rawData) {
                Map<String, String> stepProps = mapStep.values().iterator().next();

                try {
                    boolean isWaitStep = isWaitStep(stepProps);
                    if (isWaitStep) {
                        validateWaitStep(stepProps);
                    }

                    Set<String> mandatoryKeySet = isWaitStep ? WAIT_MANDATORY_KEYS : MANDATORY_KEY_SET;
                    Set<String> optionalKeySet = isWaitStep ? WAIT_OPTIONAL_KEY_SET : OPTIONAL_KEY_SET;

                    validateNotEmptyValues(stepProps, mandatoryKeySet, optionalKeySet);
                    validateOnlySupportedKeys(stepProps, mandatoryKeySet, optionalKeySet);

                    SeqStep seqStep = transformStep(stepProps);

                    validateUniqueIds(ids, seqStep);

                    if (!isWaitStep) {
                        validateAssignmentAction(seqStep);
                    }

                    transformedData.add(seqStep);

                } catch (RuntimeException rex) {
                    errors.add(rex);
                }
            }
        }

        return new BasicTransformModellingResult<>(transformedData, errors);
    }

    private void validateWaitStep(Map<String, String> stepProps) {
        String args = stepProps.getOrDefault(SEQ_STEP_ARGS_KEY, stepProps.get(SEQ_STEP_DEFAULT_ARGS_KEY));
        if (StringUtils.isEmpty(args)) {
            throw new RuntimeException(WAIT_PARAM_REQUIRED);
        }

        if (!WAIT_ARGS.matcher(args).matches()) {
            throw new RuntimeException(String.format(WAIT_INVALID_ARG, args));
        }
    }

    private boolean isWaitStep(Map<String, String> stepProps) {
        return StringUtils.equals(WAIT, stepProps.get(SEQ_STEP_ACTION_KEY));
    }

    private void validateAssignmentAction(SeqStep seqStep) {
        if (seqStep.getAction().equals(SEQ_ASSIGNMENT_ACTION)
                && (!OUTPUT_ASSIGNMENT.matcher(seqStep.getObjectPath()).matches() || isEmpty(seqStep.getArgs()))) {
            throw new RuntimeException(String.format(INVALID_ASSIGNMENT_OPERATION, seqStep.getId()));
        }
    }

    private void validateUniqueIds(Set<String> ids, SeqStep seqStep) {
        if (!ids.add(seqStep.getId())) {
            throw new RuntimeException(String.format(FOUND_DUPLICATE_STEP_WITH_ID, seqStep.getId()));
        }
    }

    private SeqStep transformStep(Map<String, String> stepProps) {
        SeqStep seqStep = new SeqStep();
        seqStep.setId(stepProps.get(SEQ_STEP_ID_KEY));
        seqStep.setObjectPath(stepProps.get(SEQ_STEP_PATH_KEY));
        seqStep.setAction(stepProps.get(SEQ_STEP_ACTION_KEY));
        seqStep.setArgs(stepProps.get(SEQ_STEP_ARGS_KEY));
        seqStep.setDefaultArgs(stepProps.get(SEQ_STEP_DEFAULT_ARGS_KEY));
        seqStep.setName(stepProps.get(SEQ_STEP_NAME_KEY));
        seqStep.setSnapshot(stepProps.get(SEQ_STEP_SNAPSHOT_KEY));
        seqStep.setHighlightId(stepProps.get(SEQ_STEP_HIGHLIGHT_ID_KEY));
        return seqStep;
    }

    private void validateNotEmptyValues(Map<String, String> tMap, Set<String> mandatoryKeySet,
            Set<String> optionalKeySet) {
        Validate.notNull(tMap);
        Validate.notNull(mandatoryKeySet);
        Validate.notNull(optionalKeySet);

        Set<String> missingKeys = new HashSet<>();
        Set<String> emptyValuesKeys = new HashSet<>();
        for (String reqKey : mandatoryKeySet) {
            String reqValue = tMap.get(reqKey);
            if (reqValue == null) {
                missingKeys.add(reqKey);
            } else if (reqValue.equals("")) {
                emptyValuesKeys.add(reqKey);
            }
        }
        if (isNotEmpty(missingKeys)) {
            throw new RuntimeException(SEQ_OPERATION_HAS_MISSING_TAGS + missingKeys.toString());
        }

        if (isNotEmpty(emptyValuesKeys)) {
            throw new RuntimeException(SEQ_OPERATION_HAS_EMPTY_TAGS + emptyValuesKeys.toString());
        }
    }

    private void validateOnlySupportedKeys(Map<String, String> tMap, Set<String> mandatoryKeys,
            Set<String> optionalKeys) {
        Set<String> invalidKeys = new HashSet<>(tMap.keySet());
        invalidKeys.removeAll(mandatoryKeys);
        invalidKeys.removeAll(optionalKeys);
        if (isNotEmpty(invalidKeys)) {
            throw new RuntimeException(
                    SEQ_OPERATION_ILLEGAL_TAGS + invalidKeys.toString() + INVALID_KEYS_ERROR_MESSAGE_SUFFIX);
        }
    }

    @Override
    public List<Scope> getScopes() {
        return Collections.emptyList();
    }

    @Override
    public String keyToTransform() {
        return null;
    }

}