sascha@998: package de.intevation.flys.artifacts.datacage.templating; sascha@998: teichmann@5608: import java.text.SimpleDateFormat; teichmann@4949: import java.util.ArrayList; sascha@998: import java.util.Collection; teichmann@5608: import java.util.Date; teichmann@4949: import java.util.List; sascha@998: import java.util.Map; sascha@998: aheinecke@5784: import java.lang.reflect.InvocationTargetException; aheinecke@5784: import java.lang.reflect.Method; aheinecke@5784: teichmann@4949: import javax.xml.namespace.QName; teichmann@4949: sascha@998: import javax.xml.xpath.XPathFunction; sascha@998: import javax.xml.xpath.XPathFunctionException; teichmann@4949: import javax.xml.xpath.XPathFunctionResolver; sascha@998: sascha@998: import org.apache.log4j.Logger; sascha@998: felix@4594: felix@4594: /** Resolves functions (e.g. dc:contains) in Datacage/Meta-Data system. */ sascha@998: public class FunctionResolver sascha@998: implements XPathFunctionResolver sascha@998: { felix@4594: /** Home logger. */ sascha@998: private static Logger log = Logger.getLogger(FunctionResolver.class); sascha@998: sascha@998: public static final String FUNCTION_NAMESPACE_URI = "dc"; sascha@998: teichmann@5604: public static final double FAR_AWAY = 99999d; teichmann@5604: sascha@998: public static final class Entry { sascha@998: sascha@998: String name; sascha@998: XPathFunction function; sascha@998: int arity; sascha@998: sascha@998: public Entry() { sascha@998: } sascha@998: sascha@998: public Entry(String name, XPathFunction function, int arity) { sascha@998: this.name = name; sascha@998: this.function = function; sascha@998: this.arity = arity; sascha@998: } sascha@998: } // class Entry sascha@998: felix@4594: /** List of functions. */ sascha@998: protected List functions; sascha@998: teichmann@5432: protected Builder.BuildHelper buildHelper; teichmann@5430: teichmann@5430: sascha@998: public FunctionResolver() { teichmann@5432: this(null); teichmann@5432: } teichmann@5432: teichmann@5432: public FunctionResolver(Builder.BuildHelper buildHelper) { teichmann@5432: this.buildHelper = buildHelper; teichmann@5432: sascha@998: functions = new ArrayList(); teichmann@5430: teichmann@5430: addFunction("contains", 2, new XPathFunction() { teichmann@5430: @Override teichmann@5430: public Object evaluate(List args) throws XPathFunctionException { teichmann@5430: return contains(args); teichmann@5430: } teichmann@5430: }); teichmann@5430: teichmann@5430: addFunction("fromValue", 3, new XPathFunction() { teichmann@5430: @Override teichmann@5430: public Object evaluate(List args) throws XPathFunctionException { teichmann@5430: return fromValue(args); teichmann@5430: } teichmann@5430: }); teichmann@5430: teichmann@5430: addFunction("toValue", 3, new XPathFunction() { teichmann@5430: @Override teichmann@5430: public Object evaluate(List args) throws XPathFunctionException { teichmann@5430: return toValue(args); teichmann@5430: } teichmann@5430: }); teichmann@5433: aheinecke@5561: addFunction("replace", 3, new XPathFunction() { aheinecke@5561: @Override aheinecke@5561: public Object evaluate(List args) throws XPathFunctionException { aheinecke@5561: return replace(args); aheinecke@5561: } aheinecke@5561: }); aheinecke@5561: teichmann@5433: addFunction("has-result", 0, new XPathFunction() { teichmann@5433: @Override teichmann@5433: public Object evaluate(List args) throws XPathFunctionException { teichmann@5433: return FunctionResolver.this.buildHelper.hasResult(); teichmann@5433: } teichmann@5433: }); teichmann@5608: teichmann@5608: addFunction("date-format", 2, new XPathFunction() { teichmann@5608: @Override teichmann@5608: public Object evaluate(List args) throws XPathFunctionException { teichmann@5608: return dateFormat(args); teichmann@5608: } teichmann@5608: }); sascha@998: } sascha@998: felix@4594: /** felix@4594: * Create a new function. felix@4594: * @param name Name of the function. felix@4594: * @param arity Number of arguments for function. felix@4594: * @param function the function itself. felix@4594: */ sascha@998: public void addFunction(String name, int arity, XPathFunction function) { sascha@998: functions.add(new Entry(name, function, arity)); sascha@998: } sascha@998: sascha@998: @Override sascha@998: public XPathFunction resolveFunction(QName functionName, int arity) { sascha@998: sascha@998: if (!functionName.getNamespaceURI().equals(FUNCTION_NAMESPACE_URI)) { sascha@998: return null; sascha@998: } sascha@998: sascha@998: String name = functionName.getLocalPart(); sascha@998: for (Entry entry: functions) { sascha@998: if (entry.arity == arity && entry.name.equals(name)) { sascha@998: return entry.function; sascha@998: } sascha@998: } sascha@998: sascha@998: return null; sascha@998: } teichmann@5430: teichmann@5430: /** Implementation of case-ignoring dc:contains. */ teichmann@5430: public Object contains(List args) throws XPathFunctionException { teichmann@5430: Object haystack = args.get(0); teichmann@5430: Object needle = args.get(1); teichmann@5430: teichmann@5630: if (needle instanceof String && !(haystack instanceof String)) { teichmann@5430: needle = ((String)needle).toUpperCase(); teichmann@5430: } teichmann@5430: teichmann@5430: try { teichmann@5430: if (haystack instanceof Collection) { teichmann@5430: return Boolean.valueOf( teichmann@5430: ((Collection)haystack).contains(needle)); teichmann@5430: } teichmann@5430: teichmann@5430: if (haystack instanceof Map) { teichmann@5430: return Boolean.valueOf( teichmann@5430: ((Map)haystack).containsKey(needle)); teichmann@5430: } teichmann@5430: teichmann@5430: if (haystack instanceof Object []) { teichmann@5430: for (Object straw: (Object [])haystack) { teichmann@5430: if (straw.equals(needle)) { teichmann@5430: return Boolean.TRUE; teichmann@5430: } teichmann@5430: } teichmann@5430: } teichmann@5430: teichmann@5629: if (haystack instanceof String && needle instanceof String) { teichmann@5629: String h = (String)haystack; teichmann@5629: String n = (String)needle; teichmann@5629: return h.contains(n); teichmann@5629: } teichmann@5629: teichmann@5430: return Boolean.FALSE; teichmann@5430: } teichmann@5430: catch (Exception e) { teichmann@5430: log.error(e); teichmann@5430: throw new XPathFunctionException(e); teichmann@5430: } teichmann@5430: } teichmann@5430: teichmann@5430: /** Implementation for getting the minimum value of location or distance teichmann@5430: * dc:fromValue. teichmann@5430: */ teichmann@5430: public Object fromValue(List args) throws XPathFunctionException { teichmann@5430: Object mode = args.get(0); teichmann@5430: Object locations = args.get(1); teichmann@5430: Object from = args.get(2); teichmann@5430: teichmann@5430: if (!(mode instanceof String)){ teichmann@5604: return -FAR_AWAY; teichmann@5430: } teichmann@5430: teichmann@5430: if (mode.equals("locations")) { teichmann@5430: if (!(locations instanceof String)) { teichmann@5604: return -FAR_AWAY; teichmann@5430: } teichmann@5430: String loc = ((String)locations).replace(" ", ""); teichmann@5430: String[] split = loc.split(","); teichmann@5430: if (split.length < 1) { teichmann@5604: return -FAR_AWAY; teichmann@5430: } teichmann@5430: try { teichmann@5430: double min = Double.parseDouble(split[0]); teichmann@5430: for (int i = 1; i < split.length; ++i) { teichmann@5430: double v = Double.parseDouble(split[i]); teichmann@5430: if (v < min) { teichmann@5430: min = v; teichmann@5430: } teichmann@5430: } teichmann@5430: return min; teichmann@5430: } teichmann@5430: catch (NumberFormatException nfe) { teichmann@5604: return -FAR_AWAY; teichmann@5430: } teichmann@5430: } teichmann@5430: else if (mode.equals("distance")) { teichmann@5430: if (!(from instanceof String)) { teichmann@5604: return -FAR_AWAY; teichmann@5430: } teichmann@5430: String f = (String)from; teichmann@5430: try { teichmann@5430: return Double.parseDouble(f); teichmann@5430: } teichmann@5430: catch(NumberFormatException nfe) { teichmann@5604: return -FAR_AWAY; teichmann@5430: } teichmann@5430: } teichmann@5430: else { teichmann@5604: return -FAR_AWAY; teichmann@5430: } teichmann@5430: } teichmann@5430: teichmann@5430: /** Implementation for getting the maximum value of location or distance teichmann@5430: * dc:toValue. teichmann@5430: */ teichmann@5430: public Object toValue(List args) throws XPathFunctionException { teichmann@5430: Object mode = args.get(0); teichmann@5430: Object locations = args.get(1); teichmann@5430: Object to = args.get(2); teichmann@5430: teichmann@5430: if (!(mode instanceof String)){ teichmann@5604: return FAR_AWAY; teichmann@5430: } teichmann@5430: teichmann@5430: if (mode.equals("locations")) { teichmann@5430: if (!(locations instanceof String)) { teichmann@5604: return FAR_AWAY; teichmann@5430: } teichmann@5430: try { teichmann@5430: String loc = ((String)locations).replace(" ", ""); teichmann@5430: String[] split = loc.split(","); teichmann@5430: if (split.length < 1) { teichmann@5604: return FAR_AWAY; teichmann@5430: } teichmann@5430: double max = Double.parseDouble(split[0]); teichmann@5430: for (int i = 1; i < split.length; ++i) { teichmann@5430: double v = Double.parseDouble(split[i]); teichmann@5430: if (v > max) { teichmann@5430: max = v; teichmann@5430: } teichmann@5430: } teichmann@5430: return max; teichmann@5430: } teichmann@5430: catch (NumberFormatException nfe) { teichmann@5604: return FAR_AWAY; teichmann@5430: } teichmann@5430: } teichmann@5430: else if (mode.equals("distance")) { teichmann@5430: if (!(to instanceof String)) { teichmann@5604: return FAR_AWAY; teichmann@5430: } teichmann@5430: else { teichmann@5430: String t = (String)to; teichmann@5430: try { teichmann@5430: return Double.parseDouble(t); teichmann@5430: } teichmann@5430: catch(NumberFormatException nfe) { teichmann@5604: return FAR_AWAY; teichmann@5430: } teichmann@5430: } teichmann@5430: } teichmann@5430: else { teichmann@5604: return FAR_AWAY; teichmann@5430: } teichmann@5430: } aheinecke@5561: aheinecke@5561: /** Implementation for doing a string replace aheinecke@5561: * dc:replace aheinecke@5561: */ aheinecke@5561: public Object replace(List args) throws XPathFunctionException { aheinecke@5561: Object haystack = args.get(0); aheinecke@5561: Object needle = args.get(1); aheinecke@5561: Object replacement = args.get(2); aheinecke@5561: aheinecke@5561: if (needle instanceof String && aheinecke@5561: haystack instanceof String && aheinecke@5561: replacement instanceof String) { aheinecke@5561: return ((String)haystack).replace( aheinecke@5561: (String)needle, (String)replacement); aheinecke@5561: } else { aheinecke@5561: return haystack; aheinecke@5561: } aheinecke@5561: } teichmann@5608: teichmann@5608: public Object dateFormat(List args) throws XPathFunctionException { teichmann@5608: Object pattern = args.get(0); teichmann@5608: Object date = args.get(1); aheinecke@5784: aheinecke@5784: try { aheinecke@5784: // Oracle does not return a date object but an oracle.sql.TIMESTAMP aheinecke@5784: Method meth = date.getClass().getMethod("dateValue", new Class[] {}); aheinecke@5784: date = meth.invoke(date, new Object [] {}); aheinecke@5784: } catch (IllegalArgumentException e) { aheinecke@5784: } catch (IllegalAccessException e) { aheinecke@5784: } catch (InvocationTargetException e) { aheinecke@5784: } catch (NoSuchMethodException e) { aheinecke@5784: } teichmann@5608: if (pattern instanceof String && date instanceof Date) { teichmann@5608: try { teichmann@5608: // TODO: Take locale into account. teichmann@5608: return new SimpleDateFormat((String)pattern).format((Date)date); teichmann@5608: } teichmann@5608: catch (IllegalArgumentException iae) { teichmann@5608: throw new XPathFunctionException(iae); teichmann@5608: } teichmann@5608: } teichmann@5608: return ""; teichmann@5608: } sascha@998: } sascha@998: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :