Eliminate LeafRefPathParseException
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / leafref / LeafRefPathParserListenerImpl.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.impl.leafref;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.Lists;
12 import java.net.URI;
13 import java.util.ArrayList;
14 import java.util.Date;
15 import java.util.List;
16 import java.util.Optional;
17 import org.antlr.v4.runtime.tree.TerminalNode;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.common.QNameModule;
20 import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.IdentifierContext;
21 import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Node_identifierContext;
22 import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_argContext;
23 import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_equality_exprContext;
24 import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_predicateContext;
25 import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.PrefixContext;
26 import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Rel_path_keyexprContext;
27 import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Relative_pathContext;
28 import org.opendaylight.yangtools.yang.model.api.Module;
29 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
30 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
31 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
32
33 final class LeafRefPathParserListenerImpl extends LeafRefPathParserBaseListener{
34
35     private final List<QNameWithPredicateBuilder> leafRefPathQnameList = new ArrayList<>();
36     private final SchemaContext schemaContext;
37     private final Module module;
38   //FIXME use for identifier path completion
39     private final SchemaNode node;
40
41     private ParsingState currentParsingState = ParsingState.LEAF_REF_PATH;
42     private List<QNameWithPredicateBuilder> predicatePathKeyQnameList;
43     private QNameWithPredicateBuilder currentLeafRefPathQName;
44     private QNamePredicateBuilder currentPredicate;
45     private QNameModule currentQnameModule;
46     private String currentQNameLocalName;
47     private LeafRefPath leafRefPath;
48     private boolean relativePath = false;
49
50     private enum ParsingState {
51         LEAF_REF_PATH, PATH_PREDICATE, PREDICATE_PATH_EQUALITY_EXPR, PATH_KEY_EXPR
52     }
53
54     public LeafRefPathParserListenerImpl(final SchemaContext schemaContext, final Module currentModule, final SchemaNode currentNode) {
55        this.schemaContext = schemaContext;
56        this.module = currentModule;
57        this.node = currentNode;
58     }
59
60     @Override
61     public void enterPath_predicate(final Path_predicateContext ctx) {
62         currentParsingState=ParsingState.PATH_PREDICATE;
63         currentPredicate = new QNamePredicateBuilder();
64     }
65
66     @Override
67     public void exitPath_predicate(final Path_predicateContext ctx) {
68         currentLeafRefPathQName.addQNamePredicate(currentPredicate.build());
69         currentPredicate = null;
70         currentParsingState=ParsingState.LEAF_REF_PATH;
71     }
72
73
74     @Override
75     public void enterRel_path_keyexpr(final Rel_path_keyexprContext ctx) {
76         currentParsingState=ParsingState.PATH_KEY_EXPR;
77
78         final List<TerminalNode> dots = ctx.DOTS();
79         predicatePathKeyQnameList = new ArrayList<>(dots.size());
80         for (int i = 0; i < dots.size(); ++i) {
81             predicatePathKeyQnameList.add(QNameWithPredicateBuilder.UP_PARENT_BUILDER);
82         }
83     }
84
85     @Override
86     public void exitRel_path_keyexpr(final Rel_path_keyexprContext ctx) {
87         final LeafRefPath pathKeyExpression = LeafRefPath.create(Lists.transform(predicatePathKeyQnameList,
88             QNameWithPredicateBuilder::build), false);
89         currentPredicate.setPathKeyExpression(pathKeyExpression);
90
91         currentParsingState=ParsingState.PREDICATE_PATH_EQUALITY_EXPR;
92     }
93
94     @Override
95     public void enterRelative_path(final Relative_pathContext ctx) {
96         relativePath = true;
97         final List<TerminalNode> dots = ctx.DOTS();
98         for (int i = 0; i < dots.size(); ++i) {
99             leafRefPathQnameList.add(QNameWithPredicateBuilder.UP_PARENT_BUILDER);
100         }
101     }
102
103     @Override
104     public void enterPath_equality_expr(final Path_equality_exprContext ctx) {
105         currentParsingState = ParsingState.PREDICATE_PATH_EQUALITY_EXPR;
106     }
107
108     @Override
109     public void exitPath_equality_expr(final Path_equality_exprContext ctx) {
110         currentParsingState = ParsingState.PATH_PREDICATE;
111     }
112
113     @Override
114     public void enterPrefix(final PrefixContext ctx) {
115         final String prefix = ctx.getText();
116         if (!module.getPrefix().equals(prefix)) {
117             final Optional<QNameModule> qnameModuleOpt = getQNameModuleForImportPrefix(prefix);
118             Preconditions.checkArgument(qnameModuleOpt.isPresent(), "No module import for prefix: %s in module: %s",
119                 prefix, module.getName());
120             currentQnameModule = qnameModuleOpt.get();
121         } else {
122             currentQnameModule = module.getQNameModule();
123         }
124     }
125
126     @Override
127     public void exitPath_arg(final Path_argContext ctx) {
128         leafRefPath = LeafRefPath.create(Lists.transform(leafRefPathQnameList, QNameWithPredicateBuilder::build),
129             !relativePath);
130     }
131
132     @Override
133     public void enterIdentifier(final IdentifierContext ctx) {
134         currentQNameLocalName = ctx.getText();
135     }
136
137     @Override
138     public void exitNode_identifier(final Node_identifierContext ctx) {
139         if (currentQnameModule == null) {
140             currentQnameModule = module.getQNameModule();
141         }
142
143         if (currentParsingState == ParsingState.PREDICATE_PATH_EQUALITY_EXPR) {
144             currentPredicate.setIdentifier(QName.create(currentQnameModule, currentQNameLocalName));
145         } else {
146             final QNameWithPredicateBuilder qnameBuilder = new QNameWithPredicateBuilder(currentQnameModule,
147                 currentQNameLocalName);
148
149             if (currentParsingState == ParsingState.PATH_KEY_EXPR) {
150                 predicatePathKeyQnameList.add(qnameBuilder);
151             } else if (currentParsingState == ParsingState.LEAF_REF_PATH) {
152                 currentLeafRefPathQName = qnameBuilder;
153                 leafRefPathQnameList.add(qnameBuilder);
154             }
155         }
156         currentQnameModule = null;
157         currentQNameLocalName = null;
158     }
159
160     public LeafRefPath getLeafRefPath() {
161         return leafRefPath;
162     }
163
164     private URI getNamespaceForImportPrefix(final String prefix) {
165         final ModuleImport moduleImport = getModuleImport(prefix);
166         final Module findedModule = schemaContext.findModuleByName(moduleImport.getModuleName(), moduleImport.getRevision());
167
168         return findedModule.getNamespace();
169     }
170
171     private Optional<QNameModule> getQNameModuleForImportPrefix(final String prefix) {
172         final ModuleImport moduleImport = getModuleImport(prefix);
173         if (moduleImport == null) {
174             return Optional.empty();
175         }
176
177         final String moduleName = moduleImport.getModuleName();
178         final Date revision = moduleImport.getRevision();
179         final Module foundModule = schemaContext.findModuleByName(moduleName, revision);
180
181         return Optional.of(foundModule.getQNameModule());
182     }
183
184     private ModuleImport getModuleImport(final String prefix) {
185         return module.getImports().stream().filter(imp -> prefix.equals(imp.getPrefix())).findFirst().orElse(null);
186     }
187 }