You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ad...@apache.org on 2008/12/27 03:31:06 UTC

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

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"



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

Posted by Adam Heath <do...@brainfood.com>.
Adrian Crum wrote:
> CVS rev 1.3. As soon I as I confirm his changes work, I'm sure they will be included in the release.

So?  If someone checks out this version, it won't have any identifying
marks on the included libraries.

All embedded libraries should have an exact version applied to them.  If
something were builting from an upstream repository, and is not an
official release, then some repository-specific version string.  If a
local patch is applied, then some other identifier needs to be applied.

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

Posted by Adrian Crum <ad...@yahoo.com>.
CVS rev 1.3. As soon I as I confirm his changes work, I'm sure they will be included in the release.

-Adrian


--- On Fri, 12/26/08, Adam Heath <do...@brainfood.com> wrote:

> From: Adam Heath <do...@brainfood.com>
> Subject: Re: svn commit: r729583 [1/2] - in /ofbiz/trunk/framework/base: lib/ src/org/ofbiz/base/util/collections/ src/org/ofbiz/base/util/string/
> To: dev@ofbiz.apache.org
> Date: Friday, December 26, 2008, 7:21 PM
> adrianc@apache.org wrote:
> > 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
> 
> If this is not a pristine download, then include some kind
> of date stamp
> in the name of the jar.


      

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

Posted by Adam Heath <do...@brainfood.com>.
adrianc@apache.org wrote:
> 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

If this is not a pristine download, then include some kind of date stamp
in the name of the jar.