Propagate @Nonnull and @Nullable annotations
[yangtools.git] / yang / yang-data-jaxen / src / main / java / org / opendaylight / yangtools / yang / data / jaxen / JaxenXPath.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.data.jaxen;
9
10 import com.google.common.base.Converter;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.collect.Lists;
14 import java.util.List;
15 import javax.annotation.Nonnull;
16 import javax.xml.xpath.XPathExpressionException;
17 import org.jaxen.BaseXPath;
18 import org.jaxen.ContextSupport;
19 import org.jaxen.JaxenException;
20 import org.jaxen.expr.Expr;
21 import org.opendaylight.yangtools.yang.common.QNameModule;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathBooleanResult;
24 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathDocument;
25 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathExpression;
26 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathNodesetResult;
27 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathNumberResult;
28 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathResult;
29 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathStringResult;
30 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 final class JaxenXPath implements XPathExpression {
35     private static final Logger LOG = LoggerFactory.getLogger(JaxenXPath.class);
36
37     private final Converter<String, QNameModule> converter;
38     private final SchemaPath schemaPath;
39     private final BaseXPath xpath;
40
41     private JaxenXPath(final Converter<String, QNameModule> converter, final SchemaPath schemaPath,
42             final BaseXPath xpath) {
43         this.converter = Preconditions.checkNotNull(converter);
44         this.schemaPath = Preconditions.checkNotNull(schemaPath);
45         this.xpath = Preconditions.checkNotNull(xpath);
46     }
47
48     static JaxenXPath create(final Converter<String, QNameModule> converter, final SchemaPath schemaPath,
49             final String xpath) throws JaxenException {
50         final BaseXPath compiled = new BaseXPath(xpath) {
51             private static final long serialVersionUID = 1L;
52
53             @Override
54             protected ContextSupport getContextSupport() {
55                 throw new UnsupportedOperationException(xpath);
56             }
57         };
58
59         final Expr expr = compiled.getRootExpr();
60         LOG.debug("Compiled {} to expression {}", xpath, expr);
61
62         new ExprWalker(new ExprListener() {
63             // FIXME: perform expression introspection to understand things like apex, etc.
64         }).walk(expr);
65
66         return new JaxenXPath(converter, schemaPath, compiled);
67     }
68
69     @Override
70     public Optional<? extends XPathResult<?>> evaluate(@Nonnull final XPathDocument document, @Nonnull final YangInstanceIdentifier path)
71             throws XPathExpressionException {
72         Preconditions.checkArgument(document instanceof JaxenDocument);
73
74         final NormalizedNodeContextSupport contextSupport = NormalizedNodeContextSupport.create(
75             (JaxenDocument)document, converter);
76
77         final Object result;
78         try {
79             result = xpath.evaluate(contextSupport.createContext(path));
80         } catch (JaxenException e) {
81             throw new XPathExpressionException(e);
82         }
83
84         if (result instanceof String) {
85             return Optional.of((XPathStringResult) () -> (String)result);
86         } else if (result instanceof Number) {
87             return Optional.of((XPathNumberResult) () -> (Number) result);
88         } else if (result instanceof Boolean) {
89             return Optional.of((XPathBooleanResult) () -> (Boolean) result);
90         } else if (result != null){
91             return Optional.of((XPathNodesetResult) () -> {
92                 // XXX: Will this really work, or do we need to perform deep transformation?
93                 return Lists.transform((List<NormalizedNodeContext>) result, NormalizedNodeContext::getNode);
94             });
95         } else {
96             return Optional.absent();
97         }
98     }
99
100     @Nonnull
101     @Override
102     public SchemaPath getEvaluationPath() {
103         return schemaPath;
104     }
105
106     @Nonnull
107     @Override
108     public SchemaPath getApexPath() {
109         // TODO: improve this
110         return SchemaPath.ROOT;
111     }
112 }