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

com.jtstand.AbstractVariables Maven / Gradle / Ivy

/*
 * Copyright (c) 2009 Albert Kurucz.
 *
 * This file, AbstractVariables.java is part of JTStand.
 *
 * JTStand is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JTStand is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with GTStand.  If not, see .
 */
package com.jtstand;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import javax.script.Bindings;
import javax.script.ScriptException;

/**
 *
 * @author albert_kurucz
 */
abstract public class AbstractVariables extends AbstractProperties {

    private static final Logger LOGGER = Logger.getLogger(TestStepInstance.class.getCanonicalName());
    private Map variablesMap = new HashMap();
    private transient Map> lockerThreads = new HashMap>();
    private transient final Object variableLock = new Object();
    private transient Thread actualLockerThread;

    public void abort(Thread thread) {
        if (thread != null) {
            for (String variableName : lockerThreads.keySet()) {
                if (lockerThreads.get(variableName).contains(thread)) {
                    TestStepScript.abort(variablesMap.get(variableName));
                }
            }
        }
    }

    public void dispose() {
        synchronized (variableLock) {
            Object[] vars = variablesMap.values().toArray();
            for (int i = vars.length - 1; i >= 0; i--) {
                TestStepScript.disposeOrClose(vars[i]);
            }
            lockerThreads.clear();
        }
    }

    public void clear() {
        variablesMap.clear();
    }

    /*
     * when running evaluations outside of steps
     */
    public Object getVariable(String keyString, TestProperty tsp, Bindings bindings) throws InterruptedException, ScriptException {
        synchronized (variableLock) {
            Object v = variablesMap.get(keyString);
            if (v != null) {
                return v;
            }
            v = tsp.getPropertyObject(bindings);
            if (v != null) {
                put(keyString, v);
            }
            return v;
        }
    }

    public Object getVariable(String keyString, boolean wait, TestProperty tsp, TestStepInstance step) throws InterruptedException, ScriptException {
        if (wait) {
            while (true) {
                Object v = getVariable(keyString, tsp, step);
                if (v != null) {
                    return v;
                }
                Thread.sleep(1);
            }
        }
        synchronized (variableLock) {
            Object v = getVariable(keyString, tsp, step);
            if (v != null) {
                return v;
            }
            v = tsp.getPropertyObject(step);
            if (v != null) {
                put(keyString, v);
            }
            return v;
        }
    }

    private Object getVariable(String keyString, TestProperty tsp, TestStepInstance step) throws ScriptException, InterruptedException {
        if (tsp.getPropertyValueAttribute() != null) {
//            System.out.println("propertyValueAttribute of '" + tsp.getName() + "' is: '" + tsp.getPropertyValueAttribute() + "'");
            return tsp.getPropertyValueAttribute();
        }
        if (tsp.isMutex() != null && tsp.isMutex()) {
            Set deadThreads = new HashSet();
            while (true) {
                synchronized (variableLock) {
                    boolean locked = false;
                    HashSet lockerThread = lockerThreads.get(keyString);
                    if (lockerThread != null) {
                        deadThreads.clear();
                        Iterator it = lockerThread.iterator();
                        while (it.hasNext() && !locked) {
                            Thread locker = it.next();
                            if (!locker.isAlive()) {
                                deadThreads.add(locker);
                            } else {
                                if (!step.isThreadInFamily(locker)) {
                                    locked = true;
                                    if (!locker.equals(actualLockerThread)) {
                                        actualLockerThread = locker;
//                                        LOGGER.info("Variable is locked by: " + actualLockerThread.getName());
                                    }
                                }
                            }
                        }
                        lockerThread.removeAll(deadThreads);
                    } else {
                        lockerThread = new HashSet();
                        lockerThreads.put(keyString, lockerThread);
                    }
                    if (!locked) {
                        Thread t = step.getThisThread();
                        if (t != null && t.isAlive()) {
                            lockerThread.add(t);
                        } else {
                            throw new IllegalStateException("Trying to lock sequence variable '" + keyString + "' by a dead thread of step '" + step.getTestStepInstancePath() + "'");
                        }
                        return variablesMap.get(keyString);
                    }
                }
                Thread.sleep(1L);
            }
        }
        synchronized (variableLock) {
            return variablesMap.get(keyString);
        }
    }

    public void releaseVariable(String keyString, TestProperty tsp, TestStepInstance step) {
        if (tsp.isMutex() != null && tsp.isMutex()) {
            synchronized (variableLock) {
                //boolean locked = false;
                HashSet lockerThread = lockerThreads.get(keyString);
                if (lockerThread != null) {
                    Set deadThreads = new HashSet();
                    Iterator it = lockerThread.iterator();
//                    while (it.hasNext() && !locked) {
                    while (it.hasNext()) {
                        Thread locker = it.next();
                        if (!locker.isAlive()) {
                            deadThreads.add(locker);
                        }
                    }
                    lockerThread.removeAll(deadThreads);
                    Thread t = step.getThisThread();
                    if (t != null && t.isAlive()) {
                        lockerThread.remove(Thread.currentThread());
                    } else {
                        throw new IllegalStateException("Trying to release sequence variable '" + keyString + "' by a dead thread of step '" + step.getTestStepInstancePath() + "'");
                    }
                    if (lockerThread.isEmpty()) {
                        lockerThreads.remove(keyString);
                    }
                }
            }
        }
    }

    public Object put(String name, Object value) {
//        System.out.println("putting '" + name + "' value: " + value);
        return variablesMap.put(name, value);
    }

    boolean containsKey(String keyString) {
        return variablesMap.containsKey(keyString);
    }

    boolean containsValue(Object value) {
        return variablesMap.containsValue(value);
    }

    Object remove(String key) {
        return variablesMap.remove(key);
    }

    Set keySet() {
        return variablesMap.keySet();
    }

    public Collection values() {
        return variablesMap.values();
    }
}