Bug 2363, Bug 2205. Beta version of LeafRefContext tree computation
[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.Function;
11 import com.google.common.collect.Lists;
12 import java.net.URI;
13 import java.util.Date;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.Set;
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
34
35 final class LeafRefPathParserListenerImpl extends LeafRefPathParserBaseListener{
36
37     private final SchemaContext schemaContext;
38     private final Module module;
39     private LeafRefPath leafRefPath;
40     private boolean relativePath=false;
41     private QNameWithPredicateBuilder currentLeafRefPathQName;
42     private QNamePredicateBuilder currentPredicate;
43     private QNameModule currentQnameModule;
44     private String currentQNameLocalName;
45     private final LinkedList<QNameWithPredicateBuilder> leafRefPathQnameList;
46     private LinkedList<QNameWithPredicateBuilder> predicatePathKeyQnameList;
47     private final SchemaNode node; //FIXME use for identifier path completion
48     private ParsingState currentParsingState;
49
50     Function<QNameWithPredicateBuilder, QNameWithPredicate> build = new Function<QNameWithPredicateBuilder, QNameWithPredicate>() {
51         @Override
52         public QNameWithPredicate apply(final QNameWithPredicateBuilder builder) {
53            return builder.build();
54         }
55      };
56
57     private enum ParsingState {
58         LEAF_REF_PATH, PATH_PREDICATE, PREDICATE_PATH_EQUALITY_EXPR, PATH_KEY_EXPR
59     }
60
61     public LeafRefPathParserListenerImpl(final SchemaContext schemaContext, final Module currentModule, final SchemaNode currentNode) {
62        this.schemaContext = schemaContext;
63        this.module = currentModule;
64        this.leafRefPathQnameList = new LinkedList<QNameWithPredicateBuilder>();
65        this.node=currentNode;
66        this.currentParsingState = ParsingState.LEAF_REF_PATH;
67     }
68
69     @Override
70     public void enterPath_predicate(final Path_predicateContext ctx) {
71         currentParsingState=ParsingState.PATH_PREDICATE;
72         currentPredicate = new QNamePredicateBuilder();
73     }
74
75
76     @Override
77     public void exitPath_predicate(final Path_predicateContext ctx) {
78         currentLeafRefPathQName.addQNamePredicate(currentPredicate.build());
79         currentPredicate = null;
80         currentParsingState=ParsingState.LEAF_REF_PATH;
81     }
82
83
84     @Override
85     public void enterRel_path_keyexpr(final Rel_path_keyexprContext ctx) {
86         currentParsingState=ParsingState.PATH_KEY_EXPR;
87         predicatePathKeyQnameList = new LinkedList<QNameWithPredicateBuilder>();
88         final List<TerminalNode> dots = ctx.DOTS();
89         for (final TerminalNode parent : dots) {
90             predicatePathKeyQnameList.add(QNameWithPredicateBuilder.UP_PARENT_BUILDER);
91         }
92     }
93
94
95     @Override
96     public void exitRel_path_keyexpr(final Rel_path_keyexprContext ctx) {
97
98         final LeafRefPath pathKeyExpression = LeafRefPath.create(Lists.transform(predicatePathKeyQnameList,build), false);
99         currentPredicate.setPathKeyExpression(pathKeyExpression);
100
101         currentParsingState=ParsingState.PREDICATE_PATH_EQUALITY_EXPR;
102     }
103
104     @Override
105     public void enterRelative_path(final Relative_pathContext ctx) {
106
107         relativePath = true;
108         final List<TerminalNode> dots = ctx.DOTS();
109         for (final TerminalNode parent : dots) {
110             leafRefPathQnameList.add(QNameWithPredicateBuilder.UP_PARENT_BUILDER);
111         }
112
113     }
114
115     @Override
116     public void enterPath_equality_expr(final Path_equality_exprContext ctx) {
117         currentParsingState=ParsingState.PREDICATE_PATH_EQUALITY_EXPR;
118     }
119
120
121     @Override
122     public void exitPath_equality_expr(final Path_equality_exprContext ctx) {
123
124         currentParsingState=ParsingState.PATH_PREDICATE;
125     }
126
127     @Override
128     public void enterPrefix(final PrefixContext ctx) {
129
130         if (module.getPrefix().equals(ctx.getText())) {
131             currentQnameModule = module.getQNameModule();
132         } else {
133             currentQnameModule = getQNameModuleForImportPrefix(ctx.getText());
134         }
135     }
136
137     @Override
138     public void exitPath_arg(final Path_argContext ctx) {
139         leafRefPath = LeafRefPath.create(Lists.transform(leafRefPathQnameList,build), !relativePath);
140     }
141
142
143     @Override
144     public void enterIdentifier(final IdentifierContext ctx) {
145         currentQNameLocalName = ctx.getText();
146     }
147
148     @Override
149     public void exitNode_identifier(final Node_identifierContext ctx) {
150
151         if (currentQnameModule == null) {
152             currentQnameModule = module.getQNameModule();
153         }
154
155         if (currentParsingState == ParsingState.PREDICATE_PATH_EQUALITY_EXPR) {
156             final QName qname = QName.create(currentQnameModule,
157                     currentQNameLocalName);
158             currentPredicate.setIdentifier(qname);
159         } else {
160
161             final QNameWithPredicateBuilder qnameBuilder = new QNameWithPredicateBuilder(
162                     currentQnameModule, currentQNameLocalName);
163
164             if (currentParsingState == ParsingState.PATH_KEY_EXPR) {
165                 predicatePathKeyQnameList.add(qnameBuilder);
166             } else if (currentParsingState == ParsingState.LEAF_REF_PATH) {
167                 currentLeafRefPathQName = qnameBuilder;
168                 leafRefPathQnameList.add(qnameBuilder);
169             }
170         }
171         currentQnameModule = null;
172         currentQNameLocalName = null;
173     }
174
175     public LeafRefPath getLeafRefPath() {
176         return leafRefPath;
177     }
178
179
180     private URI getNamespaceForImportPrefix(final String prefix){
181         final ModuleImport moduleImport = getModuleImport(prefix);
182         final Module findedModule = schemaContext.findModuleByName(moduleImport.getModuleName(), moduleImport.getRevision());
183
184         return findedModule.getNamespace();
185     }
186
187     private QNameModule getQNameModuleForImportPrefix(final String prefix) {
188         final ModuleImport moduleImport = getModuleImport(prefix);
189
190         if (moduleImport == null) {
191             throw new LeafRefPathParseException("No module import for prefix: "
192                     + prefix + " in module: " + module.getName());
193         }
194
195         final String moduleName = moduleImport.getModuleName();
196         final Date revision = moduleImport.getRevision();
197         final Module findedModule = schemaContext.findModuleByName(moduleName,
198                 revision);
199
200         return findedModule.getQNameModule();
201     }
202
203
204     private ModuleImport getModuleImport(final String prefix) {
205         final Set<ModuleImport> imports = module.getImports();
206
207         for (final ModuleImport moduleImport : imports) {
208             if(moduleImport.getPrefix().equals(prefix)) {
209                 return moduleImport;
210             }
211         }
212         return null;
213     }
214
215 }