Move yang-data-jaxen to attic top-level directory
[yangtools.git] / attic / yang-data-jaxen / src / main / java / org / opendaylight / yangtools / yang / data / jaxen / JaxenXPath.java
diff --git a/attic/yang-data-jaxen/src/main/java/org/opendaylight/yangtools/yang/data/jaxen/JaxenXPath.java b/attic/yang-data-jaxen/src/main/java/org/opendaylight/yangtools/yang/data/jaxen/JaxenXPath.java
new file mode 100644 (file)
index 0000000..b2d1e4b
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.jaxen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Converter;
+import com.google.common.base.Verify;
+import com.google.common.collect.Lists;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.List;
+import java.util.Optional;
+import javax.xml.xpath.XPathExpressionException;
+import org.eclipse.jdt.annotation.NonNull;
+import org.jaxen.JaxenException;
+import org.jaxen.JaxenHandler;
+import org.jaxen.XPathSyntaxException;
+import org.jaxen.expr.Expr;
+import org.jaxen.saxpath.SAXPathException;
+import org.jaxen.saxpath.XPathReader;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.jaxen.api.XPathBooleanResult;
+import org.opendaylight.yangtools.yang.data.jaxen.api.XPathDocument;
+import org.opendaylight.yangtools.yang.data.jaxen.api.XPathExpression;
+import org.opendaylight.yangtools.yang.data.jaxen.api.XPathNodesetResult;
+import org.opendaylight.yangtools.yang.data.jaxen.api.XPathNumberResult;
+import org.opendaylight.yangtools.yang.data.jaxen.api.XPathResult;
+import org.opendaylight.yangtools.yang.data.jaxen.api.XPathStringResult;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class JaxenXPath implements XPathExpression {
+    private static final Logger LOG = LoggerFactory.getLogger(JaxenXPath.class);
+
+    private final @NonNull Converter<String, QNameModule> converter;
+    private final @NonNull SchemaPath schemaPath;
+    private final @NonNull Expr expr;
+
+    private JaxenXPath(final @NonNull Converter<String, QNameModule> converter, final @NonNull SchemaPath schemaPath,
+            final @NonNull Expr expr) {
+        this.converter = requireNonNull(converter);
+        this.schemaPath = requireNonNull(schemaPath);
+        this.expr = requireNonNull(expr);
+    }
+
+    static @NonNull JaxenXPath create(final @NonNull Converter<String, QNameModule> converter,
+            final @NonNull SchemaPath schemaPath, final @NonNull String xpath) throws JaxenException {
+
+        final @NonNull Expr parsed;
+        try {
+            final XPathReader reader = new org.jaxen.saxpath.base.XPathReader();
+            final JaxenHandler handler = new JaxenHandler();
+            reader.setXPathHandler(handler);
+            reader.parse(xpath);
+            parsed = handler.getXPathExpr().getRootExpr();
+        } catch (org.jaxen.saxpath.XPathSyntaxException e) {
+            throw new XPathSyntaxException(e);
+        } catch (SAXPathException e) {
+            throw new JaxenException(e);
+        }
+
+        LOG.debug("Compiled {} to expression {}", xpath, parsed);
+
+        new ExprWalker(new ExprListener() {
+            // FIXME: perform expression introspection to understand things like apex, etc.
+        }).walk(parsed);
+
+        return new JaxenXPath(converter, schemaPath, parsed);
+    }
+
+    @Override
+    public Optional<? extends XPathResult<?>> evaluate(final XPathDocument document,
+            final YangInstanceIdentifier path) throws XPathExpressionException {
+        checkArgument(document instanceof JaxenDocument);
+
+        final NormalizedNodeContextSupport contextSupport = NormalizedNodeContextSupport.create(
+            (JaxenDocument)document, converter);
+
+        final Object result = evaluate(contextSupport.createContext(path));
+        if (result instanceof String) {
+            return Optional.of((XPathStringResult) () -> (String) result);
+        } else if (result instanceof Number) {
+            return Optional.of((XPathNumberResult) () -> (Number) result);
+        } else if (result instanceof Boolean) {
+            return Optional.of((XPathBooleanResult) () -> (Boolean) result);
+        } else if (result == null) {
+            return Optional.empty();
+        }
+
+        Verify.verify(result instanceof List, "Unhandled result %s", result);
+        @SuppressWarnings("unchecked")
+        final List<NormalizedNodeContext> resultList = (List<NormalizedNodeContext>) result;
+        return Optional.of((XPathNodesetResult) () -> {
+            // XXX: Will this really work, or do we need to perform deep transformation?
+            return Lists.transform(resultList,
+                context -> new SimpleImmutableEntry<>(context.getPath(), context.getNode()));
+        });
+    }
+
+    private Object evaluate(final NormalizedNodeContext context) throws XPathExpressionException {
+        final Object result;
+        try {
+            result = expr.evaluate(context);
+        } catch (JaxenException e) {
+            throw new XPathExpressionException(e);
+        }
+
+        if (result instanceof List) {
+            final List<?> list = (List<?>) result;
+            if (list.size() == 1) {
+                final Object first = list.get(0);
+                if (first instanceof String || first instanceof Number || first instanceof Boolean) {
+                    return first;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public SchemaPath getEvaluationPath() {
+        return schemaPath;
+    }
+
+    @Override
+    public SchemaPath getApexPath() {
+        // TODO: improve this
+        return SchemaPath.ROOT;
+    }
+}