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

org.apache.ode.bpel.engine.NStateLatch Maven / Gradle / Ivy

There is a newer version: 1.3.5-wso4v18
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.ode.bpel.engine;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * An N state synchronization latch useful for implementing hydration/dehydration. The
 * latch functions as follows. At any time, the latch is in one of N states and has a
 * count. Clients can "latch" and "release" the latch, which increments/decrements the
 * count; however, when latching, a state must be specified. If the state does not match
 * the current state, the latch blocks until the count is zero. Essentially, the latch
 * can change state only when the count is zero. Every time the latch changes state an
 * optional {@link Runnable} corresponding to the new state is executed.
 *
 * @author Maciej Szefler ( m s z e f l e r @ g m a i l . c o m )
 */
public class NStateLatch {
    static final Log __log = LogFactory.getLog(NStateLatch.class);

    /** Current state. */
    private int _state = -1;

    /** Current depth (i.e. number of enter() calls) */
    private int _depth = 0;

    /** Action for state transition ?-->i */
    protected Runnable _transitions[];

    /** Synchronization lock .*/
    private Lock _lock;

    /** _depth == 0 condition. */
    private Condition _depth0;

    private boolean _transitioning = false;

    /**
     * Constructor, the array of {@link Runnable}s defines the number of states and the transition
     * actions.
     * @param transitions action to perform when entering state x.
     */
    public NStateLatch(Runnable [] transitions) {
        _transitions = transitions;
        _lock = new ReentrantLock();
        _depth0 = _lock.newCondition();
    }

    public void latch(int state) {
        if (state >= _transitions.length || state < 0)
            throw new IllegalArgumentException("Invalid state.");

        _lock.lock();
        try {
            if (_transitioning )
                throw new IllegalStateException("Manipulating latch from transition. ");

            if (_state != state) {
                // wait for the depth to become 0
                while (_depth != 0)
                    _depth0.awaitUninterruptibly();

                if (_state != state) {
                    if (_transitions[state] != null)
                        try {
                            _transitioning = true;
                            _transitions[state].run();
                        } finally {
                            _transitioning = false;
                        }
                    _state = state;
                }
            }
        } finally {
            _depth ++;
            _lock.unlock();
        }
    }

    public void release(int state) {
        _lock.lock();
        try {

            if (_transitioning )
                throw new IllegalStateException("Manipulating latch from transition. ");

            if (_state != state) {
                Throwable throwable = new Exception();
                String stackTraceString = getStackTrace(throwable);
                __log.error("Latch error, was releasing for state " + state + " but actually in " + _state + "\n" + stackTraceString);
            }
            if (_depth <= 0)
                throw new IllegalStateException("Too many release() calls.");

            _depth --;

            if (_depth == 0)
                _depth0.signal();
        } finally {
            _lock.unlock();
        }
    }

    public int getDepth(int state) {
        return (_state == state ? _depth : 0);
    }

    public static String getStackTrace(Throwable aThrowable) {
        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
        aThrowable.printStackTrace(printWriter);
        return result.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy