Package org.jenkinsci.plugins.workflow.test.steps

Source Code of org.jenkinsci.plugins.workflow.test.steps.BlockSemaphoreStep$Callback

/*
* The MIT License
*
* Copyright (c) 2013-2014, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package org.jenkinsci.plugins.workflow.test.steps;

import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException;
import org.jenkinsci.plugins.workflow.steps.Step;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
import com.google.common.util.concurrent.FutureCallback;
import org.jenkinsci.plugins.workflow.steps.StepExecution;

import java.util.Map;
import java.util.Set;

/**
* Block step that can be externally controlled.
*/
public final class BlockSemaphoreStep extends Step {

    public enum State {
        /** {@link #start} has not yet been called. */
        INIT,
        /** {@link #start} has been called, but the block has not started. */
        STARTED,
        /** {@link StepContext#invokeBodyLater} has been called, so the block has started. */
        BLOCK_STARTED,
        /** {@link FutureCallback} from {@link StepContext#invokeBodyLater} has been notified, so the block has ended. */
        BLOCK_ENDED,
        /** {@link FutureCallback} from {@link Step} has been notified, so the whole step has ended. */
        DONE,
        /** Aborted through {@link StepExecution#stop(FlowInterruptedException)}. */
        STOPPED
    }

    private State state = State.INIT;
    private StepContext context;
    private Object blockReturnValue;
    private Throwable blockFailure;

    private void moveFrom(State startingState) {
        assert state == startingState : state;
        state = State.values()[state.ordinal() + 1];
    }

    public State getState() {
        return state;
    }

    @Override public StepExecution start(final StepContext context) throws Exception {
        this.context = context;
        return new StepExecution(context) {
            @Override
            public boolean start() throws Exception {
                moveFrom(State.INIT);
                return false;
            }

            @Override
            public void stop(Throwable cause) throws Exception {
                state = State.STOPPED; // force the state change regardless of the current state
                context.onFailure(cause);
            }
        };
    }

    public void startBlock(Object... contextOverrides) {
        moveFrom(State.STARTED);
        context.invokeBodyLater(contextOverrides).addCallback(new Callback());
    }
   
    private class Callback implements FutureCallback {
        @Override public void onSuccess(Object returnValue) {
            blockReturnValue = returnValue;
            blockDone();
        }
        @Override public void onFailure(Throwable t) {
            blockFailure = t;
            blockDone();
        }
    }

    private synchronized void blockDone() {
        moveFrom(State.BLOCK_STARTED);
        notifyAll();
    }

    public synchronized Object waitForBlock() throws Throwable {
        while (state == State.BLOCK_STARTED) {
            wait();
        }
        assert state == State.BLOCK_ENDED : state;
        if (blockFailure != null) {
            throw blockFailure;
        } else {
            return blockReturnValue;
        }
    }

    public void finishSuccess(Object returnValue) {
        moveFrom(State.BLOCK_ENDED);
        context.onSuccess(returnValue);
    }

    public void finishFailure(Throwable t) {
        moveFrom(State.BLOCK_ENDED);
        context.onFailure(t);
    }

    @Override public StepDescriptor getDescriptor() {
        return new DescriptorImpl();
    }

    /* not an @Extension */ private static final class DescriptorImpl extends StepDescriptor {

        @Override public Set<Class<?>> getRequiredContext() {
            throw new UnsupportedOperationException();
        }

        @Override public String getFunctionName() {
            throw new UnsupportedOperationException();
        }

        @Override public Step newInstance(Map<String,Object> arguments) {
            throw new UnsupportedOperationException();
        }

        @Override public Map<String,Object> defineArguments(Step step) throws UnsupportedOperationException {
            throw new UnsupportedOperationException();
        }

        @Override public String getDisplayName() {
            return "Test block step";
        }

        @Override public boolean takesImplicitBlockArgument() {
            return true;
        }

    }

}
TOP

Related Classes of org.jenkinsci.plugins.workflow.test.steps.BlockSemaphoreStep$Callback

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.