Merge "BUG-597: removed dependency on GeneratedTOBuilderImpl from BindingGeneratorUti...
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / util / YangModelDependencyInfo.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
3  * This program and the accompanying materials are made available under the
4  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5  * and is available at http://www.eclipse.org/legal/eplv10.html
6  */
7 package org.opendaylight.yangtools.yang.parser.impl.util;
8
9 import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.getArgumentString;
10 import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.getFirstContext;
11
12 import com.google.common.base.Optional;
13 import com.google.common.collect.ImmutableSet;
14 import java.io.InputStream;
15 import java.util.Date;
16 import java.util.List;
17 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
18 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
19 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Include_stmtContext;
20 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
21 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
22 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtContext;
23 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext;
24 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext;
25 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
28 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
29
30 /**
31  * Helper transfer object which holds basic and dependency information for YANG
32  * model.
33  *
34  *
35  *
36  * There are two concrete implementations of this interface:
37  * <ul>
38  * <li>{@link ModuleDependencyInfo} - Dependency information for module</li>
39  * <li>{@link SubmoduleDependencyInfo} - Dependency information for submodule</li>
40  * </ul>
41  *
42  * @see ModuleDependencyInfo
43  * @see SubmoduleDependencyInfo
44  *
45  */
46 public abstract class YangModelDependencyInfo {
47
48     private final String name;
49     private final String formattedRevision;
50     private final Date revision;
51     private final ImmutableSet<ModuleImport> submoduleIncludes;
52     private final ImmutableSet<ModuleImport> moduleImports;
53     private final ImmutableSet<ModuleImport> dependencies;
54
55     YangModelDependencyInfo(final String name, final String formattedRevision,
56                             final ImmutableSet<ModuleImport> imports, final ImmutableSet<ModuleImport> includes) {
57         this.name = name;
58         this.formattedRevision = formattedRevision;
59         this.revision = QName.parseRevision(formattedRevision);
60         this.moduleImports = imports;
61         this.submoduleIncludes = includes;
62         this.dependencies = ImmutableSet.<ModuleImport> builder() //
63                 .addAll(moduleImports) //
64                 .addAll(submoduleIncludes) //
65                 .build();
66     }
67
68     /**
69      * Returns immutable collection of all module imports.
70      *
71      * This collection contains both <code>import</code> statements
72      * and <code>include</code> statements for submodules.
73      *
74      * @return Immutable collection of imports.
75      */
76     public ImmutableSet<ModuleImport> getDependencies() {
77         return dependencies;
78     }
79
80     /**
81      * Returns model name
82      *
83      * @return model name
84      */
85     public String getName() {
86         return name;
87     }
88
89     /**
90      * Returns formatted revision string
91      *
92      * @return formatted revision string
93      */
94     public String getFormattedRevision() {
95         return formattedRevision;
96     }
97
98     /**
99      * Returns revision
100      *
101      * @return revision
102      */
103     Date getRevision() {
104         return revision;
105     }
106
107     @Override
108     public int hashCode() {
109         final int prime = 31;
110         int result = 1;
111         result = prime * result + ((formattedRevision == null) ? 0 : formattedRevision.hashCode());
112         result = prime * result + ((name == null) ? 0 : name.hashCode());
113         return result;
114     }
115
116     @Override
117     public boolean equals(final Object obj) {
118         if (this == obj) {
119             return true;
120         }
121         if (obj == null) {
122             return false;
123         }
124         if (!(obj instanceof YangModelDependencyInfo)) {
125             return false;
126         }
127         YangModelDependencyInfo other = (YangModelDependencyInfo) obj;
128         if (formattedRevision == null) {
129             if (other.formattedRevision != null) {
130                 return false;
131             }
132         } else if (!formattedRevision.equals(other.formattedRevision)) {
133             return false;
134         }
135         if (name == null) {
136             if (other.name != null) {
137                 return false;
138             }
139         } else if (!name.equals(other.name)) {
140             return false;
141         }
142         return true;
143     }
144
145     /**
146      * Extracts {@link YangModelDependencyInfo} from input stream
147      * containing YANG model.
148      *
149      * This parsing does not validate full YANG module, only
150      * parses header up to the revisions and imports.
151      *
152      * @param yangStream
153      *            Opened Input stream containing text source of YANG model
154      * @return {@link YangModelDependencyInfo}
155      * @throws IllegalArgumentException
156      *             If input stream is not valid YANG stream
157      */
158     public static YangModelDependencyInfo fromInputStream(final InputStream yangStream) {
159         YangContext yangContext = YangParserImpl.parseStreamWithoutErrorListeners(yangStream);
160
161         Optional<Module_stmtContext> moduleCtx = getFirstContext(yangContext, Module_stmtContext.class);
162         if (moduleCtx.isPresent()) {
163             return parseModuleContext(moduleCtx.get());
164         }
165         Optional<Submodule_stmtContext> submoduleCtx = getFirstContext(yangContext, Submodule_stmtContext.class);
166         if (submoduleCtx.isPresent()) {
167             return parseSubmoduleContext(submoduleCtx.get());
168         }
169         throw new IllegalArgumentException("Supplied stream is not valid yang file.");
170     }
171
172     private static YangModelDependencyInfo parseModuleContext(final Module_stmtContext module) {
173         String name = getArgumentString(module);
174         // String prefix =
175         // getArgumentString(module.module_header_stmts().prefix_stmt(0));
176         String namespace = getArgumentString(module.module_header_stmts().namespace_stmt(0));
177         String latestRevision = getLatestRevision(module.revision_stmts());
178         ImmutableSet<ModuleImport> imports = parseImports(module.linkage_stmts().import_stmt());
179         ImmutableSet<ModuleImport> includes = parseIncludes(module.linkage_stmts().include_stmt());
180
181         return new ModuleDependencyInfo(name, latestRevision, namespace, imports, includes);
182     }
183
184     private static ImmutableSet<ModuleImport> parseImports(final List<Import_stmtContext> importStatements) {
185         ImmutableSet.Builder<ModuleImport> builder = ImmutableSet.builder();
186         for (Import_stmtContext importStmt : importStatements) {
187             String moduleName = getArgumentString(importStmt);
188             Date revision = getRevision(importStmt.revision_date_stmt());
189             builder.add(new ModuleImportImpl(moduleName, revision));
190         }
191         return builder.build();
192     }
193
194     private static String getLatestRevision(final Revision_stmtsContext revision_stmts) {
195         List<Revision_stmtContext> revisions = revision_stmts.getRuleContexts(Revision_stmtContext.class);
196         String latestRevision = null;
197         for (Revision_stmtContext revisionStmt : revisions) {
198             String currentRevision = getArgumentString(revisionStmt);
199             if (latestRevision == null || latestRevision.compareTo(currentRevision) == -1) {
200                 latestRevision = currentRevision;
201             }
202         }
203         return latestRevision;
204     }
205
206     private static YangModelDependencyInfo parseSubmoduleContext(final Submodule_stmtContext submodule) {
207         String name = getArgumentString(submodule);
208         Belongs_to_stmtContext belongsToStmt = submodule.submodule_header_stmts().belongs_to_stmt(0);
209         String belongsTo = getArgumentString(belongsToStmt);
210
211         String latestRevision = getLatestRevision(submodule.revision_stmts());
212         ImmutableSet<ModuleImport> imports = parseImports(submodule.linkage_stmts().import_stmt());
213         ImmutableSet<ModuleImport> includes = parseIncludes(submodule.linkage_stmts().include_stmt());
214
215         return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, imports, includes);
216     }
217
218     private static ImmutableSet<ModuleImport> parseIncludes(final List<Include_stmtContext> importStatements) {
219         ImmutableSet.Builder<ModuleImport> builder = ImmutableSet.builder();
220         for (Include_stmtContext importStmt : importStatements) {
221             String moduleName = getArgumentString(importStmt);
222             Date revision = getRevision(importStmt.revision_date_stmt());
223             builder.add(new ModuleImportImpl(moduleName, revision));
224         }
225         return builder.build();
226     }
227
228     private static Date getRevision(final Revision_date_stmtContext revision_date_stmt) {
229         if (revision_date_stmt == null) {
230             return null;
231         }
232         String formatedDate = getArgumentString(revision_date_stmt);
233         return QName.parseRevision(formatedDate);
234     }
235
236     /**
237      *
238      * Dependency information for YANG module.
239      *
240      */
241     public static final class ModuleDependencyInfo extends YangModelDependencyInfo {
242
243         private ModuleDependencyInfo(final String name, final String latestRevision, final String namespace,
244                 final ImmutableSet<ModuleImport> imports, final ImmutableSet<ModuleImport> includes) {
245             super(name, latestRevision, imports, includes);
246         }
247
248         @Override
249         public String toString() {
250             return "Module [name=" + getName() + ", revision=" + getRevision() + ", dependencies=" + getDependencies()
251                     + "]";
252         }
253     }
254
255     /**
256      *
257      * Dependency information for submodule, also provides name
258      * for parent module.
259      *
260      */
261     public static final class SubmoduleDependencyInfo extends YangModelDependencyInfo {
262
263         private final String belongsTo;
264
265         /**
266          * Returns name of parent module.
267          *
268          */
269         public String getParentModule() {
270             return belongsTo;
271         }
272
273         private SubmoduleDependencyInfo(final String name, final String latestRevision, final String belongsTo,
274                 final ImmutableSet<ModuleImport> imports, final ImmutableSet<ModuleImport> includes) {
275             super(name, latestRevision, imports, includes);
276             this.belongsTo = belongsTo;
277         }
278
279         @Override
280         public String toString() {
281             return "Submodule [name=" + getName() + ", revision=" + getRevision() + ", dependencies="
282                     + getDependencies() + "]";
283         }
284     }
285
286     /**
287      * Utility implementation of {@link ModuleImport} to be used by
288      * {@link YangModelDependencyInfo}.
289      *
290      */
291     private static final class ModuleImportImpl implements ModuleImport {
292
293         private final Date revision;
294         private final String name;
295
296         public ModuleImportImpl(final String moduleName, final Date revision) {
297             this.name = moduleName;
298             this.revision = revision;
299         }
300
301         @Override
302         public String getModuleName() {
303             return this.name;
304         }
305
306         @Override
307         public Date getRevision() {
308             return this.revision;
309         }
310
311         @Override
312         public String getPrefix() {
313             return null;
314         }
315
316         @Override
317         public int hashCode() {
318             final int prime = 31;
319             int result = 1;
320             result = prime * result + ((name == null) ? 0 : name.hashCode());
321             result = prime * result + ((revision == null) ? 0 : revision.hashCode());
322             return result;
323         }
324
325         @Override
326         public boolean equals(final Object obj) {
327             if (this == obj) {
328                 return true;
329             }
330             if (obj == null) {
331                 return false;
332             }
333             if (getClass() != obj.getClass()) {
334                 return false;
335             }
336             ModuleImportImpl other = (ModuleImportImpl) obj;
337             if (name == null) {
338                 if (other.name != null) {
339                     return false;
340                 }
341             } else if (!name.equals(other.name)) {
342                 return false;
343             }
344             if (revision == null) {
345                 if (other.revision != null) {
346                     return false;
347                 }
348             } else if (!revision.equals(other.revision)) {
349                 return false;
350             }
351             return true;
352         }
353
354         @Override
355         public String toString() {
356             return "ModuleImportImpl [name=" + name + ", revision=" + QName.formattedRevision(revision) + "]";
357         }
358     }
359 }