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
7 package org.opendaylight.yangtools.yang.parser.impl.util;
9 import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.getArgumentString;
10 import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.getFirstContext;
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;
31 * Helper transfer object which holds basic and dependency information for YANG
36 * There are two concrete implementations of this interface:
38 * <li>{@link ModuleDependencyInfo} - Dependency information for module</li>
39 * <li>{@link SubmoduleDependencyInfo} - Dependency information for submodule</li>
42 * @see ModuleDependencyInfo
43 * @see SubmoduleDependencyInfo
46 public abstract class YangModelDependencyInfo {
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;
55 YangModelDependencyInfo(final String name, final String formattedRevision,
56 final ImmutableSet<ModuleImport> imports, final ImmutableSet<ModuleImport> includes) {
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) //
69 * Returns immutable collection of all module imports.
71 * This collection contains both <code>import</code> statements
72 * and <code>include</code> statements for submodules.
74 * @return Immutable collection of imports.
76 public ImmutableSet<ModuleImport> getDependencies() {
85 public String getName() {
90 * Returns formatted revision string
92 * @return formatted revision string
94 public String getFormattedRevision() {
95 return formattedRevision;
108 public int hashCode() {
109 final int prime = 31;
111 result = prime * result + ((formattedRevision == null) ? 0 : formattedRevision.hashCode());
112 result = prime * result + ((name == null) ? 0 : name.hashCode());
117 public boolean equals(final Object obj) {
124 if (!(obj instanceof YangModelDependencyInfo)) {
127 YangModelDependencyInfo other = (YangModelDependencyInfo) obj;
128 if (formattedRevision == null) {
129 if (other.formattedRevision != null) {
132 } else if (!formattedRevision.equals(other.formattedRevision)) {
136 if (other.name != null) {
139 } else if (!name.equals(other.name)) {
146 * Extracts {@link YangModelDependencyInfo} from input stream
147 * containing YANG model.
149 * This parsing does not validate full YANG module, only
150 * parses header up to the revisions and imports.
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
158 public static YangModelDependencyInfo fromInputStream(final InputStream yangStream) {
159 YangContext yangContext = YangParserImpl.parseStreamWithoutErrorListeners(yangStream);
161 Optional<Module_stmtContext> moduleCtx = getFirstContext(yangContext, Module_stmtContext.class);
162 if (moduleCtx.isPresent()) {
163 return parseModuleContext(moduleCtx.get());
165 Optional<Submodule_stmtContext> submoduleCtx = getFirstContext(yangContext, Submodule_stmtContext.class);
166 if (submoduleCtx.isPresent()) {
167 return parseSubmoduleContext(submoduleCtx.get());
169 throw new IllegalArgumentException("Supplied stream is not valid yang file.");
172 private static YangModelDependencyInfo parseModuleContext(final Module_stmtContext module) {
173 String name = getArgumentString(module);
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());
181 return new ModuleDependencyInfo(name, latestRevision, namespace, imports, includes);
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));
191 return builder.build();
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;
203 return latestRevision;
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);
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());
215 return new SubmoduleDependencyInfo(name, latestRevision, belongsTo, imports, includes);
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));
225 return builder.build();
228 private static Date getRevision(final Revision_date_stmtContext revision_date_stmt) {
229 if (revision_date_stmt == null) {
232 String formatedDate = getArgumentString(revision_date_stmt);
233 return QName.parseRevision(formatedDate);
238 * Dependency information for YANG module.
241 public static final class ModuleDependencyInfo extends YangModelDependencyInfo {
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);
249 public String toString() {
250 return "Module [name=" + getName() + ", revision=" + getRevision() + ", dependencies=" + getDependencies()
257 * Dependency information for submodule, also provides name
261 public static final class SubmoduleDependencyInfo extends YangModelDependencyInfo {
263 private final String belongsTo;
266 * Returns name of parent module.
269 public String getParentModule() {
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;
280 public String toString() {
281 return "Submodule [name=" + getName() + ", revision=" + getRevision() + ", dependencies="
282 + getDependencies() + "]";
287 * Utility implementation of {@link ModuleImport} to be used by
288 * {@link YangModelDependencyInfo}.
291 private static final class ModuleImportImpl implements ModuleImport {
293 private final Date revision;
294 private final String name;
296 public ModuleImportImpl(final String moduleName, final Date revision) {
297 this.name = moduleName;
298 this.revision = revision;
302 public String getModuleName() {
307 public Date getRevision() {
308 return this.revision;
312 public String getPrefix() {
317 public int hashCode() {
318 final int prime = 31;
320 result = prime * result + ((name == null) ? 0 : name.hashCode());
321 result = prime * result + ((revision == null) ? 0 : revision.hashCode());
326 public boolean equals(final Object obj) {
333 if (getClass() != obj.getClass()) {
336 ModuleImportImpl other = (ModuleImportImpl) obj;
338 if (other.name != null) {
341 } else if (!name.equals(other.name)) {
344 if (revision == null) {
345 if (other.revision != null) {
348 } else if (!revision.equals(other.revision)) {
355 public String toString() {
356 return "ModuleImportImpl [name=" + name + ", revision=" + QName.formattedRevision(revision) + "]";