<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package usda.weru.util;

import java.util.HashMap;
import java.util.Map;
import javolution.context.Context;
import org.apache.log4j.Logger;

/**
 *
 * @author Joseph Levin &lt;joelevin@weru.ksu.edu&gt;
 */
public class PropertyStackContext extends Context {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = Logger.getLogger(PropertyStackContext.class);
    private static final Map&lt;Object, Map&lt;String, Integer&gt;&gt; c_latches = new HashMap&lt;Object, Map&lt;String, Integer&gt;&gt;();
    private static final Object LOCK_LATCH = new Object();

    private Object c_source;
    private String c_propertyName;

    /**
     *
     */
    @Override
    protected void enterAction() {
    }

    /**
     *
     */
    @Override
    protected void exitAction() {
    }

    /**
     *
     * @return
     */
    public static PropertyStackContext getCurrent() {
        for (Context ctx = Context.getCurrent(); ctx != null; ctx = ctx.getOuter()) {
            if (ctx instanceof PropertyStackContext) {
                return (PropertyStackContext) ctx;
            }
        }
        //TODO: add a default context
        return null;
    }

//    public static void enter(){
//        Context.enter(PropertyStackContext.class);
//    }
    /**
     *
     * @param source
     * @param propertyName
     */
    public static void enter(Object source, String propertyName) {
        if (isPropertyOnStack(source, propertyName)) {
            LOGGER.debug("Duplicate property stack entrance. "
                    + (source != null ? source.toString() : "NULL") + ":"
                    + (propertyName != null ? propertyName : "NULL"));
        }
        Context.enter(PropertyStackContext.class);
        getCurrent().c_source = source;
        getCurrent().c_propertyName = propertyName;
        synchronized (LOCK_LATCH) {
            latchUp(source, propertyName);
        }

        //
    }

    /**
     *
     * @param source
     * @param propertyName
     */
    public static void exit(Object source, String propertyName) {
        if (getCurrent().getSource() == source &amp;&amp; getCurrent().getPropertyName().equals(propertyName)) {
            Context.exit(PropertyStackContext.class);
            synchronized (LOCK_LATCH) {
                latchDown(source, propertyName);
            }
        } else {
            throw new IllegalStateException("PropertyStackContext not exited: " + getCurrent().getPropertyName());
        }
    }

    /**
     *
     * @return
     */
    public String getPropertyName() {
        return c_propertyName;
    }

    /**
     *
     * @return
     */
    public Object getSource() {
        return c_source;
    }

    /**
     *
     * @param source
     * @param propertyName
     * @return
     */
    public static boolean isPropertyOnStack(Object source, String propertyName) {
        return isPropertyOnStack(source, propertyName, true);
    }

    /**
     *
     * @param source
     * @param propertyName
     * @param anyThread
     * @return
     */
    public static boolean isPropertyOnStack(Object source, String propertyName, boolean anyThread) {
        if (anyThread) {
            return isLatched(source, propertyName);

        } else {
            for (Context ctx = Context.getCurrent(); ctx != null; ctx = ctx.getOuter()) {
                if (ctx instanceof PropertyStackContext) {
                    PropertyStackContext pctx = (PropertyStackContext) ctx;

                    if (pctx.getSource() == source &amp;&amp; pctx.getPropertyName().equals(propertyName)) {
                        return true;
                    }
                }
            }
            return false;
        }
    }

    //latch code
    private static boolean isLatched(Object source, String propertyName) {
        Map&lt;String, Integer&gt; latch = c_latches.get(source);
        if (latch == null) {
            return false;
        }
        Integer count = latch.get(propertyName);
        if (count == null) {
            return false;
        }
        return count &gt; 0;
    }

    private static void latchUp(Object source, String propertyName) {
        Map&lt;String, Integer&gt; latch = c_latches.get(source);
        if (latch == null) {
            latch = new HashMap&lt;String, Integer&gt;();
            c_latches.put(source, latch);
        }
        Integer count = latch.get(propertyName);
        if (count == null) {
            count = 0;
        }
        count++;
        latch.put(propertyName, count);
    }

    private static void latchDown(Object source, String propertyName) {
        Map&lt;String, Integer&gt; latch = c_latches.get(source);
        if (latch == null) {
            latch = new HashMap&lt;String, Integer&gt;();
            c_latches.put(source, latch);
        }
        Integer count = latch.get(propertyName);
        if (count == null) {
            count = 0;
        }
        count--;

        if (count == 0) {
            latch.remove(propertyName);
            if (latch.isEmpty()) {
                c_latches.remove(source);
            }

        } else {
            latch.put(propertyName, count);
        }

    }
}
</pre></body></html>