view flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/StackFrames.java @ 5779:ebec12def170

Datacage: Add a pool of builders to make it multi threadable. XML DOM is not thread safe. Therefore the old implementation only allowed one thread to use the builder at a time. As the complexity of the configuration has increased over time this has become a bottleneck of the whole application because it took quiet some time to build a result. Furthermore the builder code path is visited very frequent. So many concurrent requests were piled up resulting in long waits for the users. To mitigate this problem a round robin pool of builders is used now. Each of the pooled builders has an independent copy of the XML template and can be run in parallel. The number of builders is determined by the system property 'flys.datacage.pool.size'. It defaults to 4.
author Sascha L. Teichmann <teichmann@intevation.de>
date Sun, 21 Apr 2013 12:48:09 +0200
parents 142ed3c62765
children
line wrap: on
line source
package de.intevation.flys.artifacts.datacage.templating;

import java.util.ArrayList;
import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import javax.xml.xpath.XPathVariableResolver;

import javax.xml.namespace.QName;

import org.apache.log4j.Logger;


/**
 * Maintains stack of 'frames' which are maps from string to object.
 * Used for variables in datacage/meta-data system.
 */
public class StackFrames
implements   XPathVariableResolver
{
    private static Logger log = Logger.getLogger(StackFrames.class);

    public static final Object NULL = new Object();

    /** The frames (used like a stack). */
    protected List<Map<String, Object>> frames;

    public StackFrames() {
        frames = new ArrayList<Map<String, Object>>();
    }

    public StackFrames(Map<String, Object> initialFrame) {
        this();
        if (initialFrame != null) {
            frames.add(new HashMap<String, Object>(initialFrame));
        }
    }

    /** Push a new String->Object map. */
    public void enter() {
        frames.add(new HashMap<String, Object>());
    }

    /** Pop/Remove last String->Object map. */
    public void leave() {
        frames.remove(frames.size()-1);
    }

    /** Put Key/Value in last String->Object map. */
    public void put(String key, Object value) {
        int N = frames.size();
        if (N > 0) {
            frames.get(N-1).put(key, value);
        }
    }

    /** Put multiple Key/Values in last String->Object map. */
    public void put(String [] keys, Object [] values) {
        Map<String, Object> top = frames.get(frames.size()-1);
        for (int i = 0; i < keys.length; ++i) {
            top.put(keys[i], values[i]);
        }
    }

    /** Check last frame (string->object map) for key. */
    public boolean containsKey(String key) {
        key = key.toUpperCase();
        for (int i = frames.size()-1; i >= 0; --i) {
            if (frames.get(i).containsKey(key)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Get element (variable) key.
     * Returns null if not found.
     * @param key name to resolve
     * @return resolution, null if not found.
     */
    public Object get(String key) {
        return get(key, null);
    }

    /** result[0] is modified with value when true returned.
     * @return false if key not found in any frame. */
    public boolean getStore(String key, Object [] result) {

        key = key.toUpperCase();

        for (int i = frames.size()-1; i >= 0; --i) {
            Map<String, Object> frame = frames.get(i);
            if (frame.containsKey(key)) {
                result[0] = frame.get(key);
                return true;
            }
        }

        return false;
    }

    public Object get(String key, Object def) {

        key = key.toUpperCase();

        for (int i = frames.size()-1; i >= 0; --i) {
            Map<String, Object> frame = frames.get(i);
            if (frame.containsKey(key)) {
                return frame.get(key);
            }
        }

        return def;
    }

    public Object getNull(String key) {
        return getNull(key, null);
    }

    public Object getNull(String key, Object def) {

        key = key.toUpperCase();

        for (int i = frames.size()-1; i >= 0; --i) {
            Map<String, Object> frame = frames.get(i);
            if (frame.containsKey(key)) {
                Object value = frame.get(key);
                return value != null ? value : NULL;
            }
        }

        return def;
    }

    @Override
    public Object resolveVariable(QName variableName) {
        if (log.isDebugEnabled()) {
            log.debug("resolve var: " + variableName);
        }

        return getNull(variableName.getLocalPart());
    }

    public String dump() {
        StringBuilder sb = new StringBuilder("[");
        Set<String> already = new HashSet<String>();

        boolean first = true;

        for (int i = frames.size()-1; i >= 0; --i) {
            Map<String, Object> frame = frames.get(i);
            for (Map.Entry<String, Object> entry: frame.entrySet()) {
                if (already.add(entry.getKey())) {
                    if (first) { first = false;   }
                    else       { sb.append(", "); }
                    sb.append('\'').append(entry.getKey())
                      .append("'='").append(entry.getValue()).append('\'');
                }
            }
        }
        return sb.append(']').toString();
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org