d86b49d78bccc6c219a475ea2d9ad89ac491bd7b
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / model / parser / impl / YangModelParserImpl.java
1 /*
2  * Copyright (c) 2013 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.controller.yang.model.parser.impl;
9
10 import java.io.File;
11 import java.io.FileInputStream;
12 import java.io.IOException;
13 import java.util.ArrayList;
14 import java.util.Calendar;
15 import java.util.Date;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.TreeMap;
22
23 import org.antlr.v4.runtime.ANTLRInputStream;
24 import org.antlr.v4.runtime.CommonTokenStream;
25 import org.antlr.v4.runtime.tree.ParseTree;
26 import org.antlr.v4.runtime.tree.ParseTreeWalker;
27 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
28 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
29 import org.opendaylight.controller.model.util.UnknownType;
30 import org.opendaylight.controller.yang.common.QName;
31 import org.opendaylight.controller.yang.model.api.AugmentationSchema;
32 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
33 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
34 import org.opendaylight.controller.yang.model.api.Module;
35 import org.opendaylight.controller.yang.model.api.ModuleImport;
36 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
37 import org.opendaylight.controller.yang.model.api.RpcDefinition;
38 import org.opendaylight.controller.yang.model.api.SchemaContext;
39 import org.opendaylight.controller.yang.model.api.SchemaPath;
40 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
41 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;
42 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder;
43 import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;
44 import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
45 import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;
46 import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
47 import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 public class YangModelParserImpl implements YangModelParser {
52
53     private static final Logger logger = LoggerFactory
54             .getLogger(YangModelParserImpl.class);
55
56     @Override
57     public Module parseYangModel(String yangFile) {
58         final Map<String, TreeMap<Date, ModuleBuilder>> modules = loadFiles(yangFile);
59         Set<Module> result = build(modules);
60         return result.iterator().next();
61     }
62
63     @Override
64     public Set<Module> parseYangModels(String... yangFiles) {
65         final Map<String, TreeMap<Date, ModuleBuilder>> modules = loadFiles(yangFiles);
66         Set<Module> result = build(modules);
67         return result;
68     }
69
70     @Override
71     public SchemaContext resolveSchemaContext(Set<Module> modules) {
72         return new SchemaContextImpl(modules);
73     }
74
75     private Set<Module> build(Map<String, TreeMap<Date, ModuleBuilder>> modules) {
76         // first validate
77         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
78             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
79                 ModuleBuilder moduleBuilder = childEntry.getValue();
80                 validateBuilder(modules, moduleBuilder);
81             }
82         }
83
84         // then build
85         final Set<Module> result = new HashSet<Module>();
86         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
87             final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
88             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
89                 ModuleBuilder moduleBuilder = childEntry.getValue();
90                 modulesByRevision.put(childEntry.getKey(),moduleBuilder.build());
91                 result.add(moduleBuilder.build());
92             }
93         }
94
95         return result;
96     }
97
98     private void validateBuilder(Map<String, TreeMap<Date, ModuleBuilder>> modules, ModuleBuilder builder) {
99         resolveTypedefs(modules, builder);
100         resolveAugments(modules, builder);
101     }
102
103     private void resolveTypedefs(Map<String, TreeMap<Date, ModuleBuilder>> modules, ModuleBuilder builder) {
104         Map<List<String>, TypeAwareBuilder> dirtyNodes = builder.getDirtyNodes();
105         if (dirtyNodes.size() == 0) {
106             return;
107         } else {
108             for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes.entrySet()) {
109                 TypeAwareBuilder tab = entry.getValue();
110                 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(modules,entry.getValue(), builder);
111                 tab.setType(tdb.build());
112             }
113         }
114     }
115
116     private TypeDefinitionBuilder findTypeDefinitionBuilder(Map<String, TreeMap<Date, ModuleBuilder>> modules, TypeAwareBuilder typeBuilder, ModuleBuilder builder) {
117         UnknownType type = (UnknownType) typeBuilder.getType();
118         QName typeQName = type.getQName();
119         String typeName = type.getQName().getLocalName();
120         String prefix = typeQName.getPrefix();
121
122         ModuleBuilder dependentModuleBuilder;
123         if (prefix.equals(builder.getPrefix())) {
124             dependentModuleBuilder = builder;
125         } else {
126             ModuleImport dependentModuleImport = getDependentModuleImport(builder, prefix);
127             String dependentModuleName = dependentModuleImport.getModuleName();
128             Date dependentModuleRevision = dependentModuleImport.getRevision();
129             TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
130             if(dependentModuleRevision == null) {
131                 dependentModuleBuilder = moduleBuildersByRevision.lastEntry().getValue();
132             } else {
133                 dependentModuleBuilder = moduleBuildersByRevision.get(dependentModuleRevision);
134             }
135         }
136
137         final Set<TypeDefinitionBuilder> typedefs = dependentModuleBuilder.getModuleTypedefs();
138
139         TypeDefinitionBuilder lookedUpBuilder = null;
140         for (TypeDefinitionBuilder tdb : typedefs) {
141             QName qname = tdb.getQName();
142             if (qname.getLocalName().equals(typeName)) {
143                 lookedUpBuilder = tdb;
144                 break;
145             }
146         }
147
148         if (lookedUpBuilder.getBaseType() instanceof UnknownType) {
149             return findTypeDefinitionBuilder(modules, (TypeAwareBuilder) lookedUpBuilder, dependentModuleBuilder);
150         } else {
151             return lookedUpBuilder;
152         }
153     }
154
155     private void resolveAugments(Map<String, TreeMap<Date, ModuleBuilder>> modules, ModuleBuilder builder) {
156         Set<AugmentationSchemaBuilder> augmentBuilders = builder.getAddedAugments();
157
158         Set<AugmentationSchema> augments = new HashSet<AugmentationSchema>();
159         for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) {
160             SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
161             String prefix = null;
162             List<String> augmentTargetPath = new ArrayList<String>();
163             for (QName pathPart : augmentTargetSchemaPath.getPath()) {
164                 prefix = pathPart.getPrefix();
165                 augmentTargetPath.add(pathPart.getLocalName());
166             }
167             ModuleImport dependentModuleImport = getDependentModuleImport(builder, prefix);
168             String dependentModuleName = dependentModuleImport.getModuleName();
169             augmentTargetPath.add(0, dependentModuleName);
170
171             Date dependentModuleRevision = dependentModuleImport.getRevision();
172
173             TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
174             ModuleBuilder dependentModule;
175             if(dependentModuleRevision == null) {
176                 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
177             } else {
178                 dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
179             }
180
181             AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule.getNode(augmentTargetPath);
182             AugmentationSchema result = augmentBuilder.build();
183             augmentTarget.addAugmentation(result);
184             fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget);
185             augments.add(result);
186         }
187         builder.setAugmentations(augments);
188     }
189
190     private void fillAugmentTarget(AugmentationSchemaBuilder augment,
191             ChildNodeBuilder target) {
192         for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
193             builder.setAugmenting(true);
194             target.addChildNode(builder);
195         }
196     }
197
198     private Map<String, TreeMap<Date, ModuleBuilder>> loadFiles(String... yangFiles) {
199         final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
200
201         final YangModelParserListenerImpl yangModelParser = new YangModelParserListenerImpl();
202         final ParseTreeWalker walker = new ParseTreeWalker();
203
204         List<ParseTree> trees = parseFiles(yangFiles);
205
206         ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
207
208         for (int i = 0; i < trees.size(); i++) {
209             walker.walk(yangModelParser, trees.get(i));
210             builders[i] = yangModelParser.getModuleBuilder();
211         }
212
213         for (ModuleBuilder builder : builders) {
214             final String builderName = builder.getName();
215             Date builderRevision = builder.getRevision();
216             if(builderRevision == null) {
217                 builderRevision = createEpochTime();
218             }
219
220             TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
221             if (builderByRevision == null) {
222                 builderByRevision = new TreeMap<Date, ModuleBuilder>();
223             }
224             builderByRevision.put(builderRevision, builder);
225
226             modules.put(builderName, builderByRevision);
227         }
228         return modules;
229     }
230
231     private List<ParseTree> parseFiles(String... yangFileNames) {
232         List<ParseTree> trees = new ArrayList<ParseTree>();
233         for (String fileName : yangFileNames) {
234             trees.add(parseFile(fileName));
235         }
236         return trees;
237     }
238
239     private ParseTree parseFile(String yangFileName) {
240         ParseTree result = null;
241         try {
242             final File yangFile = new File(yangFileName);
243             final FileInputStream inStream = new FileInputStream(yangFile);
244             final ANTLRInputStream input = new ANTLRInputStream(inStream);
245             final YangLexer lexer = new YangLexer(input);
246             final CommonTokenStream tokens = new CommonTokenStream(lexer);
247             final YangParser parser = new YangParser(tokens);
248             result = parser.yang();
249         } catch (IOException e) {
250             logger.warn("Exception while reading yang file: " + yangFileName, e);
251         }
252         return result;
253     }
254
255     private ModuleImport getDependentModuleImport(ModuleBuilder builder, String prefix) {
256         ModuleImport moduleImport = null;
257         for (ModuleImport mi : builder.getModuleImports()) {
258             if (mi.getPrefix().equals(prefix)) {
259                 moduleImport = mi;
260                 break;
261             }
262         }
263         return moduleImport;
264     }
265
266     private Date createEpochTime() {
267         Calendar c = Calendar.getInstance();
268         c.setTimeInMillis(0);
269         return c.getTime();
270     }
271
272     private static class SchemaContextImpl implements SchemaContext {
273         private final Set<Module> modules;
274
275         private SchemaContextImpl(Set<Module> modules) {
276             this.modules = modules;
277         }
278
279         @Override
280         public Set<DataSchemaNode> getDataDefinitions() {
281             final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
282             for (Module m : modules) {
283                 dataDefs.addAll(m.getChildNodes());
284             }
285             return dataDefs;
286         }
287
288         @Override
289         public Set<Module> getModules() {
290             return modules;
291         }
292
293         @Override
294         public Set<NotificationDefinition> getNotifications() {
295             final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
296             for (Module m : modules) {
297                 notifications.addAll(m.getNotifications());
298             }
299             return notifications;
300         }
301
302         @Override
303         public Set<RpcDefinition> getOperations() {
304             final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
305             for (Module m : modules) {
306                 rpcs.addAll(m.getRpcs());
307             }
308             return rpcs;
309         }
310
311         @Override
312         public Set<ExtensionDefinition> getExtensions() {
313             final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
314             for (Module m : modules) {
315                 extensions.addAll(m.getExtensionSchemaNodes());
316             }
317             return extensions;
318         }
319     }
320
321 }