456d124a5d774c352901f7634404b9dc1cf391c0
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / Utils.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.parser.stmt.rfc6020;
9
10 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
11
12 import java.net.URI;
13 import java.net.URISyntaxException;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.Date;
17 import java.util.Iterator;
18 import java.util.LinkedList;
19 import java.util.List;
20
21 import javax.annotation.Nullable;
22 import javax.xml.xpath.XPath;
23 import javax.xml.xpath.XPathExpressionException;
24 import javax.xml.xpath.XPathFactory;
25
26 import org.antlr.v4.runtime.tree.TerminalNode;
27 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
28 import org.opendaylight.yangtools.yang.common.QName;
29 import org.opendaylight.yangtools.yang.common.QNameModule;
30 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
31 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
32 import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
33 import org.opendaylight.yangtools.yang.model.api.stmt.BelongsToStatement;
34 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
35 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
36 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
37 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
38 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
39 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
40 import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleName;
41 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier;
42 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleIdentifierToModuleQName;
43 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
44 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
45 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
46 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
47
48 import com.google.common.base.CharMatcher;
49 import com.google.common.base.Splitter;
50
51 public class Utils {
52
53     private static final CharMatcher DOUBLE_QUOTE_MATCHER = CharMatcher.is('"');
54     private static final CharMatcher SINGLE_QUOTE_MATCHER = CharMatcher.is('\'');
55
56     private static final char SEPARATOR_NODENAME = '/';
57
58     private static final String REGEX_PATH_ABS = "/[^/].+";
59
60     public static final StatementSourceReference CONTEXT_REF = new StatementSourceReference() {
61
62         @Override
63         public StatementSource getStatementSource() {
64             return StatementSource.CONTEXT;
65         }
66     };
67
68     public static List<String> splitPathToNodeNames(String path) {
69
70         Splitter keySplitter = Splitter.on(SEPARATOR_NODENAME).omitEmptyStrings().trimResults();
71         return keySplitter.splitToList(path);
72     }
73
74     public static void validateXPath(String path) {
75
76         final XPath xPath = XPathFactory.newInstance().newXPath();
77
78         try {
79             xPath.compile(path);
80         } catch (XPathExpressionException e) {
81             throw new IllegalArgumentException("An argument is not valid XPath string");
82         }
83     }
84
85     public static boolean isXPathAbsolute(String path) {
86
87         validateXPath(path);
88
89         return path.matches(REGEX_PATH_ABS);
90     }
91
92     public static Iterable<QName> parseXPath(StmtContext<?, ?, ?> ctx, String path) {
93
94         validateXPath(path);
95
96         List<String> nodeNames = splitPathToNodeNames(path);
97         List<QName> qNames = new ArrayList<>();
98
99         for (String nodeName : nodeNames) {
100             try {
101                 final QName qName = Utils.qNameFromArgument(ctx, nodeName);
102                 qNames.add(qName);
103             } catch (Exception e) {
104                 throw new IllegalArgumentException(e);
105             }
106         }
107
108         return qNames;
109     }
110
111     public static String stringFromStringContext(final YangStatementParser.ArgumentContext context) {
112         StringBuilder sb = new StringBuilder();
113         List<TerminalNode> strings = context.STRING();
114         if (strings.size() == 0) {
115             strings = Arrays.asList(context.IDENTIFIER());
116         }
117         for (TerminalNode stringNode : strings) {
118             final String str = stringNode.getText();
119             char firstChar = str.charAt(0);
120             final CharMatcher quoteMatcher;
121             if (SINGLE_QUOTE_MATCHER.matches(firstChar)) {
122                 quoteMatcher = SINGLE_QUOTE_MATCHER;
123             } else if (DOUBLE_QUOTE_MATCHER.matches(firstChar)) {
124                 quoteMatcher = DOUBLE_QUOTE_MATCHER;
125             } else {
126                 sb.append(str);
127                 continue;
128             }
129             sb.append(quoteMatcher.removeFrom(str.substring(1, str.length() - 1)));
130         }
131         return sb.toString();
132     }
133
134     public static QName qNameFromArgument(StmtContext<?, ?, ?> ctx, String value) {
135
136         String prefix = null;
137         QNameModule qNameModule = null;
138         try {
139             qNameModule = QNameModule.create(new URI(""), new Date(0));
140         } catch (URISyntaxException e) {
141             e.printStackTrace();
142         }
143         String localName = null;
144
145         String[] namesParts = value.split(":");
146         switch (namesParts.length) {
147         case 1:
148             localName = namesParts[0];
149
150             if (StmtContextUtils.producesDeclared(ctx.getRoot(), ModuleStatement.class)) {
151                 prefix = firstAttributeOf(ctx.getRoot().declaredSubstatements(), PrefixStatement.class);
152                 qNameModule = ctx.getFromNamespace(PrefixToModule.class, prefix);
153
154             } else if (StmtContextUtils.producesDeclared(ctx.getRoot(), SubmoduleStatement.class)) {
155                 String belongsToModuleName = firstAttributeOf(ctx.getRoot().declaredSubstatements(),
156                         BelongsToStatement.class);
157                 qNameModule = ctx.getFromNamespace(ModuleNameToModuleQName.class, belongsToModuleName);
158             }
159             break;
160         case 2:
161             prefix = namesParts[0];
162             localName = namesParts[1];
163
164             ModuleIdentifier impModIdentifier = ctx.getRoot().getFromNamespace(ImpPrefixToModuleIdentifier.class,
165                     prefix);
166             qNameModule = ctx.getFromNamespace(ModuleIdentifierToModuleQName.class, impModIdentifier);
167
168             if (qNameModule == null && StmtContextUtils.producesDeclared(ctx.getRoot(), SubmoduleStatement.class)) {
169                 String moduleName = ctx.getRoot().getFromNamespace(BelongsToPrefixToModuleName.class, prefix);
170                 qNameModule = ctx.getFromNamespace(ModuleNameToModuleQName.class, moduleName);
171             }
172
173             break;
174         default:
175             break;
176         }
177
178         return QName.create(qNameModule, localName);
179     }
180
181     @Nullable
182     public static StatementContextBase<?, ?, ?> findCtxOfNodeInRoot(StatementContextBase<?, ?, ?> rootStmtCtx,
183             final SchemaNodeIdentifier node) {
184
185         StatementContextBase<?, ?, ?> parent = rootStmtCtx;
186         final Iterator<QName> pathIter = node.getPathFromRoot().iterator();
187
188         QName targetNode = pathIter.next();
189
190         while (pathIter.hasNext()) {
191
192             for (StatementContextBase<?, ?, ?> child : parent.declaredSubstatements()) {
193
194                 if (targetNode.equals(child.getStatementArgument())) {
195                     parent = child;
196                     targetNode = pathIter.next();
197                 }
198             }
199
200             if (parent.equals(rootStmtCtx)) {
201
202                 return null;
203             }
204         }
205
206         StatementContextBase<?, ?, ?> targetCtx = null;
207
208         for (StatementContextBase<?, ?, ?> child : parent.declaredSubstatements()) {
209
210             if (targetNode.equals(child.getStatementArgument())) {
211                 targetCtx = child;
212             }
213         }
214
215         return targetCtx;
216     }
217
218     public static SchemaPath getSchemaPath(StmtContext<?, ?, ?> ctx) {
219
220         Iterator<Object> argumentsIterator = ctx.getArgumentsFromRoot().iterator();
221         argumentsIterator.next(); // skip root argument
222
223         List<QName> qNamesFromRoot = new LinkedList<>();
224
225         while (argumentsIterator.hasNext()) {
226             Object argument = argumentsIterator.next();
227             if (argument instanceof QName) {
228                 QName qname = (QName) argument;
229                 qNamesFromRoot.add(qname);
230             } else
231                 return SchemaPath.SAME;
232         }
233
234         return SchemaPath.create(qNamesFromRoot, true);
235     }
236 }