svn commit: r770915 - in /ofbiz/trunk/framework: base/src/org/ofbiz/base/util/ base/src/org/ofbiz/base/util/string/ minilang/src/org/ofbiz/minilang/method/envops/

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

svn commit: r770915 - in /ofbiz/trunk/framework: base/src/org/ofbiz/base/util/ base/src/org/ofbiz/base/util/string/ minilang/src/org/ofbiz/minilang/method/envops/

lektran
Author: lektran
Date: Sat May  2 08:45:22 2009
New Revision: 770915

URL: http://svn.apache.org/viewvc?rev=770915&view=rev
Log:
OFBIZ-2397
Implement a custom JUEL ELResolver that handles string properties for objects implementing org.w3c.dom.Node
and org.apache.xerces.dom.NodeImpl. It takes the String and compiles it into an XPathExpression which is
then evaluated against the base Node. The JUEL evaluation returns either null, a single Node or a NodeList
depending on the result of the XPath evaluation.

Added:
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/NodeELResolver.java   (with props)
Modified:
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ObjectType.java
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelUtil.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Iterate.java

Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ObjectType.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ObjectType.java?rev=770915&r1=770914&r2=770915&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ObjectType.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/ObjectType.java Sat May  2 08:45:22 2009
@@ -28,6 +28,8 @@
 import java.util.*;
 import java.nio.*;
 
+import org.w3c.dom.Node;
+
 import javolution.util.FastList;
 import javolution.util.FastMap;
 import javolution.util.FastSet;
@@ -979,6 +981,14 @@
             } else {
                 throw new GeneralException("Conversion from " + fromType + " to " + type + " not currently supported");
             }
+        } else if (obj instanceof Node) {
+            Node node = (Node) obj;
+            String nodeValue =  node.getTextContent();
+            if ("String".equals(type) || "java.lang.String".equals(type)) {
+                return nodeValue;
+            } else {
+                return simpleTypeConvert(nodeValue, type, format, timeZone, locale, noTypeFail);
+            }
         } else {
             // we can pretty much always do a conversion to a String, so do that here
             if ("String".equals(type) || "java.lang.String".equals(type)) {

Added: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/NodeELResolver.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/NodeELResolver.java?rev=770915&view=auto
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/NodeELResolver.java (added)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/NodeELResolver.java Sat May  2 08:45:22 2009
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * 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.beans.FeatureDescriptor;
+import java.util.Iterator;
+
+import javax.el.CompositeELResolver;
+import javax.el.ELContext;
+import javax.el.ELResolver;
+import javax.el.PropertyNotWritableException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.xerces.dom.NodeImpl;
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.cache.UtilCache;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Defines property resolution behavior on Nodes. This resolver handles base objects that implement
+ * org.w3c.dom.Node or org.apache.xerces.dom.NodeImpl. It accepts a String as a property and compiles
+ * that String into an XPathExpression. The resulting value is the evaluation of the XPathExpression
+ * in the context of the base Node. This resolver is currently only available in read-only mode, which
+ * means that isReadOnly will always return true and {@link #setValue(ELContext, Object, Object, Object)}
+ * will always throw PropertyNotWritableException. ELResolvers are combined together using {@link CompositeELResolver}
+ * s, to define rich semantics for evaluating an expression. See the javadocs for {@link ELResolver}
+ * for details.
+ */
+public class NodeELResolver extends ELResolver {
+    private final XPath xpath;
+    private final UtilCache<String, XPathExpression> exprCache = new UtilCache<String, XPathExpression>("nodeElResolver.ExpressionCache");
+    private static final String module = NodeELResolver.class.getName();
+
+    /**
+     * Creates a new read-only NodeELResolver.
+     */
+    public NodeELResolver() {
+        XPathFactory factory = XPathFactory.newInstance();
+        xpath = factory.newXPath();
+    }
+
+    @Override
+    public Class<?> getCommonPropertyType(ELContext context, Object base) {
+        return isResolvable(base) ? String.class : null;
+    }
+
+    @Override
+    public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
+        return null;
+    }
+
+    @Override
+    public Class<?> getType(ELContext context, Object base, Object property) {
+        if (context == null) {
+            throw new NullPointerException("context is null");
+        }
+        Class<?> result = null;
+        if (isResolvable(base)) {
+            result = Node.class;
+            context.setPropertyResolved(true);
+        }
+        return result;
+    }
+
+    @Override
+    public Object getValue(ELContext context, Object base, Object property) {
+        if (context == null) {
+            throw new NullPointerException("context is null");
+        }
+        Object result = null;
+        if (isResolvable(base)) {
+            try {
+                Node node = (Node) base;
+                String propertyString = (String) property;
+                XPathExpression expr = getXPathExpressionInstance(propertyString);
+                NodeList nodeList = (NodeList) expr.evaluate(node, XPathConstants.NODESET);
+                if (nodeList.getLength() == 0) {
+                    return null;
+                } else if (nodeList.getLength() == 1) {
+                    result = nodeList.item(0);
+                } else {
+                    result = nodeList;
+                }
+                context.setPropertyResolved(true);
+            } catch (XPathExpressionException e) {
+                Debug.logError("An error occurred during XPath expression evaluation, error was: " + e, module);
+            }
+
+        }
+        return result;
+    }
+
+    @Override
+    public boolean isReadOnly(ELContext context, Object base, Object property) {
+        if (context == null) {
+            throw new NullPointerException("context is null");
+        }
+        if (isResolvable(base)) {
+            context.setPropertyResolved(true);
+        }
+        return true;
+    }
+
+    @Override
+    public void setValue(ELContext context, Object base, Object property, Object value) {
+        if (context == null) {
+            throw new NullPointerException("context is null");
+        }
+        if (isResolvable(base)) {
+            throw new PropertyNotWritableException("resolver is read-only");
+        }
+    }
+
+    private final boolean isResolvable(Object base) {
+        return base != null && (base instanceof Node || base instanceof NodeImpl);
+    }
+    
+    private XPathExpression getXPathExpressionInstance(String xPathString) {
+        XPathExpression xpe = exprCache.get(xPathString);
+        if (xpe == null) {
+            synchronized (exprCache) {
+                xpe = exprCache.get(xPathString);
+                if (xpe == null) {
+                    try {
+                        xpe = xpath.compile(xPathString);
+                        exprCache.put(xPathString, xpe);
+                    } catch (XPathExpressionException e) {
+                        Debug.logError("An error occurred during XPath expression compilation, error was: " + e, module);
+                    }
+                }
+            }
+        }
+        return xpe;
+    }
+}

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

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

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

Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelUtil.java?rev=770915&r1=770914&r2=770915&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelUtil.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/string/UelUtil.java Sat May  2 08:45:22 2009
@@ -41,6 +41,7 @@
             add(new ExtendedMapResolver(false));
             add(new ExtendedListResolver(false));
             add(new ArrayELResolver(false));
+            add(new NodeELResolver()); // Below the most common but must be kept above BeanELResolver
             add(new ResourceBundleELResolver());
             add(new BeanELResolver(false));
         }

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Iterate.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Iterate.java?rev=770915&r1=770914&r2=770915&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Iterate.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Iterate.java Sat May  2 08:45:22 2009
@@ -34,6 +34,8 @@
 import org.ofbiz.minilang.method.MethodContext;
 import org.ofbiz.minilang.method.MethodOperation;
 import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**
  * Process sub-operations for each entry in the list
@@ -101,7 +103,7 @@
                 }
                 return false;
             }
-        } else {
+        } else if (objList instanceof Iterable) {
             Collection<Object> theList = UtilGenerics.checkList(objList);
 
             if (theList == null) {
@@ -121,6 +123,17 @@
                     return false;
                 }
             }
+        } else if (objList instanceof NodeList) {
+            NodeList theList = (NodeList) objList;
+            for (int i = 0; i < theList.getLength(); i++) {
+                Node theEntry = theList.item(i);
+                entryAcsr.put(methodContext, theEntry);
+
+                if (!SimpleMethod.runSubOps(subOps, methodContext)) {
+                    // only return here if it returns false, otherwise just carry on
+                    return false;
+                }
+            }
         }
         entryAcsr.put(methodContext, oldEntryValue);
         return true;