svn commit: r729583 [1/2] - in /ofbiz/trunk/framework/base: lib/ src/org/ofbiz/base/util/collections/ src/org/ofbiz/base/util/string/

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r729583 [1/2] - in /ofbiz/trunk/framework/base: lib/ src/org/ofbiz/base/util/collections/ src/org/ofbiz/base/util/string/

adrianc
Author: adrianc
Date: Fri Dec 26 18:31:05 2008
New Revision: 729583

URL: http://svn.apache.org/viewvc?rev=729583&view=rev
Log:
Improved UEL implementation. FlexibleMapAccessor.java uses the UEL library instead of the home-grown parser.

This commit includes the JUEL library taken from CVS - not the 2.1.0 zip file download. It includes the author's modifications to support auto-vivify.

Added:
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/JuelConnector.java   (with props)
Modified:
    ofbiz/trunk/framework/base/lib/juel-2.1.0.jar
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/FlexibleMapAccessor.java
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelFunctions.java   (contents, props changed)
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelUtil.java

Modified: ofbiz/trunk/framework/base/lib/juel-2.1.0.jar
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/lib/juel-2.1.0.jar?rev=729583&r1=729582&r2=729583&view=diff
==============================================================================
Binary files - no diff available.

Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/FlexibleMapAccessor.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/FlexibleMapAccessor.java?rev=729583&r1=729582&r2=729583&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/FlexibleMapAccessor.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/FlexibleMapAccessor.java Fri Dec 26 18:31:05 2008
@@ -19,16 +19,11 @@
 package org.ofbiz.base.util.collections;
 
 import java.io.Serializable;
-import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
-import javolution.util.FastList;
-import javolution.util.FastMap;
-
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilGenerics;
-import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.cache.UtilCache;
 import org.ofbiz.base.util.string.UelUtil;
 
@@ -47,8 +42,7 @@
     protected static final FlexibleMapAccessor nullFma = new FlexibleMapAccessor(null);
 
     protected final String original;
-    protected final String bracketedOriginal;
-    protected final ExpressionNode node;
+    protected String bracketedOriginal;
     protected boolean isAscending = true;
 
     protected FlexibleMapAccessor(String name) {
@@ -61,14 +55,10 @@
                 this.isAscending = true;
                 name = name.substring(1);
             }
+            this.bracketedOriginal = openBracket + UelUtil.prepareExpression(name) + closeBracket;
         }
-        String bracketedOriginal = openBracket + name + closeBracket;
-        // JUEL library doesn't like "+" in list indexes
-        bracketedOriginal = bracketedOriginal.replace("[+", "[");
-        this.bracketedOriginal = bracketedOriginal;
-        this.node = parseExpression(name);
         if (Debug.verboseOn()) {
-          Debug.logVerbose("FlexibleMapAccessor created, original = " + this.original + ", node = " + this.node, module);
+            Debug.logVerbose("FlexibleMapAccessor created, original = " + this.original, module);
         }
     }
     
@@ -78,7 +68,7 @@
      */
     @SuppressWarnings("unchecked")
     public static <T> FlexibleMapAccessor<T> getInstance(String original) {
-        if (original == null || original.length() == 0) {
+        if (original == null || original.length() == 0 || "null".equals(original)) {
             return nullFma;
         }
         FlexibleMapAccessor fma = fmaCache.get(original);
@@ -112,16 +102,7 @@
      * @return the found value
      */
     public T get(Map<String, ? extends Object> base) {
-        if (this.isEmpty()) {
-            return null;
-        }
-        Object obj = null;
-        try {
-            obj = UelUtil.evaluate(base, this.bracketedOriginal);
-        } catch (Exception e) {
-            Debug.logVerbose("Error evaluating expression: " + e, module);
-        }
-        return UtilGenerics.<T>cast(obj);
+        return get(base, null);
     }
 
     /** Given the name based information in this accessor, get the value from the passed in Map.
@@ -132,13 +113,25 @@
      * @return the found value
      */
     public T get(Map<String, ? extends Object> base, Locale locale) {
-        if (this.isEmpty()) {
+        if (base == null || this.isEmpty()) {
             return null;
         }
-        Object obj = this.node.get(base, UtilGenerics.<Map<String, Object>>cast(base), locale);
+        if (!base.containsKey(UelUtil.localizedMapLocaleKey) && locale != null) {
+            Map<String, Object> writableMap = UtilGenerics.cast(base);
+            writableMap.put(UelUtil.localizedMapLocaleKey, locale);
+        }
+        Object obj = null;
+        try {
+            obj = UelUtil.evaluate(base, this.bracketedOriginal);
+        } catch (Exception e) {
+            // PropertyNotFound exceptions are common, so logging verbose
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("UEL exception while getting value: " + e + ", original = " + this.original, module);
+            }
+        }
         return UtilGenerics.<T>cast(obj);
     }
-    
+
     /** Given the name based information in this accessor, put the value in the passed in Map.
      * If the brackets for a list are empty the value will be appended to the list,
      * otherwise the value will be set in the position of the number in the brackets.
@@ -154,7 +147,11 @@
         if (base == null) {
             throw new IllegalArgumentException("Cannot put a value in a null base Map");
         }
-        this.node.put(base, base, value);
+        try {
+            UelUtil.setValue(base, this.bracketedOriginal, value == null ? Object.class : value.getClass(), value);
+        } catch (Exception e) {
+            Debug.logInfo("UEL exception while setting value: " + e + ", original = " + this.original + ", value = " + value, module);
+        }
     }
     
     /** Given the name based information in this accessor, remove the value from the passed in Map.
@@ -165,7 +162,17 @@
         if (this.isEmpty()) {
             return null;
         }
-        return UtilGenerics.<T>cast(this.node.remove(base, UtilGenerics.<Map<String, Object>>cast(base)));
+        T object = get(base);
+        if (object == null) {
+            return null;
+        }
+        try {
+            Map<String, Object> writableMap = UtilGenerics.cast(base);
+            UelUtil.removeValue(writableMap, this.bracketedOriginal);
+        } catch (Exception e) {
+            Debug.logInfo("UEL exception while removing value: " + e + ", original = " + this.original, module);
+        }
+        return object;
     }
     
     public String toString() {
@@ -193,353 +200,4 @@
     public int hashCode() {
         return this.original == null ? super.hashCode() : this.original.hashCode();
     }
-    
-    protected static ExpressionNode parseExpression(String original) {
-        if (original == null || original.length() == 0) {
-            return null;
-        }
-        String str = original;
-        int end = original.indexOf(".");
-        if (end != -1) {
-            int openBrace = original.indexOf("[");
-            if (openBrace != -1 && openBrace < end) {
-                end = original.indexOf(']', openBrace);
-                str = original.substring(0, end + 1);
-            } else {
-                str = original.substring(0, end);
-            }
-        }
-        ExpressionNode node = null;
-        if (str.contains("[")) {
-            node = parseBracketedExpression(str);
-        } else {
-            node = new MapElementNode(str);
-        }
-        if (end != -1) {
-            node.setChild(parseExpression(original.substring(end + 1)));
-        }
-        return node;
-    }
-
-    protected static ExpressionNode parseBracketedExpression(String original) {
-        boolean isAddAtEnd = false;
-        boolean isAddAtIndex = false;
-        int listIndex = -1;
-        int openBrace = original.indexOf('[');
-        int closeBrace = (openBrace == -1 ? -1 : original.indexOf(']', openBrace));
-        if (closeBrace == -1) {
-            throw new RuntimeException("Missing ] in expression: " + original);
-        }
-        String base = original.substring(0, openBrace);
-        String property = original.substring(openBrace+1, closeBrace).trim();
-        if (property.length() == 0) {
-            isAddAtEnd = true;
-        } else if (property.charAt(0) == '+') {
-            property = property.substring(1);
-            isAddAtIndex = true;
-        }
-        try{
-            listIndex = Integer.parseInt(property);
-        } catch (Exception e) {}
-        if (listIndex != -1 || isAddAtEnd || isAddAtIndex) {
-            return new ListNode(original, base, isAddAtEnd, isAddAtIndex, listIndex);
-        } else {
-            return new BracketNode(original, base, property);
-        }
-    }
-
-    /** Abstract class for the expression nodes. Expression nodes are separated
-     * by a period. <code>ExpressionNode</code> instances are connected as a
-     * singly-linked list - going from left to right in the expression. The last
-     * node has a <code>null</code> child.
-     */
-    protected static abstract class ExpressionNode implements Serializable {
-        protected final String original;
-        protected ExpressionNode child = null;
-        protected ExpressionNode(String original) {
-            this.original = original;
-        }
-        protected void setChild(ExpressionNode child) {
-            this.child = child;
-        }
-        protected abstract Object get(Map<String, ? extends Object> context, Map<String, Object> base, Locale locale);
-        protected abstract void put(Map<String, Object> context, Map<String, Object> base, Object value);
-        protected abstract Object remove(Map<String, ? extends Object> context, Map<String, Object> base);
-    }
-
-    /** Implementation of a <code>Map</code> element (<code>someMap.someElement</code>). */
-    protected static class MapElementNode extends ExpressionNode {
-        protected MapElementNode(String original) {
-            super(original);
-        }
-        public String toString() {
-            return "MapElementNode(" + this.original + ")" + (this.child == null ? "" : "." + this.child.toString());
-        }
-        protected Object get(Map<String, ? extends Object> context, Map<String, Object> base, Locale locale) {
-            String key = getExprString(context, this.original);
-            if (this.child == null) {
-                return legacyGet(base, key, locale);
-            } else {
-                Map<String, Object> thisElement = getMapPutElement(base, key, true);
-                return this.child.get(context, thisElement, locale);
-            }
-        }
-        protected void put(Map<String, Object> context, Map<String, Object> base, Object value) {
-            String key = getExprString(context, this.original);
-            if (this.child == null) {
-                base.put(key, value);
-            } else {
-                Map<String, Object> thisElement = getMapPutElement(base, key, true);
-                this.child.put(context, thisElement, value);
-            }
-        }
-        protected Object remove(Map<String, ? extends Object> context, Map<String, Object> base) {
-            String key = getExprString(context, this.original);
-            if (this.child == null) {
-                return base.remove(key);
-            } else {
-                Map<String, Object> thisElement = UtilGenerics.<Map<String, Object>>cast(base.get(key));
-                if (thisElement != null) {
-                    return this.child.remove(context, thisElement);
-                }
-            }
-            return null;
-        }
-    }
-
-    /** Implementation of a <code>List</code> element with a literal index
-     * (<code>someList[1]</code>). */
-    protected static class ListNode extends ExpressionNode {
-        protected final String key;
-        protected final boolean isAddAtEnd;
-        protected final boolean isAddAtIndex;
-        protected final int listIndex;
-        protected ListNode(String original, String base, boolean isAddAtEnd, boolean isAddAtIndex, int listIndex) {
-            super(original);
-            this.key = base;
-            this.isAddAtEnd = isAddAtEnd;
-            this.isAddAtIndex = isAddAtIndex;
-            this.listIndex = listIndex;
-        }
-        public String toString() {
-            return "ListNode(" + this.original + ")" + (this.child == null ? "" : "." + this.child.toString());
-        }
-        protected Object get(Map<String, ? extends Object> context, Map<String, Object> base, Locale locale) {
-            List<Object> list = getListElementFromMap(base, key, true);
-            if (this.child == null) {
-                return list.get(this.listIndex);
-            }
-            Map<String, Object> newBase = null;
-            try {
-                newBase = UtilGenerics.<Map<String, Object>>cast(list.get(this.listIndex));
-            } catch (Exception e) {
-                throw new RuntimeException("Variable is not a Map: " + this.original);
-            }
-            return this.child.get(context, newBase, locale);
-        }
-        protected void put(Map<String, Object> context, Map<String, Object> base, Object value) {
-            String key = getExprString(context, this.key);
-            List<Object> list = getListElementFromMap(base, key, true);
-            base.put(key, list);
-            if (this.child == null) {
-                if (this.isAddAtEnd) {
-                    list.add(value);
-                } else {
-                    if (this.isAddAtIndex) {
-                        list.add(this.listIndex, value);
-                    } else {
-                        list.set(this.listIndex, value);
-                    }
-                }
-                return;
-            }
-            Map<String, Object> newBase = null;
-            try {
-                newBase = UtilGenerics.<Map<String, Object>>cast(list.get(this.listIndex));
-            } catch (Exception e) {
-                throw new RuntimeException("Variable is not a Map: " + this.original);
-            }
-            this.child.put(context, newBase, value);
-        }
-        protected Object remove(Map<String, ? extends Object> context, Map<String, Object> base) {
-            String key = getExprString(context, this.key);
-            return removeList(getListElementFromMap(base, key, false), this.listIndex, context, this.child);
-        }
-    }
-
-    /** Implementation of a <code>Map</code> or <code>List</code> element with
-     * a variable property (<code>someElement[var]</code>). If <code>var</code>
-     * evaluates to an integer, then the element is treated as a <code>List</code>,
-     * otherwise it is treated as a <code>Map</code>.*/
-    protected static class BracketNode extends ExpressionNode {
-        // .base[property]
-        protected final String base;
-        protected final String property;
-        protected BracketNode(String original, String base, String property) {
-            super(original);
-            this.base = base;
-            this.property = property;
-        }
-        public String toString() {
-            return "BracketNode(" + this.original + ")" + (this.child == null ? "" : "." + this.child.toString());
-        }
-        protected Object get(Map<String, ? extends Object> context, Map<String, Object> base, Locale locale) {
-            String key = getExprString(context, this.base);
-            Object property = getProperty(context);
-            Integer index = UtilMisc.toIntegerObject(property);
-            if (index != null) {
-                // This node is a List
-                List<Object> list = getListElementFromMap(base, key, true);
-                if (this.child == null) {
-                    return list.get(index);
-                }
-                Map<String, Object> newBase = null;
-                try {
-                    newBase = UtilGenerics.<Map<String, Object>>cast(list.get(index));
-                } catch (Exception e) {
-                    throw new RuntimeException("Variable is not a Map: " + this.original);
-                }
-                return this.child.get(context, newBase, locale);
-            } else {
-                // This node is a Map
-                Map<String, Object> newBase = getMapPutElement(base, key, true);
-                String newKey = property.toString();
-                if (this.child == null) {
-                    return legacyGet(newBase, newKey, locale);
-                } else {
-                    Map<String, Object> thisElement = getMapPutElement(newBase, newKey, true);
-                    return this.child.get(context, thisElement, locale);
-                }
-            }
-        }
-        protected void put(Map<String, Object> context, Map<String, Object> base, Object value) {
-            String key = getExprString(context, this.base);
-            Object property = getProperty(context);
-            Integer index = UtilMisc.toIntegerObject(property);
-            if (index != null) {
-                // This node is a List
-                List<Object> list = getListElementFromMap(base, key, true);
-                base.put(key, list);
-                if (this.child == null) {
-                    list.set(index, value);
-                    return;
-                }
-                Map<String, Object> newBase = null;
-                try {
-                    newBase = UtilGenerics.<Map<String, Object>>cast(list.get(index));
-                } catch (Exception e) {
-                    throw new RuntimeException("Variable is not a Map: " + this.original);
-                }
-                this.child.put(context, newBase, value);
-            } else {
-                // This node is a Map
-                Map<String, Object> newBase = getMapPutElement(base, key, true);
-                String newKey = property.toString();
-                if (this.child == null) {
-                    newBase.put(newKey, value);
-                } else {
-                    Map<String, Object> thisElement = getMapPutElement(newBase, newKey, true);
-                    this.child.put(context, thisElement, value);
-                }
-            }
-        }
-        protected Object remove(Map<String, ? extends Object> context, Map<String, Object> base) {
-            String key = getExprString(context, this.base);
-            Object property = getProperty(context);
-            Integer index = UtilMisc.toIntegerObject(property);
-            if (index != null) {
-                // This node is a List
-                return removeList(getListElementFromMap(base, key, false), index, context, this.child);
-            } else {
-                // This node is a Map
-                Map<String, Object> newBase = UtilGenerics.<Map<String, Object>>cast(base.get(key));
-                if (newBase != null) {
-                    if (this.child == null) {
-                        String newKey = property.toString();
-                        return newBase.remove(newKey);
-                    } else {
-                        return this.child.remove(context, newBase);
-                    }
-                }
-                return null;
-            }
-        }
-        protected Object getProperty(Map<String, ? extends Object> context) {
-            String str = this.property;
-            if (!this.property.startsWith(openBracket)) {
-                str = openBracket + str + closeBracket;
-            }
-            Object obj = null;
-            try {
-                obj = UelUtil.evaluate(context, str);
-            } catch (Exception e) {}
-            if (obj == null) {
-                throw new RuntimeException("Variable " + this.property + " not found in expression " + original);
-            }
-            return obj;
-        }
-
-    }
-
-    /** Evaluates an expression, then converts the result <code>Object</code> to a <code>String</code>. */
-    protected static String getExprString(Map<String, ? extends Object> context, String expression) {
-        Object result = expression;
-        if (expression.startsWith(openBracket)) {
-            try {
-                result = UelUtil.evaluate(context, expression);
-            } catch (Exception e) {
-                throw new RuntimeException("Error while evaluating expression " + expression + ": " + e);
-            }
-        }
-        return result.toString();
-    }
-
-    /** Returns a <code>List</code> element contained in a <code>Map</code>. If <code>createIfMissing
-     * </code> is true, then the <code>List</code> is created if not found. */
-    protected static List<Object> getListElementFromMap(Map<String, ? extends Object> base, String key, boolean createIfMissing) {
-        List<Object> result = null;
-        try {
-            result = UtilGenerics.<List<Object>>cast(base.get(key));
-        } catch (Exception e) {
-            throw new RuntimeException("Variable is not a List: " + key);
-        }
-        if (result == null && createIfMissing) {
-            result = FastList.newInstance();
-        }
-        return result;
-    }
-
-    protected static Map<String, Object> getMapPutElement(Map<String, Object> base, String key, boolean createIfMissing) {
-        Map<String, Object> result = UtilGenerics.<Map<String, Object>>cast(base.get(key));
-        if (result == null && createIfMissing) {
-            result = FastMap.newInstance();
-            base.put(key, result);
-        }
-        return result;
-    }
-
-    protected static Object removeList(List<Object> list, int index, Map<String, ? extends Object> context, ExpressionNode child) {
-        if (list != null) {
-            if (child == null) {
-                return list.remove(index);
-            } else {
-                Map<String, Object> newBase = null;
-                try {
-                    newBase = UtilGenerics.<Map<String, Object>>cast(list.get(index));
-                } catch (Exception e) {}
-                if (newBase != null) {
-                    return child.remove(context, newBase);
-                }
-            }
-        }
-        return null;
-    }
-    
-    @SuppressWarnings("unchecked")
-    protected static Object legacyGet(Map<String, Object> map, String key, Locale locale) {
-        if (map instanceof LocalizedMap) {
-            return ((LocalizedMap)map).get(key, locale);
-        }
-        return map.get(key);
-    }
 }

Added: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/JuelConnector.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/JuelConnector.java?rev=729583&view=auto
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/JuelConnector.java (added)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/JuelConnector.java Fri Dec 26 18:31:05 2008
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.ofbiz.base.util.string;
+
+import javax.el.*;
+
+import de.odysseus.el.misc.LocalMessages;
+import de.odysseus.el.tree.*;
+import de.odysseus.el.tree.impl.ast.*;
+import de.odysseus.el.tree.impl.*;
+import de.odysseus.el.tree.impl.Parser.*;
+import de.odysseus.el.tree.impl.Scanner.*;
+
+import org.ofbiz.base.util.Debug;
+
+/** A facade class used to connect the OFBiz framework to the JUEL library.
+ *<p>The Unified Expression Language specification doesn't allow assignment of
+ * values to non-existent variables (auto-vivify) - but the OFBiz scripting
+ * languages do. This class modifies the JUEL library behavior to enable
+ * auto-vivify.</p>
+ */
+public class JuelConnector {
+    protected static final String module = JuelConnector.class.getName();
+    
+    /** Returns an <code>ExpressionFactory</code> instance.
+     * @return A customized <code>ExpressionFactory</code> instance
+     */
+    public static ExpressionFactory newExpressionFactory() {
+        return new de.odysseus.el.ExpressionFactoryImpl(new TreeStore(new ExtendedBuilder(), new Cache(1000)));
+    }
+
+    /** Custom <code>AstBracket</code> class that implements
+     * <code>List</code> or <code>Map</code> auto-vivify.
+     */
+    public static class ExtendedAstBracket extends AstBracket {
+        public ExtendedAstBracket(AstNode base, AstNode property, boolean lvalue, boolean strict) {
+            super(base, property, lvalue, strict);
+        }
+        public void setValue(Bindings bindings, ELContext context, Object value) throws ELException {
+            if (!lvalue) {
+                throw new ELException(LocalMessages.get("error.value.set.rvalue"));
+            }
+            Object base = null;
+            try {
+                base = prefix.eval(bindings, context);
+            } catch (Exception e) {}
+            Object property = getProperty(bindings, context);
+            if (property == null && strict) {
+                throw new PropertyNotFoundException(LocalMessages.get("error.property.property.notfound", "null", base));
+            }
+            if (base == null) {
+                base = UelUtil.autoVivifyListOrMap(property);
+                if (Debug.verboseOn()) {
+                    Debug.logVerbose("ExtendedAstBracket.setValue auto-vivify base: " + base + ", property = " + property, module);
+                }
+                prefix.setValue(bindings, context, base);
+            }
+            context.getELResolver().setValue(context, base, property, value);
+            if (!context.isPropertyResolved()) {
+                throw new PropertyNotFoundException(LocalMessages.get("error.property.property.notfound", property, base));
+            }
+        }
+    }
+
+    /** Custom <code>AstDot</code> class that implements
+     * <code>List</code> or <code>Map</code> auto-vivify.
+     */
+    public static class ExtendedAstDot extends AstDot {
+        public ExtendedAstDot(AstNode base, String property, boolean lvalue) {
+            super(base, property, lvalue);
+        }
+        public void setValue(Bindings bindings, ELContext context, Object value) throws ELException {
+            if (!lvalue) {
+                throw new ELException(LocalMessages.get("error.value.set.rvalue"));
+            }
+            Object base = null;
+            try {
+                base = prefix.eval(bindings, context);
+            } catch (Exception e) {}
+            Object property = getProperty(bindings, context);
+            if (property == null && strict) {
+                throw new PropertyNotFoundException(LocalMessages.get("error.property.property.notfound", "null", base));
+            }
+            if (base == null) {
+                base = UelUtil.autoVivifyListOrMap(property);
+                if (Debug.verboseOn()) {
+                    Debug.logVerbose("ExtendedAstDot.setValue auto-vivify base: " + base + ", property = " + property, module);
+                }
+                prefix.setValue(bindings, context, base);
+            }
+            context.getELResolver().setValue(context, base, property, value);
+            if (!context.isPropertyResolved()) {
+                throw new PropertyNotFoundException(LocalMessages.get("error.property.property.notfound", property, base));
+            }
+        }
+    }
+    
+    /** Custom <code>Parser</code> class needed to implement auto-vivify. */
+    protected static class ExtendedParser extends Parser {
+        public ExtendedParser(Builder context, String input) {
+            super(context, input);
+        }
+        protected AstBracket createAstBracket(AstNode base, AstNode property, boolean lvalue, boolean strict) {
+            return new ExtendedAstBracket(base, property, lvalue, strict);
+        }
+        protected AstDot createAstDot(AstNode base, String property, boolean lvalue) {
+            return new ExtendedAstDot(base, property, lvalue);
+        }
+    }
+
+    /** Custom <code>Builder</code> class needed to implement a custom parser. */
+    @SuppressWarnings("serial")
+    protected static class ExtendedBuilder extends Builder {
+        public Tree build(String expression) throws ELException {
+            try {
+                return new ExtendedParser(this, expression).tree();
+            } catch (ScanException e) {
+                throw new ELException(LocalMessages.get("error.build", expression, e.getMessage()));
+            } catch (ParseException e) {
+                throw new ELException(LocalMessages.get("error.build", expression, e.getMessage()));
+            }
+        }
+    }
+}

Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/JuelConnector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/JuelConnector.java
------------------------------------------------------------------------------
    svn:keywords = "Date Rev Author URL Id"

Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/JuelConnector.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelFunctions.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelFunctions.java?rev=729583&r1=729582&r2=729583&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelFunctions.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelFunctions.java Fri Dec 26 18:31:05 2008
@@ -1,371 +1,371 @@
-/*******************************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *******************************************************************************/
-package org.ofbiz.base.util.string;
-
-import java.lang.reflect.Method;
-import java.text.DateFormat;
-import java.util.Collection;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-import java.sql.Timestamp;
-import javax.el.*;
-
-import javolution.util.FastMap;
-
-import org.ofbiz.base.util.Debug;
-import org.ofbiz.base.util.UtilDateTime;
-
-/** Implements Unified Expression Language functions.
- * <p>Built-in functions are divided into a number of
- * namespace prefixes:</p>
- * <table border="1">
- * <tr><td colspan="2"><b><code>date:</code> contains miscellaneous date/time functions</b></td></tr>
- * <tr><td><code>date:second(Timestamp, TimeZone, Locale)</code></td><td>Returns the second value of <code>Timestamp</code> (0 - 59).</td></tr>
- * <tr><td><code>date:minute(Timestamp, TimeZone, Locale)</code></td><td>Returns the minute value of <code>Timestamp</code> (0 - 59).</td></tr>
- * <tr><td><code>date:hour(Timestamp, TimeZone, Locale)</code></td><td>Returns the hour value of <code>Timestamp</code> (0 - 23).</td></tr>
- * <tr><td><code>date:dayOfMonth(Timestamp, TimeZone, Locale)</code></td><td>Returns the day of month value of <code>Timestamp</code> (1 - 31).</td></tr>
- * <tr><td><code>date:dayOfWeek(Timestamp, TimeZone, Locale)</code></td><td>Returns the day of week value of <code>Timestamp</code> (Sunday = 1, Saturday = 7).</td></tr>
- * <tr><td><code>date:dayOfYear(Timestamp, TimeZone, Locale)</code></td><td>Returns the day of year value of <code>Timestamp</code>.</td></tr>
- * <tr><td><code>date:week(Timestamp, TimeZone, Locale)</code></td><td>Returns the week value of <code>Timestamp</code>.</td></tr>
- * <tr><td><code>date:month(Timestamp, TimeZone, Locale)</code></td><td>Returns the month value of <code>Timestamp</code> (January = 0, December = 11).</td></tr>
- * <tr><td><code>date:year(Timestamp, TimeZone, Locale)</code></td><td>Returns the year value of <code>Timestamp</code>.</td></tr>
- * <tr><td><code>date:dayStart(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to start of day.</td></tr>
- * <tr><td><code>date:dayEnd(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to end of day.</td></tr>
- * <tr><td><code>date:weekStart(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to start of week.</td></tr>
- * <tr><td><code>date:weekEnd(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to end of week.</td></tr>
- * <tr><td><code>date:monthStart(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to start of month.</td></tr>
- * <tr><td><code>date:monthEnd(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to end of month.</td></tr>
- * <tr><td><code>date:yearStart(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to start of year.</td></tr>
- * <tr><td><code>date:yearEnd(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to end of year.</td></tr>
- * <tr><td><code>date:dateStr(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> as a date <code>String</code> (yyyy-mm-dd).</td></tr>
- * <tr><td><code>date:dateTimeStr(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> as a date-time <code>String</code> (yyyy-mm-dd hh:mm).</td></tr>
- * <tr><td><code>date:timeStr(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> as a time <code>String</code> (hh:mm).</td></tr>
- * <tr><td><code>date:nowTimestamp()</code></td><td>Returns <code>Timestamp </code> for right now<code>String</code>.</td></tr>
- * <tr><td colspan="2"><b><code>math:</code> maps to <code>java.lang.Math</code></b></td></tr>
- * <tr><td><code>math:absDouble(double)</code></td><td>Returns the absolute value of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:absFloat(float)</code></td><td>Returns the absolute value of a <code>float</code> value.</td></tr>
- * <tr><td><code>math:absInt(int)</code></td><td>Returns the absolute value of an <code>int</code> value.</td></tr>
- * <tr><td><code>math:absLong(long)</code></td><td>Returns the absolute value of a <code>long</code> value.</td></tr>
- * <tr><td><code>math:acos(double)</code></td><td>Returns the arc cosine of an angle, in the range of 0.0 through <i>pi</i>.</td></tr>
- * <tr><td><code>math:asin(double)</code></td><td>Returns the arc sine of an angle, in the range of -<i>pi</i>/2 through <i>pi</i>/2.</td></tr>
- * <tr><td><code>math:atan(double)</code></td><td>Returns the arc tangent of an angle, in the range of -<i>pi</i>/2 through <i>pi</i>/2.</td></tr>
- * <tr><td><code>math:atan2(double, double)</code></td><td>Converts rectangular coordinates (<code>x</code>,&nbsp;<code>y</code>) to polar (r,&nbsp;<i>theta</i>).</td></tr>
- * <tr><td><code>math:cbrt(double)</code></td><td>Returns the cube root of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:ceil(double)</code></td><td>Returns the smallest (closest to negative infinity) <code>double</code> value that is greater than or equal to the argument and is equal to a mathematical integer.</td></tr>
- * <tr><td><code>math:cos(double)</code></td><td>Returns the trigonometric cosine of an angle.</td></tr>
- * <tr><td><code>math:cosh(double)</code></td><td>Returns the hyperbolic cosine of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:exp(double)</code></td><td>Returns Euler's number <i>e</i> raised to the power of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:expm1(double)</code></td><td>Returns <i>e</i><sup>x</sup>&nbsp;-1.</td></tr>
- * <tr><td><code>math:floor(double)</code></td><td>Returns the largest (closest to positive infinity) <code>double</code> value that is less than or equal to the argument and is equal to a mathematical integer.</td></tr>
- * <tr><td><code>math:hypot(double, double)</code></td><td>Returns sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>) without intermediate overflow or underflow.</td></tr>
- * <tr><td><code>math:IEEEremainder(double, double)</code></td><td>Computes the remainder operation on two arguments as prescribed by the IEEE 754 standard.</td></tr>
- * <tr><td><code>math:log(double)</code></td><td>Returns the natural logarithm (base <i>e</i>) of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:log10(double)</code></td><td>Returns the base 10 logarithm of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:log1p(double)</code></td><td>Returns the natural logarithm of the sum of the argument and 1.</td></tr>
- * <tr><td><code>math:maxDouble(double, double)</code></td><td>Returns the greater of two <code>double</code> values.</td></tr>
- * <tr><td><code>math:maxFloat(float, float)</code></td><td>Returns the greater of two <code>float</code> values.</td></tr>
- * <tr><td><code>math:maxInt(int, int)</code></td><td>Returns the greater of two <code>int</code> values.</td></tr>
- * <tr><td><code>math:maxLong(long, long)</code></td><td>Returns the greater of two <code>long</code> values.</td></tr>
- * <tr><td><code>math:minDouble(double, double)</code></td><td>Returns the smaller of two <code>double</code> values.</td></tr>
- * <tr><td><code>math:minFloat(float, float)</code></td><td>Returns the smaller of two <code>float</code> values.</td></tr>
- * <tr><td><code>math:minInt(int, int)</code></td><td>Returns the smaller of two <code>int</code> values.</td></tr>
- * <tr><td><code>math:minLong(long, long)</code></td><td>Returns the smaller of two <code>long</code> values.</td></tr>
- * <tr><td><code>math:pow(double, double)</code></td><td>Returns the value of the first argument raised to the power of the second argument.</td></tr>
- * <tr><td><code>math:random()</code></td><td>Returns a <code>double</code> value with a positive sign, greater than or equal to <code>0.0</code> and less than <code>1.0</code>.</td></tr>
- * <tr><td><code>math:rint(double)</code></td><td>Returns the <code>double</code> value that is closest in value to the argument and is equal to a mathematical integer.</td></tr>
- * <tr><td><code>math:roundDouble(double)</code></td><td>Returns the closest <code>long</code> to the argument.</td></tr>
- * <tr><td><code>math:roundFloat(float)</code></td><td>Returns the closest <code>int</code> to the argument.</td></tr>
- * <tr><td><code>math:signumDouble(double)</code></td><td>Returns the signum function of the argument; zero if the argument is zero, 1.0 if the argument is greater than zero, -1.0 if the argument is less than zero.</td></tr>
- * <tr><td><code>math:signumFloat(float)</code></td><td>Returns the signum function of the argument; zero if the argument is zero, 1.0f if the argument is greater than zero, -1.0f if the argument is less than zero.</td></tr>
- * <tr><td><code>math:sin(double)</code></td><td>Returns the trigonometric sine of an angle.</td></tr>
- * <tr><td><code>math:sinh(double)</code></td><td>Returns the hyperbolic sine of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:sqrt(double)</code></td><td>Returns the correctly rounded positive square root of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:tan(double)</code></td><td>Returns the trigonometric tangent of an angle.</td></tr>
- * <tr><td><code>math:tanh(double)</code></td><td>Returns the hyperbolic tangent of a <code>double</code> value.</td></tr>
- * <tr><td><code>math:toDegrees(double)</code></td><td>Converts an angle measured in radians to an approximately equivalent angle measured in degrees.</td></tr>
- * <tr><td><code>math:toRadians(double)</code></td><td>Converts an angle measured in degrees to an approximately equivalent angle measured in radians.</td></tr>
- * <tr><td><code>math:ulpDouble(double)</code></td><td>Returns the size of an ulp (units in the last place) of the argument.</td></tr>
- * <tr><td><code>math:ulpFloat(float)</code></td><td>Returns the size of an ulp (units in the last place) of the argument.</td></tr>
- * <tr><td colspan="2"><b><code>str:</code> maps to <code>java.lang.String</code></b></td></tr>
- * <tr><td><code>str:endsWith(String, String)</code></td><td>Returns <code>true</code> if this string ends with the specified suffix.</td></tr>
- * <tr><td><code>str:indexOf(String, String)</code></td><td>Returns the index within this string of the first occurrence of the specified substring.</td></tr>
- * <tr><td><code>str:lastIndexOf(String, String)</code></td><td>Returns the index within this string of the last occurrence of the specified character.</td></tr>
- * <tr><td><code>str:length(String)</code></td><td>Returns the length of this string.</td></tr>
- * <tr><td><code>str:replace(String, String, String)</code></td><td>Replaces each substring of this string that matches the literal target sequence with the specified literal replacement sequence.</td></tr>
- * <tr><td><code>str:replaceAll(String, String, String)</code></td><td>Replaces each substring of this string that matches the given regular expression with the given replacement.</td></tr>
- * <tr><td><code>str:replaceFirst(String, String, String)</code></td><td>Replaces the first substring of this string that matches the given regular expression with the given replacement.</td></tr>
- * <tr><td><code>str:startsWith(String, String)</code></td><td>Returns <code>true</code> if this string starts with the specified prefix.</td></tr>
- * <tr><td><code>str:endstring(String, int)</code></td><td>Returns a new string that is a substring of this string. The substring begins with the character at the specified index and extends to the end of this string.</td></tr>
- * <tr><td><code>str:substring(String, int, int)</code></td><td>Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex.</td></tr>
- * <tr><td><code>str:toString(Object)</code></td><td>Converts <code>Object</code> to a <code>String</code> - bypassing localization.</td></tr>
- * <tr><td><code>str:trim(String)</code></td><td>Returns a copy of the string, with leading and trailing whitespace omitted.</td></tr>
- * <tr><td colspan="2"><b><code>sys:</code> maps to <code>java.lang.System</code></b></td></tr>
- * <tr><td><code>sys:getenv(String)</code></td><td>Gets the value of the specified environment variable.</td></tr>
- * <tr><td><code>sys:getProperty(String)</code></td><td>Gets the system property indicated by the specified key.</td></tr>
- * <tr><td colspan="2"><b><code>util:</code> contains miscellaneous utility functions</b></td></tr>
- * <tr><td><code>util:defaultLocale()</code></td><td>Returns the default <code>Locale</code>.</td></tr>
- * <tr><td><code>util:defaultTimeZone()</code></td><td>Returns the default <code>TimeZone</code>.</td></tr>
- * <tr><td><code>util:size(Object)</code></td><td>Returns the size of <code>Maps</code>,
- * <code>Collections</code>, and <code>Strings</code>. Invalid <code>Object</code> types return -1.</td></tr>
- * </table>
- */
-public class UelFunctions {
-
-    public static final String module = UelFunctions.class.getName();
-    protected static final FunctionMapper functionMapper = new Functions();
-
-    /** Returns a <code>FunctionMapper</code> instance.
-     * @return <code>FunctionMapper</code> instance
-     */
-    public static FunctionMapper getFunctionMapper() {
-        return functionMapper;
-    }
-
-    protected static class Functions extends FunctionMapper {
-        protected final Map<String, Method> functionMap = FastMap.newInstance();
-        public Functions() {
-            try {
-                this.functionMap.put("date:second", UtilDateTime.class.getMethod("getSecond", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:minute", UtilDateTime.class.getMethod("getMinute", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:hour", UtilDateTime.class.getMethod("getHour", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:dayOfMonth", UtilDateTime.class.getMethod("getDayOfMonth", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:dayOfWeek", UtilDateTime.class.getMethod("getDayOfWeek", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:dayOfYear", UtilDateTime.class.getMethod("getDayOfYear", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:week", UtilDateTime.class.getMethod("getWeek", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:month", UtilDateTime.class.getMethod("getMonth", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:year", UtilDateTime.class.getMethod("getYear", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:dayStart", UtilDateTime.class.getMethod("getDayStart", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:dayEnd", UtilDateTime.class.getMethod("getDayEnd", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:weekStart", UtilDateTime.class.getMethod("getWeekStart", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:weekEnd", UtilDateTime.class.getMethod("getWeekEnd", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:monthStart", UtilDateTime.class.getMethod("getMonthStart", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:monthEnd", UtilDateTime.class.getMethod("getMonthEnd", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:yearStart", UtilDateTime.class.getMethod("getYearStart", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:yearEnd", UtilDateTime.class.getMethod("getYearEnd", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:dateStr", UelFunctions.class.getMethod("dateString", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:dateTimeStr", UelFunctions.class.getMethod("dateTimeString", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:timeStr", UelFunctions.class.getMethod("timeString", Timestamp.class, TimeZone.class, Locale.class));
-                this.functionMap.put("date:nowTimestamp", UtilDateTime.class.getMethod("nowTimestamp"));
-                this.functionMap.put("math:absDouble", Math.class.getMethod("abs", double.class));
-                this.functionMap.put("math:absFloat", Math.class.getMethod("abs", float.class));
-                this.functionMap.put("math:absInt", Math.class.getMethod("abs", int.class));
-                this.functionMap.put("math:absLong", Math.class.getMethod("abs", long.class));
-                this.functionMap.put("math:acos", Math.class.getMethod("abs", double.class));
-                this.functionMap.put("math:asin", Math.class.getMethod("asin", double.class));
-                this.functionMap.put("math:atan", Math.class.getMethod("atan", double.class));
-                this.functionMap.put("math:atan2", Math.class.getMethod("max", double.class, double.class));
-                this.functionMap.put("math:cbrt", Math.class.getMethod("cbrt", double.class));
-                this.functionMap.put("math:ceil", Math.class.getMethod("ceil", double.class));
-                this.functionMap.put("math:cos", Math.class.getMethod("cos", double.class));
-                this.functionMap.put("math:cosh", Math.class.getMethod("cosh", double.class));
-                this.functionMap.put("math:exp", Math.class.getMethod("exp", double.class));
-                this.functionMap.put("math:expm1", Math.class.getMethod("expm1", double.class));
-                this.functionMap.put("math:floor", Math.class.getMethod("floor", double.class));
-                this.functionMap.put("math:hypot", Math.class.getMethod("hypot", double.class, double.class));
-                this.functionMap.put("math:IEEEremainder", Math.class.getMethod("IEEEremainder", double.class, double.class));
-                this.functionMap.put("math:log", Math.class.getMethod("log", double.class));
-                this.functionMap.put("math:log10", Math.class.getMethod("log10", double.class));
-                this.functionMap.put("math:log1p", Math.class.getMethod("log1p", double.class));
-                this.functionMap.put("math:maxDouble", Math.class.getMethod("max", double.class, double.class));
-                this.functionMap.put("math:maxFloat", Math.class.getMethod("max", float.class, float.class));
-                this.functionMap.put("math:maxInt", Math.class.getMethod("max", int.class, int.class));
-                this.functionMap.put("math:maxLong", Math.class.getMethod("max", long.class, long.class));
-                this.functionMap.put("math:minDouble", Math.class.getMethod("min", double.class, double.class));
-                this.functionMap.put("math:minFloat", Math.class.getMethod("min", float.class, float.class));
-                this.functionMap.put("math:minInt", Math.class.getMethod("min", int.class, int.class));
-                this.functionMap.put("math:minLong", Math.class.getMethod("min", long.class, long.class));
-                this.functionMap.put("math:pow", Math.class.getMethod("pow", double.class, double.class));
-                this.functionMap.put("math:random", Math.class.getMethod("random"));
-                this.functionMap.put("math:rint", Math.class.getMethod("rint", double.class));
-                this.functionMap.put("math:roundDouble", Math.class.getMethod("round", double.class));
-                this.functionMap.put("math:roundFloat", Math.class.getMethod("round", float.class));
-                this.functionMap.put("math:signumDouble", Math.class.getMethod("signum", double.class));
-                this.functionMap.put("math:signumFloat", Math.class.getMethod("signum", float.class));
-                this.functionMap.put("math:sin", Math.class.getMethod("sin", double.class));
-                this.functionMap.put("math:sinh", Math.class.getMethod("sinh", double.class));
-                this.functionMap.put("math:sqrt", Math.class.getMethod("sqrt", double.class));
-                this.functionMap.put("math:tan", Math.class.getMethod("tan", double.class));
-                this.functionMap.put("math:tanh", Math.class.getMethod("tanh", double.class));
-                this.functionMap.put("math:toDegrees", Math.class.getMethod("toDegrees", double.class));
-                this.functionMap.put("math:toRadians", Math.class.getMethod("toRadians", double.class));
-                this.functionMap.put("math:ulpDouble", Math.class.getMethod("ulp", double.class));
-                this.functionMap.put("math:ulpFloat", Math.class.getMethod("ulp", float.class));
-                this.functionMap.put("str:endsWith", UelFunctions.class.getMethod("endsWith", String.class, String.class));
-                this.functionMap.put("str:indexOf", UelFunctions.class.getMethod("indexOf", String.class, String.class));
-                this.functionMap.put("str:lastIndexOf", UelFunctions.class.getMethod("lastIndexOf", String.class, String.class));
-                this.functionMap.put("str:length", UelFunctions.class.getMethod("length", String.class));
-                this.functionMap.put("str:replace", UelFunctions.class.getMethod("replace", String.class, String.class, String.class));
-                this.functionMap.put("str:replaceAll", UelFunctions.class.getMethod("replaceAll", String.class, String.class, String.class));
-                this.functionMap.put("str:replaceFirst", UelFunctions.class.getMethod("replaceFirst", String.class, String.class, String.class));
-                this.functionMap.put("str:startsWith", UelFunctions.class.getMethod("startsWith", String.class, String.class));
-                this.functionMap.put("str:endstring", UelFunctions.class.getMethod("endString", String.class, int.class));
-                this.functionMap.put("str:substring", UelFunctions.class.getMethod("subString", String.class, int.class, int.class));
-                this.functionMap.put("str:toString", UelFunctions.class.getMethod("toString", Object.class));
-                this.functionMap.put("str:trim", UelFunctions.class.getMethod("trim", String.class));
-                this.functionMap.put("sys:getenv", UelFunctions.class.getMethod("sysGetEnv", String.class));
-                this.functionMap.put("sys:getProperty", UelFunctions.class.getMethod("sysGetProp", String.class));
-                this.functionMap.put("util:size", UelFunctions.class.getMethod("getSize", Object.class));
-                this.functionMap.put("util:defaultLocale", Locale.class.getMethod("getDefault"));
-                this.functionMap.put("util:defaultTimeZone", TimeZone.class.getMethod("getDefault"));
-            } catch (Exception e) {
-                Debug.logWarning("Error while initializing UelFunctions.Functions instance: " + e, module);
-            }
-            Debug.logVerbose("UelFunctions.Functions loaded " + this.functionMap.size() + " functions", module);
-        }
-        public void setFunction(String prefix, String localName, Method method) {
-            synchronized(this) {
-                functionMap.put(prefix + ":" + localName, method);
-            }
-        }
-        public Method resolveFunction(String prefix, String localName) {
-            return functionMap.get(prefix + ":" + localName);
-        }
-    }
-
-    public static String dateString(Timestamp stamp, TimeZone timeZone, Locale locale) {
-        DateFormat dateFormat = UtilDateTime.toDateFormat(UtilDateTime.DATE_FORMAT, timeZone, locale);
-        dateFormat.setTimeZone(timeZone);
-        return dateFormat.format(stamp);
-    }
-
-    public static String dateTimeString(Timestamp stamp, TimeZone timeZone, Locale locale) {
-        DateFormat dateFormat = UtilDateTime.toDateTimeFormat("yyyy-MM-dd HH:mm", timeZone, locale);
-        dateFormat.setTimeZone(timeZone);
-        return dateFormat.format(stamp);
-    }
-
-    public static String timeString(Timestamp stamp, TimeZone timeZone, Locale locale) {
-        DateFormat dateFormat = UtilDateTime.toTimeFormat(UtilDateTime.TIME_FORMAT, timeZone, locale);
-        dateFormat.setTimeZone(timeZone);
-        return dateFormat.format(stamp);
-    }
-
-    @SuppressWarnings("unchecked")
-    public static int getSize(Object obj) {
-        try {
-            Map map = (Map) obj;
-            return map.size();
-        } catch (Exception e) {}
-        try {
-            Collection coll = (Collection) obj;
-            return coll.size();
-        } catch (Exception e) {}
-        try {
-            String str = (String) obj;
-            return str.length();
-        } catch (Exception e) {}
-        return -1;
-    }
-
-    public static boolean endsWith(String str1, String str2) {
-        try {
-            return str1.endsWith(str2);
-        } catch (Exception e) {}
-        return false;
-    }
-
-    public static int indexOf(String str1, String str2) {
-        try {
-            return str1.indexOf(str2);
-        } catch (Exception e) {}
-        return -1;
-    }
-
-    public static int lastIndexOf(String str1, String str2) {
-        try {
-            return str1.lastIndexOf(str2);
-        } catch (Exception e) {}
-        return -1;
-    }
-
-    public static int length(String str1) {
-        try {
-            return str1.length();
-        } catch (Exception e) {}
-        return -1;
-    }
-
-    public static String replace(String str1, String str2, String str3) {
-        try {
-            return str1.replace(str2, str3);
-        } catch (Exception e) {}
-        return null;
-    }
-
-    public static String replaceAll(String str1, String str2, String str3) {
-        try {
-            return str1.replaceAll(str2, str3);
-        } catch (Exception e) {}
-        return null;
-    }
-
-    public static String replaceFirst(String str1, String str2, String str3) {
-        try {
-            return str1.replaceFirst(str2, str3);
-        } catch (Exception e) {}
-        return null;
-    }
-
-    public static boolean startsWith(String str1, String str2) {
-        try {
-            return str1.startsWith(str2);
-        } catch (Exception e) {}
-        return false;
-    }
-
-    public static String endString(String str, int index) {
-        try {
-            return str.substring(index);
-        } catch (Exception e) {}
-        return null;
-    }
-
-    public static String subString(String str, int beginIndex, int endIndex) {
-        try {
-            return str.substring(beginIndex, endIndex);
-        } catch (Exception e) {}
-        return null;
-    }
-
-    public static String trim(String str) {
-        try {
-            return str.trim();
-        } catch (Exception e) {}
-        return null;
-    }
-
-    public static String toString(Object obj) {
-        return obj.toString();
-    }
-
-    public static String sysGetEnv(String str) {
-        try {
-            return System.getenv(str);
-        } catch (Exception e) {}
-        return null;
-    }
-
-    public static String sysGetProp(String str) {
-        try {
-            return System.getProperty(str);
-        } catch (Exception e) {}
-        return null;
-    }
-}
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.ofbiz.base.util.string;
+
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.sql.Timestamp;
+import javax.el.*;
+
+import javolution.util.FastMap;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.UtilDateTime;
+
+/** Implements Unified Expression Language functions.
+ * <p>Built-in functions are divided into a number of
+ * namespace prefixes:</p>
+ * <table border="1">
+ * <tr><td colspan="2"><b><code>date:</code> contains miscellaneous date/time functions</b></td></tr>
+ * <tr><td><code>date:second(Timestamp, TimeZone, Locale)</code></td><td>Returns the second value of <code>Timestamp</code> (0 - 59).</td></tr>
+ * <tr><td><code>date:minute(Timestamp, TimeZone, Locale)</code></td><td>Returns the minute value of <code>Timestamp</code> (0 - 59).</td></tr>
+ * <tr><td><code>date:hour(Timestamp, TimeZone, Locale)</code></td><td>Returns the hour value of <code>Timestamp</code> (0 - 23).</td></tr>
+ * <tr><td><code>date:dayOfMonth(Timestamp, TimeZone, Locale)</code></td><td>Returns the day of month value of <code>Timestamp</code> (1 - 31).</td></tr>
+ * <tr><td><code>date:dayOfWeek(Timestamp, TimeZone, Locale)</code></td><td>Returns the day of week value of <code>Timestamp</code> (Sunday = 1, Saturday = 7).</td></tr>
+ * <tr><td><code>date:dayOfYear(Timestamp, TimeZone, Locale)</code></td><td>Returns the day of year value of <code>Timestamp</code>.</td></tr>
+ * <tr><td><code>date:week(Timestamp, TimeZone, Locale)</code></td><td>Returns the week value of <code>Timestamp</code>.</td></tr>
+ * <tr><td><code>date:month(Timestamp, TimeZone, Locale)</code></td><td>Returns the month value of <code>Timestamp</code> (January = 0, December = 11).</td></tr>
+ * <tr><td><code>date:year(Timestamp, TimeZone, Locale)</code></td><td>Returns the year value of <code>Timestamp</code>.</td></tr>
+ * <tr><td><code>date:dayStart(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to start of day.</td></tr>
+ * <tr><td><code>date:dayEnd(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to end of day.</td></tr>
+ * <tr><td><code>date:weekStart(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to start of week.</td></tr>
+ * <tr><td><code>date:weekEnd(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to end of week.</td></tr>
+ * <tr><td><code>date:monthStart(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to start of month.</td></tr>
+ * <tr><td><code>date:monthEnd(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to end of month.</td></tr>
+ * <tr><td><code>date:yearStart(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to start of year.</td></tr>
+ * <tr><td><code>date:yearEnd(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> set to end of year.</td></tr>
+ * <tr><td><code>date:dateStr(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> as a date <code>String</code> (yyyy-mm-dd).</td></tr>
+ * <tr><td><code>date:dateTimeStr(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> as a date-time <code>String</code> (yyyy-mm-dd hh:mm).</td></tr>
+ * <tr><td><code>date:timeStr(Timestamp, TimeZone, Locale)</code></td><td>Returns <code>Timestamp</code> as a time <code>String</code> (hh:mm).</td></tr>
+ * <tr><td><code>date:nowTimestamp()</code></td><td>Returns <code>Timestamp </code> for right now<code>String</code>.</td></tr>
+ * <tr><td colspan="2"><b><code>math:</code> maps to <code>java.lang.Math</code></b></td></tr>
+ * <tr><td><code>math:absDouble(double)</code></td><td>Returns the absolute value of a <code>double</code> value.</td></tr>
+ * <tr><td><code>math:absFloat(float)</code></td><td>Returns the absolute value of a <code>float</code> value.</td></tr>
+ * <tr><td><code>math:absInt(int)</code></td><td>Returns the absolute value of an <code>int</code> value.</td></tr>
+ * <tr><td><code>math:absLong(long)</code></td><td>Returns the absolute value of a <code>long</code> value.</td></tr>
+ * <tr><td><code>math:acos(double)</code></td><td>Returns the arc cosine of an angle, in the range of 0.0 through <i>pi</i>.</td></tr>
+ * <tr><td><code>math:asin(double)</code></td><td>Returns the arc sine of an angle, in the range of -<i>pi</i>/2 through <i>pi</i>/2.</td></tr>
+ * <tr><td><code>math:atan(double)</code></td><td>Returns the arc tangent of an angle, in the range of -<i>pi</i>/2 through <i>pi</i>/2.</td></tr>
+ * <tr><td><code>math:atan2(double, double)</code></td><td>Converts rectangular coordinates (<code>x</code>,&nbsp;<code>y</code>) to polar (r,&nbsp;<i>theta</i>).</td></tr>
+ * <tr><td><code>math:cbrt(double)</code></td><td>Returns the cube root of a <code>double</code> value.</td></tr>
+ * <tr><td><code>math:ceil(double)</code></td><td>Returns the smallest (closest to negative infinity) <code>double</code> value that is greater than or equal to the argument and is equal to a mathematical integer.</td></tr>
+ * <tr><td><code>math:cos(double)</code></td><td>Returns the trigonometric cosine of an angle.</td></tr>
+ * <tr><td><code>math:cosh(double)</code></td><td>Returns the hyperbolic cosine of a <code>double</code> value.</td></tr>
+ * <tr><td><code>math:exp(double)</code></td><td>Returns Euler's number <i>e</i> raised to the power of a <code>double</code> value.</td></tr>
+ * <tr><td><code>math:expm1(double)</code></td><td>Returns <i>e</i><sup>x</sup>&nbsp;-1.</td></tr>
+ * <tr><td><code>math:floor(double)</code></td><td>Returns the largest (closest to positive infinity) <code>double</code> value that is less than or equal to the argument and is equal to a mathematical integer.</td></tr>
+ * <tr><td><code>math:hypot(double, double)</code></td><td>Returns sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>) without intermediate overflow or underflow.</td></tr>
+ * <tr><td><code>math:IEEEremainder(double, double)</code></td><td>Computes the remainder operation on two arguments as prescribed by the IEEE 754 standard.</td></tr>
+ * <tr><td><code>math:log(double)</code></td><td>Returns the natural logarithm (base <i>e</i>) of a <code>double</code> value.</td></tr>
+ * <tr><td><code>math:log10(double)</code></td><td>Returns the base 10 logarithm of a <code>double</code> value.</td></tr>
+ * <tr><td><code>math:log1p(double)</code></td><td>Returns the natural logarithm of the sum of the argument and 1.</td></tr>
+ * <tr><td><code>math:maxDouble(double, double)</code></td><td>Returns the greater of two <code>double</code> values.</td></tr>
+ * <tr><td><code>math:maxFloat(float, float)</code></td><td>Returns the greater of two <code>float</code> values.</td></tr>
+ * <tr><td><code>math:maxInt(int, int)</code></td><td>Returns the greater of two <code>int</code> values.</td></tr>
+ * <tr><td><code>math:maxLong(long, long)</code></td><td>Returns the greater of two <code>long</code> values.</td></tr>
+ * <tr><td><code>math:minDouble(double, double)</code></td><td>Returns the smaller of two <code>double</code> values.</td></tr>
+ * <tr><td><code>math:minFloat(float, float)</code></td><td>Returns the smaller of two <code>float</code> values.</td></tr>
+ * <tr><td><code>math:minInt(int, int)</code></td><td>Returns the smaller of two <code>int</code> values.</td></tr>
+ * <tr><td><code>math:minLong(long, long)</code></td><td>Returns the smaller of two <code>long</code> values.</td></tr>
+ * <tr><td><code>math:pow(double, double)</code></td><td>Returns the value of the first argument raised to the power of the second argument.</td></tr>
+ * <tr><td><code>math:random()</code></td><td>Returns a <code>double</code> value with a positive sign, greater than or equal to <code>0.0</code> and less than <code>1.0</code>.</td></tr>
+ * <tr><td><code>math:rint(double)</code></td><td>Returns the <code>double</code> value that is closest in value to the argument and is equal to a mathematical integer.</td></tr>
+ * <tr><td><code>math:roundDouble(double)</code></td><td>Returns the closest <code>long</code> to the argument.</td></tr>
+ * <tr><td><code>math:roundFloat(float)</code></td><td>Returns the closest <code>int</code> to the argument.</td></tr>
+ * <tr><td><code>math:signumDouble(double)</code></td><td>Returns the signum function of the argument; zero if the argument is zero, 1.0 if the argument is greater than zero, -1.0 if the argument is less than zero.</td></tr>
+ * <tr><td><code>math:signumFloat(float)</code></td><td>Returns the signum function of the argument; zero if the argument is zero, 1.0f if the argument is greater than zero, -1.0f if the argument is less than zero.</td></tr>
+ * <tr><td><code>math:sin(double)</code></td><td>Returns the trigonometric sine of an angle.</td></tr>
+ * <tr><td><code>math:sinh(double)</code></td><td>Returns the hyperbolic sine of a <code>double</code> value.</td></tr>
+ * <tr><td><code>math:sqrt(double)</code></td><td>Returns the correctly rounded positive square root of a <code>double</code> value.</td></tr>
+ * <tr><td><code>math:tan(double)</code></td><td>Returns the trigonometric tangent of an angle.</td></tr>
+ * <tr><td><code>math:tanh(double)</code></td><td>Returns the hyperbolic tangent of a <code>double</code> value.</td></tr>
+ * <tr><td><code>math:toDegrees(double)</code></td><td>Converts an angle measured in radians to an approximately equivalent angle measured in degrees.</td></tr>
+ * <tr><td><code>math:toRadians(double)</code></td><td>Converts an angle measured in degrees to an approximately equivalent angle measured in radians.</td></tr>
+ * <tr><td><code>math:ulpDouble(double)</code></td><td>Returns the size of an ulp (units in the last place) of the argument.</td></tr>
+ * <tr><td><code>math:ulpFloat(float)</code></td><td>Returns the size of an ulp (units in the last place) of the argument.</td></tr>
+ * <tr><td colspan="2"><b><code>str:</code> maps to <code>java.lang.String</code></b></td></tr>
+ * <tr><td><code>str:endsWith(String, String)</code></td><td>Returns <code>true</code> if this string ends with the specified suffix.</td></tr>
+ * <tr><td><code>str:indexOf(String, String)</code></td><td>Returns the index within this string of the first occurrence of the specified substring.</td></tr>
+ * <tr><td><code>str:lastIndexOf(String, String)</code></td><td>Returns the index within this string of the last occurrence of the specified character.</td></tr>
+ * <tr><td><code>str:length(String)</code></td><td>Returns the length of this string.</td></tr>
+ * <tr><td><code>str:replace(String, String, String)</code></td><td>Replaces each substring of this string that matches the literal target sequence with the specified literal replacement sequence.</td></tr>
+ * <tr><td><code>str:replaceAll(String, String, String)</code></td><td>Replaces each substring of this string that matches the given regular expression with the given replacement.</td></tr>
+ * <tr><td><code>str:replaceFirst(String, String, String)</code></td><td>Replaces the first substring of this string that matches the given regular expression with the given replacement.</td></tr>
+ * <tr><td><code>str:startsWith(String, String)</code></td><td>Returns <code>true</code> if this string starts with the specified prefix.</td></tr>
+ * <tr><td><code>str:endstring(String, int)</code></td><td>Returns a new string that is a substring of this string. The substring begins with the character at the specified index and extends to the end of this string.</td></tr>
+ * <tr><td><code>str:substring(String, int, int)</code></td><td>Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex.</td></tr>
+ * <tr><td><code>str:toString(Object)</code></td><td>Converts <code>Object</code> to a <code>String</code> - bypassing localization.</td></tr>
+ * <tr><td><code>str:trim(String)</code></td><td>Returns a copy of the string, with leading and trailing whitespace omitted.</td></tr>
+ * <tr><td colspan="2"><b><code>sys:</code> maps to <code>java.lang.System</code></b></td></tr>
+ * <tr><td><code>sys:getenv(String)</code></td><td>Gets the value of the specified environment variable.</td></tr>
+ * <tr><td><code>sys:getProperty(String)</code></td><td>Gets the system property indicated by the specified key.</td></tr>
+ * <tr><td colspan="2"><b><code>util:</code> contains miscellaneous utility functions</b></td></tr>
+ * <tr><td><code>util:defaultLocale()</code></td><td>Returns the default <code>Locale</code>.</td></tr>
+ * <tr><td><code>util:defaultTimeZone()</code></td><td>Returns the default <code>TimeZone</code>.</td></tr>
+ * <tr><td><code>util:size(Object)</code></td><td>Returns the size of <code>Maps</code>,
+ * <code>Collections</code>, and <code>Strings</code>. Invalid <code>Object</code> types return -1.</td></tr>
+ * </table>
+ */
+public class UelFunctions {
+
+    public static final String module = UelFunctions.class.getName();
+    protected static final FunctionMapper functionMapper = new Functions();
+
+    /** Returns a <code>FunctionMapper</code> instance.
+     * @return <code>FunctionMapper</code> instance
+     */
+    public static FunctionMapper getFunctionMapper() {
+        return functionMapper;
+    }
+
+    protected static class Functions extends FunctionMapper {
+        protected final Map<String, Method> functionMap = FastMap.newInstance();
+        public Functions() {
+            try {
+                this.functionMap.put("date:second", UtilDateTime.class.getMethod("getSecond", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:minute", UtilDateTime.class.getMethod("getMinute", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:hour", UtilDateTime.class.getMethod("getHour", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:dayOfMonth", UtilDateTime.class.getMethod("getDayOfMonth", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:dayOfWeek", UtilDateTime.class.getMethod("getDayOfWeek", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:dayOfYear", UtilDateTime.class.getMethod("getDayOfYear", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:week", UtilDateTime.class.getMethod("getWeek", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:month", UtilDateTime.class.getMethod("getMonth", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:year", UtilDateTime.class.getMethod("getYear", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:dayStart", UtilDateTime.class.getMethod("getDayStart", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:dayEnd", UtilDateTime.class.getMethod("getDayEnd", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:weekStart", UtilDateTime.class.getMethod("getWeekStart", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:weekEnd", UtilDateTime.class.getMethod("getWeekEnd", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:monthStart", UtilDateTime.class.getMethod("getMonthStart", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:monthEnd", UtilDateTime.class.getMethod("getMonthEnd", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:yearStart", UtilDateTime.class.getMethod("getYearStart", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:yearEnd", UtilDateTime.class.getMethod("getYearEnd", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:dateStr", UelFunctions.class.getMethod("dateString", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:dateTimeStr", UelFunctions.class.getMethod("dateTimeString", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:timeStr", UelFunctions.class.getMethod("timeString", Timestamp.class, TimeZone.class, Locale.class));
+                this.functionMap.put("date:nowTimestamp", UtilDateTime.class.getMethod("nowTimestamp"));
+                this.functionMap.put("math:absDouble", Math.class.getMethod("abs", double.class));
+                this.functionMap.put("math:absFloat", Math.class.getMethod("abs", float.class));
+                this.functionMap.put("math:absInt", Math.class.getMethod("abs", int.class));
+                this.functionMap.put("math:absLong", Math.class.getMethod("abs", long.class));
+                this.functionMap.put("math:acos", Math.class.getMethod("abs", double.class));
+                this.functionMap.put("math:asin", Math.class.getMethod("asin", double.class));
+                this.functionMap.put("math:atan", Math.class.getMethod("atan", double.class));
+                this.functionMap.put("math:atan2", Math.class.getMethod("max", double.class, double.class));
+                this.functionMap.put("math:cbrt", Math.class.getMethod("cbrt", double.class));
+                this.functionMap.put("math:ceil", Math.class.getMethod("ceil", double.class));
+                this.functionMap.put("math:cos", Math.class.getMethod("cos", double.class));
+                this.functionMap.put("math:cosh", Math.class.getMethod("cosh", double.class));
+                this.functionMap.put("math:exp", Math.class.getMethod("exp", double.class));
+                this.functionMap.put("math:expm1", Math.class.getMethod("expm1", double.class));
+                this.functionMap.put("math:floor", Math.class.getMethod("floor", double.class));
+                this.functionMap.put("math:hypot", Math.class.getMethod("hypot", double.class, double.class));
+                this.functionMap.put("math:IEEEremainder", Math.class.getMethod("IEEEremainder", double.class, double.class));
+                this.functionMap.put("math:log", Math.class.getMethod("log", double.class));
+                this.functionMap.put("math:log10", Math.class.getMethod("log10", double.class));
+                this.functionMap.put("math:log1p", Math.class.getMethod("log1p", double.class));
+                this.functionMap.put("math:maxDouble", Math.class.getMethod("max", double.class, double.class));
+                this.functionMap.put("math:maxFloat", Math.class.getMethod("max", float.class, float.class));
+                this.functionMap.put("math:maxInt", Math.class.getMethod("max", int.class, int.class));
+                this.functionMap.put("math:maxLong", Math.class.getMethod("max", long.class, long.class));
+                this.functionMap.put("math:minDouble", Math.class.getMethod("min", double.class, double.class));
+                this.functionMap.put("math:minFloat", Math.class.getMethod("min", float.class, float.class));
+                this.functionMap.put("math:minInt", Math.class.getMethod("min", int.class, int.class));
+                this.functionMap.put("math:minLong", Math.class.getMethod("min", long.class, long.class));
+                this.functionMap.put("math:pow", Math.class.getMethod("pow", double.class, double.class));
+                this.functionMap.put("math:random", Math.class.getMethod("random"));
+                this.functionMap.put("math:rint", Math.class.getMethod("rint", double.class));
+                this.functionMap.put("math:roundDouble", Math.class.getMethod("round", double.class));
+                this.functionMap.put("math:roundFloat", Math.class.getMethod("round", float.class));
+                this.functionMap.put("math:signumDouble", Math.class.getMethod("signum", double.class));
+                this.functionMap.put("math:signumFloat", Math.class.getMethod("signum", float.class));
+                this.functionMap.put("math:sin", Math.class.getMethod("sin", double.class));
+                this.functionMap.put("math:sinh", Math.class.getMethod("sinh", double.class));
+                this.functionMap.put("math:sqrt", Math.class.getMethod("sqrt", double.class));
+                this.functionMap.put("math:tan", Math.class.getMethod("tan", double.class));
+                this.functionMap.put("math:tanh", Math.class.getMethod("tanh", double.class));
+                this.functionMap.put("math:toDegrees", Math.class.getMethod("toDegrees", double.class));
+                this.functionMap.put("math:toRadians", Math.class.getMethod("toRadians", double.class));
+                this.functionMap.put("math:ulpDouble", Math.class.getMethod("ulp", double.class));
+                this.functionMap.put("math:ulpFloat", Math.class.getMethod("ulp", float.class));
+                this.functionMap.put("str:endsWith", UelFunctions.class.getMethod("endsWith", String.class, String.class));
+                this.functionMap.put("str:indexOf", UelFunctions.class.getMethod("indexOf", String.class, String.class));
+                this.functionMap.put("str:lastIndexOf", UelFunctions.class.getMethod("lastIndexOf", String.class, String.class));
+                this.functionMap.put("str:length", UelFunctions.class.getMethod("length", String.class));
+                this.functionMap.put("str:replace", UelFunctions.class.getMethod("replace", String.class, String.class, String.class));
+                this.functionMap.put("str:replaceAll", UelFunctions.class.getMethod("replaceAll", String.class, String.class, String.class));
+                this.functionMap.put("str:replaceFirst", UelFunctions.class.getMethod("replaceFirst", String.class, String.class, String.class));
+                this.functionMap.put("str:startsWith", UelFunctions.class.getMethod("startsWith", String.class, String.class));
+                this.functionMap.put("str:endstring", UelFunctions.class.getMethod("endString", String.class, int.class));
+                this.functionMap.put("str:substring", UelFunctions.class.getMethod("subString", String.class, int.class, int.class));
+                this.functionMap.put("str:toString", UelFunctions.class.getMethod("toString", Object.class));
+                this.functionMap.put("str:trim", UelFunctions.class.getMethod("trim", String.class));
+                this.functionMap.put("sys:getenv", UelFunctions.class.getMethod("sysGetEnv", String.class));
+                this.functionMap.put("sys:getProperty", UelFunctions.class.getMethod("sysGetProp", String.class));
+                this.functionMap.put("util:size", UelFunctions.class.getMethod("getSize", Object.class));
+                this.functionMap.put("util:defaultLocale", Locale.class.getMethod("getDefault"));
+                this.functionMap.put("util:defaultTimeZone", TimeZone.class.getMethod("getDefault"));
+            } catch (Exception e) {
+                Debug.logWarning("Error while initializing UelFunctions.Functions instance: " + e, module);
+            }
+            Debug.logVerbose("UelFunctions.Functions loaded " + this.functionMap.size() + " functions", module);
+        }
+        public void setFunction(String prefix, String localName, Method method) {
+            synchronized(this) {
+                functionMap.put(prefix + ":" + localName, method);
+            }
+        }
+        public Method resolveFunction(String prefix, String localName) {
+            return functionMap.get(prefix + ":" + localName);
+        }
+    }
+
+    public static String dateString(Timestamp stamp, TimeZone timeZone, Locale locale) {
+        DateFormat dateFormat = UtilDateTime.toDateFormat(UtilDateTime.DATE_FORMAT, timeZone, locale);
+        dateFormat.setTimeZone(timeZone);
+        return dateFormat.format(stamp);
+    }
+
+    public static String dateTimeString(Timestamp stamp, TimeZone timeZone, Locale locale) {
+        DateFormat dateFormat = UtilDateTime.toDateTimeFormat("yyyy-MM-dd HH:mm", timeZone, locale);
+        dateFormat.setTimeZone(timeZone);
+        return dateFormat.format(stamp);
+    }
+
+    public static String timeString(Timestamp stamp, TimeZone timeZone, Locale locale) {
+        DateFormat dateFormat = UtilDateTime.toTimeFormat(UtilDateTime.TIME_FORMAT, timeZone, locale);
+        dateFormat.setTimeZone(timeZone);
+        return dateFormat.format(stamp);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static int getSize(Object obj) {
+        try {
+            Map map = (Map) obj;
+            return map.size();
+        } catch (Exception e) {}
+        try {
+            Collection coll = (Collection) obj;
+            return coll.size();
+        } catch (Exception e) {}
+        try {
+            String str = (String) obj;
+            return str.length();
+        } catch (Exception e) {}
+        return -1;
+    }
+
+    public static boolean endsWith(String str1, String str2) {
+        try {
+            return str1.endsWith(str2);
+        } catch (Exception e) {}
+        return false;
+    }
+
+    public static int indexOf(String str1, String str2) {
+        try {
+            return str1.indexOf(str2);
+        } catch (Exception e) {}
+        return -1;
+    }
+
+    public static int lastIndexOf(String str1, String str2) {
+        try {
+            return str1.lastIndexOf(str2);
+        } catch (Exception e) {}
+        return -1;
+    }
+
+    public static int length(String str1) {
+        try {
+            return str1.length();
+        } catch (Exception e) {}
+        return -1;
+    }
+
+    public static String replace(String str1, String str2, String str3) {
+        try {
+            return str1.replace(str2, str3);
+        } catch (Exception e) {}
+        return null;
+    }
+
+    public static String replaceAll(String str1, String str2, String str3) {
+        try {
+            return str1.replaceAll(str2, str3);
+        } catch (Exception e) {}
+        return null;
+    }
+
+    public static String replaceFirst(String str1, String str2, String str3) {
+        try {
+            return str1.replaceFirst(str2, str3);
+        } catch (Exception e) {}
+        return null;
+    }
+
+    public static boolean startsWith(String str1, String str2) {
+        try {
+            return str1.startsWith(str2);
+        } catch (Exception e) {}
+        return false;
+    }
+
+    public static String endString(String str, int index) {
+        try {
+            return str.substring(index);
+        } catch (Exception e) {}
+        return null;
+    }
+
+    public static String subString(String str, int beginIndex, int endIndex) {
+        try {
+            return str.substring(beginIndex, endIndex);
+        } catch (Exception e) {}
+        return null;
+    }
+
+    public static String trim(String str) {
+        try {
+            return str.trim();
+        } catch (Exception e) {}
+        return null;
+    }
+
+    public static String toString(Object obj) {
+        return obj.toString();
+    }
+
+    public static String sysGetEnv(String str) {
+        try {
+            return System.getenv(str);
+        } catch (Exception e) {}
+        return null;
+    }
+
+    public static String sysGetProp(String str) {
+        try {
+            return System.getProperty(str);
+        } catch (Exception e) {}
+        return null;
+    }
+}

Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelFunctions.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelFunctions.java
------------------------------------------------------------------------------
    svn:keywords = "Date Rev Author URL Id"