All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vmware.operations.OperationSequence Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Copyright (c) 2015-2018 VMware, Inc. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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.vmware.operations;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Perform a collection of operations in sequence, waiting for
 * each one to complete before starting the next.
 */
public class OperationSequence extends OperationSyncBase implements OperationCollection {
    private static final Logger logger = LoggerFactory.getLogger(OperationSequence.class.getPackage().getName());

    private boolean isExecuted = false;
    private List data = new ArrayList<>();
    private List revdata = null;

    /**
     * Constructor.
     * @param executorService An executor for running validations on other threads
     */
    public OperationSequence(ExecutorService executorService) {
        super(executorService);
    }

    /**
     * Add a command to the list.
     *
     * @param cmd the command to run
     */
    public void add(Operation cmd) {
        data.add(cmd);
    }

    /**
     * Add a command to the list, and execute it immediately.
     * This ensures that it will be cleaned up when this list is reverted/cleaned up.
     *
     * @param cmd the command to run
     * @throws Exception if the execution cannot be completed
     */
    public void addExecute(Operation cmd) throws Exception {
        data.add(cmd);
        cmd.execute();
    }

    /**
     * @return true if no commands have been added
     */
    public boolean isEmpty() {
        return data.isEmpty();
    }

    /**
     * @return the number of commands added
     */
    public int size() {
        return data.size();
    }

    @Override
    public List getOperations() {
        return data;
    }

    /**
     * After the list is finished, it cannot be changed.  Calling
     * execute() will automatically finish the list.
     *
     * The implementation also creates a reversed copy of the list, since
     * it is guaranteed to be used at least once.
     *
     * finish() is idempotent, and can be called multiple times.
     */
    public void finish() {
        if (revdata == null) {
            data = Collections.unmodifiableList(data);

            List clone = new ArrayList<>(data);
            Collections.reverse(clone);
            revdata = Collections.unmodifiableList(clone);
        }

        // If there are operations, and all have been executed, then we are executed too.
        if (!data.isEmpty()) {
            for (Operation o : data) {
                if (!o.isExecuted()) {
                    return;
                }
            }
            isExecuted = true;
        }
    }

    /**
     * Perform a list of commands in sequence, waiting for
     * each one to complete before starting the next.
     */
    @Override
    public void executeImpl() throws Exception {
        finish();

        logger.info("Executing {}", toString());
        throwIfExecuted();

        for (Operation cmd : data) {
            cmd.execute();
        }
        this.isExecuted = true;
    }

    /**
     * Revert the list of commands in reverse order of
     * execution.
     *
     * If any of the commands are marked as not isExecuted(),
     * they will be silently skipped.  This allows for easy
     * reverting of a test, when one or more of the individual
     * operations where undone explicitly.
     */
    @Override
    public void revertImpl() throws Exception {
        finish();

        logger.info("Reverting {}", toString());
        throwIfNotExecuted();

        // Create a new trace entry for each operation
        for (Operation cmd : revdata) {
            cmd.revert();
        }
        this.isExecuted = false;
    }

    /**
     * Returns true only if all of the commands in the list
     * have been executed.
     *
     * Note that partially executed lists (which can happen if one of the
     * commands threw an exception) still return false.
     */
    @Override
    public boolean isExecuted() {
        return this.isExecuted;
    }

    @Override
    public void cleanup() {
        finish();

        // Log to establish the current token
        logger.info("Cleaning {}", toString());

        for (Operation cmd : revdata) {
            try {
                cmd.cleanup();
            } catch (Throwable throwable) {
                handleCleanupException(throwable);
            }
        }

        this.isExecuted = false;
        this.data = null;
        this.revdata = null;
    }

    @Override
    public String toString() {
        StringBuilder message = new StringBuilder();
        message.append(getClass().getSimpleName());
        message.append("(@");
        message.append(Integer.toHexString(System.identityHashCode(this)));

        if (data != null) {
            message.append(", ");
            message.append(data.size());
            message.append(" items");
        }

        message.append(")");
        return message.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy