view flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/FunctionResolver.java @ 5561:f8a4ee86d276

Add dc:replace function for datacage
author Andre Heinecke <aheinecke@intevation.de>
date Thu, 04 Apr 2013 16:07:24 +0200
parents df32d7518f55
children 7e837c5c377b
line wrap: on
line source
package de.intevation.flys.artifacts.datacage.templating;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import javax.xml.xpath.XPathFunctionResolver;

import org.apache.log4j.Logger;


/** Resolves functions (e.g. dc:contains) in Datacage/Meta-Data system. */
public class FunctionResolver
implements   XPathFunctionResolver
{
    /** Home logger. */
    private static Logger log = Logger.getLogger(FunctionResolver.class);

    public static final String FUNCTION_NAMESPACE_URI = "dc";

    public static final class Entry {

        String        name;
        XPathFunction function;
        int           arity;

        public Entry() {
        }

        public Entry(String name, XPathFunction function, int arity) {
            this.name     = name;
            this.function = function;
            this.arity    = arity;
        }
    } // class Entry

    /** List of functions. */
    protected List<Entry> functions;

    protected Builder.BuildHelper buildHelper;


    public FunctionResolver() {
        this(null);
    }

    public FunctionResolver(Builder.BuildHelper buildHelper) {
        this.buildHelper = buildHelper;

        functions = new ArrayList<Entry>();

        addFunction("contains", 2, new XPathFunction() {
            @Override
            public Object evaluate(List args) throws XPathFunctionException {
                return contains(args);
            }
        });

        addFunction("fromValue", 3, new XPathFunction() {
            @Override
            public Object evaluate(List args) throws XPathFunctionException {
                return fromValue(args);
            }
        });

        addFunction("toValue", 3, new XPathFunction() {
            @Override
            public Object evaluate(List args) throws XPathFunctionException {
                return toValue(args);
            }
        });

        addFunction("replace", 3, new XPathFunction() {
            @Override
            public Object evaluate(List args) throws XPathFunctionException {
                return replace(args);
            }
        });

        addFunction("has-result", 0, new XPathFunction() {
            @Override
            public Object evaluate(List args) throws XPathFunctionException {
                return FunctionResolver.this.buildHelper.hasResult();
            }
        });
    }

    /**
     * Create a new function.
     * @param name  Name of the function.
     * @param arity Number of arguments for function.
     * @param function the function itself.
     */
    public void addFunction(String name, int arity, XPathFunction function) {
        functions.add(new Entry(name, function, arity));
    }

    @Override
    public XPathFunction resolveFunction(QName functionName, int arity) {

        if (!functionName.getNamespaceURI().equals(FUNCTION_NAMESPACE_URI)) {
            return null;
        }

        String name = functionName.getLocalPart();
        for (Entry entry: functions) {
            if (entry.arity == arity && entry.name.equals(name)) {
                return entry.function;
            }
        }

        return null;
    }

    /** Implementation of case-ignoring dc:contains. */
    public Object contains(List args) throws XPathFunctionException {
        Object haystack = args.get(0);
        Object needle   = args.get(1);

        if (needle instanceof String) {
            needle = ((String)needle).toUpperCase();
        }

        try {
            if (haystack instanceof Collection) {
                return Boolean.valueOf(
                    ((Collection)haystack).contains(needle));
            }

            if (haystack instanceof Map) {
                return Boolean.valueOf(
                    ((Map)haystack).containsKey(needle));
            }

            if (haystack instanceof Object []) {
                for (Object straw: (Object [])haystack) {
                    if (straw.equals(needle)) {
                        return Boolean.TRUE;
                    }
                }
            }

            return Boolean.FALSE;
        }
        catch (Exception e) {
            log.error(e);
            throw new XPathFunctionException(e);
        }
    }

    /** Implementation for getting the minimum value of location or distance
     *  dc:fromValue.
     */
    public Object fromValue(List args) throws XPathFunctionException {
        Object mode      = args.get(0);
        Object locations = args.get(1);
        Object from      = args.get(2);

        if (!(mode instanceof String)){
            return -99999d;
        }

        if (mode.equals("locations")) {
            if (!(locations instanceof String)) {
                return -99999d;
            }
            String loc = ((String)locations).replace(" ", "");
            String[] split = loc.split(",");
            if (split.length < 1) {
                return -99999d;
            }
            try {
                double min = Double.parseDouble(split[0]);
                for (int i = 1; i < split.length; ++i) {
                    double v = Double.parseDouble(split[i]);
                    if (v < min) {
                        min = v;
                    }
                }
                return min;
            }
            catch (NumberFormatException nfe) {
                return -99999d;
            }
        }
        else if (mode.equals("distance")) {
            if (!(from instanceof String)) {
                return -99999d;
            }
            String f = (String)from;
            try {
                return Double.parseDouble(f);
            }
            catch(NumberFormatException nfe) {
                return -99999d;
            }
        }
        else {
            return -99999d;
        }
    }

    /** Implementation for getting the maximum value of location or distance
     *  dc:toValue.
     */
    public Object toValue(List args) throws XPathFunctionException {
        Object mode      = args.get(0);
        Object locations = args.get(1);
        Object to        = args.get(2);

        if (!(mode instanceof String)){
            return 99999d;
        }

        if (mode.equals("locations")) {
            if (!(locations instanceof String)) {
                return 99999d;
            }
            try {
                String loc = ((String)locations).replace(" ", "");
                String[] split = loc.split(",");
                if (split.length < 1) {
                    return 99999d;
                }
                double max = Double.parseDouble(split[0]);
                for (int i = 1; i < split.length; ++i) {
                    double v = Double.parseDouble(split[i]);
                    if (v > max) {
                        max = v;
                    }
                }
                return max;
            }
            catch (NumberFormatException nfe) {
                return 99999d;
            }
        }
        else if (mode.equals("distance")) {
            if (!(to instanceof String)) {
                return 99999d;
            }
            else {
                String t = (String)to;
                try {
                    return Double.parseDouble(t);
                }
                catch(NumberFormatException nfe) {
                    return 99999d;
                }
            }
        }
        else {
            return 99999d;
        }
    }

    /** Implementation for doing a string replace
     *  dc:replace
     */
    public Object replace(List args) throws XPathFunctionException {
        Object haystack    = args.get(0);
        Object needle      = args.get(1);
        Object replacement = args.get(2);

        if (needle instanceof String &&
            haystack instanceof String &&
            replacement instanceof String) {
            return ((String)haystack).replace(
                    (String)needle, (String)replacement);
        } else {
            return haystack;
        }
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org