563b69526b3e25cde9946488ae2617eca7be3287
[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.Function;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.Lists;
15 import java.util.Collection;
16 import java.util.List;
17 import javax.xml.xpath.XPathExpressionException;
18 import org.jaxen.BaseXPath;
19 import org.jaxen.ContextSupport;
20 import org.jaxen.JaxenException;
21 import org.jaxen.expr.Expr;
22 import org.opendaylight.yangtools.yang.common.QNameModule;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
24 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathBooleanResult;
26 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathDocument;
27 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathExpression;
28 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathNodesetResult;
29 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathNumberResult;
30 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathResult;
31 import org.opendaylight.yangtools.yang.data.api.schema.xpath.XPathStringResult;
32 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 final class JaxenXPath implements XPathExpression {
37     private static final Logger LOG = LoggerFactory.getLogger(JaxenXPath.class);
38     protected static final Function<NormalizedNodeContext, NormalizedNode<?, ?>> EXTRACT_NODE =
39             new Function<NormalizedNodeContext, NormalizedNode<?, ?>>() {
40         @Override
41         public NormalizedNode<?, ?> apply(final NormalizedNodeContext input) {
42             return input.getNode();
43         }
44     };
45     private final Converter<String, QNameModule> converter;
46     private final SchemaPath schemaPath;
47     private final BaseXPath xpath;
48
49     private JaxenXPath(final Converter<String, QNameModule> converter, final SchemaPath schemaPath,
50             final BaseXPath xpath) {
51         this.converter = Preconditions.checkNotNull(converter);
52         this.schemaPath = Preconditions.checkNotNull(schemaPath);
53         this.xpath = Preconditions.checkNotNull(xpath);
54     }
55
56     static JaxenXPath create(final Converter<String, QNameModule> converter, final SchemaPath schemaPath,
57             final String xpath) throws JaxenException {
58         final BaseXPath compiled = new BaseXPath(xpath) {
59             private static final long serialVersionUID = 1L;
60
61             @Override
62             protected ContextSupport getContextSupport() {
63                 throw new UnsupportedOperationException(xpath);
64             }
65         };
66
67         final Expr expr = compiled.getRootExpr();
68         LOG.debug("Compiled {} to expression {}", xpath, expr);
69
70         // FIXME: perform expression introspection to understand things like apex, etc.
71
72         return new JaxenXPath(converter, schemaPath, compiled);
73     }
74
75     @Override
76     public Optional<? extends XPathResult<?>> evaluate(final XPathDocument document, final YangInstanceIdentifier path)
77             throws XPathExpressionException {
78         Preconditions.checkArgument(document instanceof JaxenDocument);
79
80         final NormalizedNodeContextSupport contextSupport = NormalizedNodeContextSupport.create(
81             (JaxenDocument)document, converter);
82
83         final Object result;
84         try {
85             result = xpath.evaluate(contextSupport.createContext(path));
86         } catch (JaxenException e) {
87             throw new XPathExpressionException(e);
88         }
89
90         if (result instanceof String) {
91             return Optional.of(new XPathStringResult() {
92                 @Override
93                 public String getValue() {
94                     return (String)result;
95                 }
96             });
97         } else if (result instanceof Number) {
98             return Optional.of(new XPathNumberResult() {
99                 @Override
100                 public Number getValue() {
101                     return (Number) result;
102                 }
103             });
104         } else if (result instanceof Boolean) {
105             return Optional.of(new XPathBooleanResult() {
106                 @Override
107                 public Boolean getValue() {
108                     return (Boolean) result;
109                 }
110             });
111         } else if (result != null){
112             return Optional.of(new XPathNodesetResult() {
113                 @SuppressWarnings("unchecked")
114                 @Override
115                 public Collection<NormalizedNode<?, ?>> getValue() {
116                     // XXX: Will this really work, or do we need to perform deep transformation?
117                     return Lists.transform((List<NormalizedNodeContext>) result, EXTRACT_NODE);
118                 }
119             });
120         } else {
121             return Optional.absent();
122         }
123     }
124
125     @Override
126     public SchemaPath getEvaluationPath() {
127         return schemaPath;
128     }
129
130     @Override
131     public SchemaPath getApexPath() {
132         // TODO: improve this
133         return SchemaPath.ROOT;
134     }
135 }