X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fimpl%2FYangParserImpl.java;h=ce720b814857fdfcd777bdb01beb35c4494c78f0;hb=39a6b7575fc8f0a0041082c9f8a722c03ecf2e51;hp=7948158f4dee6b277493d8d2451395d3ee6b3d19;hpb=1c6811475b33129127a9e1e32bdccb199ea92afd;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java index 7948158f4d..ce720b8148 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java @@ -1,1226 +1,109 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others. All rights reserved. + * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.yangtools.yang.parser.impl; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.fillAugmentTarget; -import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findBaseIdentity; -import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findModuleFromContext; -import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findSchemaNode; -import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findSchemaNodeInModule; -import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.processAugmentation; -import static org.opendaylight.yangtools.yang.parser.builder.impl.TypeUtils.resolveType; -import static org.opendaylight.yangtools.yang.parser.builder.impl.TypeUtils.resolveTypeUnion; +import static java.util.Objects.requireNonNull; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.base.Splitter; -import com.google.common.collect.HashBiMap; -import com.google.common.io.ByteSource; -import java.io.File; +import com.google.common.collect.SetMultimap; import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.TreeMap; -import javax.annotation.concurrent.Immutable; -import org.antlr.v4.runtime.ANTLRInputStream; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.ParseTreeWalker; -import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer; -import org.opendaylight.yangtools.antlrv4.code.gen.YangParser; -import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; -import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition; -import org.opendaylight.yangtools.yang.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; -import org.opendaylight.yangtools.yang.model.api.ModuleImport; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaPath; -import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement; +import org.opendaylight.yangtools.yang.model.parser.api.YangParser; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserException; import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException; -import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder; -import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder; -import org.opendaylight.yangtools.yang.parser.builder.api.Builder; -import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder; -import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.api.ExtensionBuilder; -import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder; -import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder; -import org.opendaylight.yangtools.yang.parser.builder.api.UnknownSchemaNodeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils; -import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.GroupingUtils; -import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; -import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleImpl; -import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder; -import org.opendaylight.yangtools.yang.parser.builder.util.Comparators; -import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort; -import org.opendaylight.yangtools.yang.parser.util.NamedByteArrayInputStream; -import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream; -import org.opendaylight.yangtools.yang.parser.util.NamedInputStream; -import org.opendaylight.yangtools.yang.parser.util.YangParseException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; -@Immutable -public final class YangParserImpl implements YangContextParser { - private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class); - private static final Splitter COLON_SPLITTER = Splitter.on(':'); - private static final YangParserImpl INSTANCE = new YangParserImpl(); +@Deprecated(since = "7.0.0", forRemoval = true) +final class YangParserImpl implements YangParser { + private final org.opendaylight.yangtools.yang.parser.api.YangParser delegate; - public static YangParserImpl getInstance() { - return INSTANCE; + YangParserImpl(final org.opendaylight.yangtools.yang.parser.api.YangParser yangParser) { + this.delegate = requireNonNull(yangParser); } @Override - @Deprecated - public Set parseYangModels(final File yangFile, final File directory) { - try { - return parseFile(yangFile, directory).getModules(); - } catch (IOException | YangSyntaxErrorException e) { - throw new YangParseException("Failed to parse yang data", e); - } - } - - @Override - public SchemaContext parseFile(final File yangFile, final File directory) throws IOException, YangSyntaxErrorException { - Preconditions.checkState(yangFile.exists(), yangFile + " does not exists"); - Preconditions.checkState(directory.exists(), directory + " does not exists"); - Preconditions.checkState(directory.isDirectory(), directory + " is not a directory"); - - final String yangFileName = yangFile.getName(); - final String[] fileList = checkNotNull(directory.list(), directory + " not found or is not a directory"); - - Map sourceToFile = new LinkedHashMap<>(); - ByteSource mainFileSource = BuilderUtils.fileToByteSource(yangFile); - sourceToFile.put(mainFileSource, yangFile); - - for (String fileName : fileList) { - if (fileName.equals(yangFileName)) { - continue; - } - File dependency = new File(directory, fileName); - if (dependency.isFile()) { - sourceToFile.put(BuilderUtils.fileToByteSource(dependency), dependency); - } - } - - Map sourceToBuilder = parseSourcesToBuilders(sourceToFile.keySet(), null); - ModuleBuilder main = sourceToBuilder.get(mainFileSource); - - List moduleBuilders = new ArrayList<>(); - moduleBuilders.add(main); - filterImports(main, new ArrayList<>(sourceToBuilder.values()), moduleBuilders); - Collection resolved = resolveSubmodules(moduleBuilders); - - // module builders sorted by dependencies - List sortedBuilders = ModuleDependencySort.sort(resolved); - LinkedHashMap> modules = resolveModulesWithImports(sortedBuilders, null); - Collection unsorted = build(modules).values(); - Set result = new LinkedHashSet<>( - ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); - return resolveSchemaContext(result); - } - - @Override - @Deprecated - public Set parseYangModels(final List yangFiles) { - return parseFiles(yangFiles).getModules(); + public @NonNull Set supportedStatements() { + // TODO Auto-generated method stub + return null; } @Override - public SchemaContext parseFiles(final Collection yangFiles) { - Collection unsorted = parseYangModelsMapped(yangFiles).values(); - Set sorted = new LinkedHashSet<>( - ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); - return resolveSchemaContext(sorted); + public @NonNull Collection> supportedSourceRepresentations() { + return delegate.supportedSourceRepresentations(); } @Override - @Deprecated - public Set parseYangModels(final List yangFiles, final SchemaContext context) { + public @NonNull YangParser addSource(final SchemaSourceRepresentation source) throws IOException, + YangSyntaxErrorException { try { - return parseFiles(yangFiles, context).getModules(); - } catch (IOException | YangSyntaxErrorException e) { - throw new YangParseException("Failed to parse yang data", e); + delegate.addSource(source); + } catch (org.opendaylight.yangtools.yang.parser.api.YangSyntaxErrorException e) { + throw mapException(e); } + return this; } @Override - public SchemaContext parseFiles(final Collection yangFiles, final SchemaContext context) throws IOException, - YangSyntaxErrorException { - if (yangFiles == null) { - return resolveSchemaContext(Collections. emptySet()); - } - - Collection sources = BuilderUtils.filesToByteSources(yangFiles); - return parseSources(sources, context); - } - - @Override - @Deprecated - public Set parseYangModelsFromStreams(final List yangModelStreams) { + public @NonNull YangParser addLibSource(final SchemaSourceRepresentation source) throws IOException, + YangSyntaxErrorException { try { - Collection sources = BuilderUtils.streamsToByteSources(yangModelStreams); - return parseSources(sources).getModules(); - } catch (IOException | YangSyntaxErrorException e) { - throw new YangParseException("Failed to parse yang data", e); + delegate.addLibSource(source); + } catch (org.opendaylight.yangtools.yang.parser.api.YangSyntaxErrorException e) { + throw mapException(e); } + return this; } @Override - public SchemaContext parseSources(final Collection sources) throws IOException,YangSyntaxErrorException { - return assembleContext(parseYangModelSources(sources, null).values()); - } - - @Override - @Deprecated - public Set parseYangModelsFromStreams(final List yangModelStreams, final SchemaContext context) { - try { - Collection sources = BuilderUtils.streamsToByteSources(yangModelStreams); - return parseSources(sources, context).getModules(); - } catch (IOException | YangSyntaxErrorException e) { - throw new YangParseException("Failed to parse yang data", e); - } + public @NonNull YangParser setSupportedFeatures(final Set supportedFeatures) { + delegate.setSupportedFeatures(supportedFeatures); + return this; } @Override - public SchemaContext parseSources(final Collection sources, final SchemaContext context) - throws IOException, YangSyntaxErrorException { - if (sources == null) { - return resolveSchemaContext(Collections. emptySet()); - } - - final List sorted = resolveModuleBuilders(sources, context); - final Map> modules = resolveModulesWithImports(sorted, context); - - final Set unsorted = new LinkedHashSet<>(build(modules).values()); - if (context != null) { - for (Module m : context.getModules()) { - if (!unsorted.contains(m)) { - unsorted.add(m); - } - } - } - Set result = new LinkedHashSet<>( - ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()]))); - return resolveSchemaContext(result); - } - - private static LinkedHashMap> resolveModulesWithImports(final List sorted, - final SchemaContext context) { - final LinkedHashMap> modules = orderModules(sorted); - for (ModuleBuilder module : sorted) { - if (module != null) { - for (ModuleImport imp : module.getImports().values()) { - String prefix = imp.getPrefix(); - ModuleBuilder targetModule = BuilderUtils.findModuleFromBuilders(imp, sorted); - if (targetModule == null) { - Module result = findModuleFromContext(context, module, prefix, 0); - targetModule = new ModuleBuilder(result); - TreeMap map = modules.get(targetModule.getNamespace()); - if (map == null) { - map = new TreeMap<>(); - map.put(targetModule.getRevision(), targetModule); - modules.put(targetModule.getNamespace(), map); - } else { - map.put(targetModule.getRevision(), targetModule); - } - } - module.addImportedModule(prefix, targetModule); - } - } - } - return modules; + public @NonNull YangParser setModulesWithSupportedDeviations( + final SetMultimap modulesDeviatedByModules) { + delegate.setModulesWithSupportedDeviations(modulesDeviatedByModules); + return this; } @Override - public Map parseYangModelsMapped(final Collection yangFiles) { - if (yangFiles == null || yangFiles.isEmpty()) { - return Collections.emptyMap(); - } - - Map byteSourceToFile = new HashMap<>(); - for (final File file : yangFiles) { - ByteSource source = new ByteSource() { - @Override - public InputStream openStream() throws IOException { - return new NamedFileInputStream(file, file.getPath()); - } - }; - byteSourceToFile.put(source, file); - } - - Map byteSourceToModule; + public @NonNull List> buildDeclaredModel() throws YangParserException { try { - byteSourceToModule = parseYangModelSources(byteSourceToFile.keySet(), null); - } catch (IOException | YangSyntaxErrorException e) { - throw new YangParseException("Failed to parse yang data", e); - } - Map result = new LinkedHashMap<>(); - for (Map.Entry entry : byteSourceToModule.entrySet()) { - result.put(byteSourceToFile.get(entry.getKey()), entry.getValue()); + return delegate.buildDeclaredModel(); + } catch (org.opendaylight.yangtools.yang.parser.api.YangParserException e) { + throw mapException(e); } - return result; } @Override - public Map parseYangModelsFromStreamsMapped(final Collection yangModelStreams) { - if (yangModelStreams == null || yangModelStreams.isEmpty()) { - return Collections.emptyMap(); - } - - Map sourceToStream = new HashMap<>(); - for (final InputStream stream : yangModelStreams) { - ByteSource source = new ByteSource() { - @Override - public InputStream openStream() throws IOException { - return NamedByteArrayInputStream.create(stream); - } - }; - sourceToStream.put(source, stream); - } - - Map sourceToModule; + public @NonNull EffectiveModelContext buildEffectiveModel() throws YangParserException { try { - sourceToModule = parseYangModelSources(sourceToStream.keySet(), null); - } catch (IOException | YangSyntaxErrorException e) { - throw new YangParseException("Failed to parse yang data", e); - } - Map result = new LinkedHashMap<>(); - for (Map.Entry entry : sourceToModule.entrySet()) { - result.put(sourceToStream.get(entry.getKey()), entry.getValue()); - } - return result; - } - - @Override - public SchemaContext resolveSchemaContext(final Set modules) { - // after merging parse method with this one, add support for getting - // submodule sources. - Map identifiersToSources = new HashMap<>(); - for (Module module : modules) { - ModuleImpl moduleImpl = (ModuleImpl) module; - identifiersToSources.put(module, moduleImpl.getSource()); - } - return new SchemaContextImpl(modules, identifiersToSources); - } - - public Collection buildModules(final Collection builders) { - Collection unsorted = resolveSubmodules(builders); - List sorted = ModuleDependencySort.sort(unsorted); - Map> modules = resolveModulesWithImports(sorted, null); - Map builderToModule = build(modules); - return builderToModule.values(); - } - - public SchemaContext assembleContext(final Collection modules) { - final Set sorted = new LinkedHashSet<>( - ModuleDependencySort.sort(modules.toArray(new Module[modules.size()]))); - return resolveSchemaContext(sorted); - } - - private Map parseYangModelSources(final Collection sources, final SchemaContext context) throws IOException, YangSyntaxErrorException { - if (sources == null || sources.isEmpty()) { - return Collections.emptyMap(); - } - - Map sourceToBuilder = resolveSources(sources, context); - // sort and check for duplicates - List sorted = ModuleDependencySort.sort(sourceToBuilder.values()); - Map> modules = resolveModulesWithImports(sorted, null); - Map builderToModule = build(modules); - Map builderToSource = HashBiMap.create(sourceToBuilder).inverse(); - sorted = ModuleDependencySort.sort(builderToModule.keySet()); - - Map result = new LinkedHashMap<>(); - for (ModuleBuilder moduleBuilder : sorted) { - Module value = checkNotNull(builderToModule.get(moduleBuilder), "Cannot get module for %s", moduleBuilder); - result.put(builderToSource.get(moduleBuilder), value); - } - - return result; - } - - /** - * Parse streams and resolve submodules. - * - * @param streams - * collection of streams to parse - * @return map, where key is source stream and value is module builder - * parsed from stream - * @throws YangSyntaxErrorException - */ - // TODO: remove ByteSource result after removing YangModelParser - private Map resolveSources(final Collection streams, final SchemaContext context) throws IOException, YangSyntaxErrorException { - Map builders = parseSourcesToBuilders(streams, context); - return resolveSubmodules(builders); - } - - private Map parseSourcesToBuilders(final Collection sources, - final SchemaContext context) throws IOException, YangSyntaxErrorException { - final ParseTreeWalker walker = new ParseTreeWalker(); - final Map sourceToTree = parseYangSources(sources); - final Map sourceToBuilder = new LinkedHashMap<>(); - - // validate yang - new YangModelBasicValidator(walker).validate(sourceToTree.values()); - - Map> namespaceContext = BuilderUtils.createYangNamespaceContext( - sourceToTree.values(), Optional.fromNullable(context)); - YangParserListenerImpl yangModelParser; - for (Map.Entry entry : sourceToTree.entrySet()) { - ByteSource source = entry.getKey(); - String path = null; // TODO refactor to Optional - // TODO refactor so that path can be retrieved without opening - // stream: NamedInputStream -> NamedByteSource ? - try (InputStream stream = source.openStream()) { - if (stream instanceof NamedInputStream) { - path = stream.toString(); - } - } - yangModelParser = new YangParserListenerImpl(namespaceContext, path); - walker.walk(yangModelParser, entry.getValue()); - ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder(); - moduleBuilder.setSource(source); - sourceToBuilder.put(source, moduleBuilder); - } - return sourceToBuilder; - } - - private Map resolveSubmodules(final Map builders) { - Map modules = new HashMap<>(); - Map> submodules = new HashMap<>(); - for (Map.Entry entry : builders.entrySet()) { - ModuleBuilder builder = entry.getValue(); - if (builder.isSubmodule()) { - String submoduleName = builder.getName(); - TreeMap map = submodules.get(submoduleName); - if (map == null) { - map = new TreeMap<>(); - map.put(builder.getRevision(), builder); - submodules.put(submoduleName, map); - } else { - map.put(builder.getRevision(), builder); - } - } else { - modules.put(entry.getKey(), builder); - } - } - - for (ModuleBuilder module : modules.values()) { - resolveSubmodules(module, submodules); - } - - return modules; - } - - private Collection resolveSubmodules(final Collection builders) { - Collection modules = new HashSet<>(); - Map> submodules = new HashMap<>(); - for (ModuleBuilder builder : builders) { - if (builder.isSubmodule()) { - String submoduleName = builder.getName(); - TreeMap map = submodules.get(submoduleName); - if (map == null) { - map = new TreeMap<>(); - map.put(builder.getRevision(), builder); - submodules.put(submoduleName, map); - } else { - map.put(builder.getRevision(), builder); - } - } else { - modules.add(builder); - } - } - - for (ModuleBuilder module : modules) { - resolveSubmodules(module, submodules); - } - - return modules; - } - - /** - * Traverse collection of builders, find builders representing submodule and - * add this submodule to its parent module. - * - * @param module - * current module - * @param submodules - * collection all loaded submodules - * @return collection of module builders with resolved submodules - */ - private void resolveSubmodules(final ModuleBuilder module, - final Map> submodules) { - Map includes = module.getIncludedModules(); - for (Map.Entry entry : includes.entrySet()) { - TreeMap subs = submodules.get(entry.getKey()); - if (subs == null) { - throw new YangParseException("Failed to find references submodule " + entry.getKey() + " in module " - + module.getName()); - } - Date rev = entry.getValue(); - ModuleBuilder submodule; - if (rev == null) { - submodule = subs.lastEntry().getValue(); - } else { - submodule = subs.get(rev); - // FIXME an exception should be thrown after issue with - // submodule's revisions and namespaces will be resolved - if (submodule == null) { - submodule = subs.lastEntry().getValue(); - } - } - - if (submodule.getIncludedModules().size() > 0) { - resolveSubmodules(submodule, submodules); - } - addSubmoduleToModule(submodule, module); - } - } - - private void addSubmoduleToModule(final ModuleBuilder submodule, final ModuleBuilder module) { - module.addSubmodule(submodule); - submodule.setParent(module); - module.getDirtyNodes().addAll(submodule.getDirtyNodes()); - module.getImports().putAll(submodule.getImports()); - module.getAugments().addAll(submodule.getAugments()); - module.getAugmentBuilders().addAll(submodule.getAugmentBuilders()); - module.getAllAugments().addAll(submodule.getAllAugments()); - module.getChildNodeBuilders().addAll(submodule.getChildNodeBuilders()); - module.getChildNodes().putAll(submodule.getChildNodes()); - module.getGroupings().addAll(submodule.getGroupings()); - module.getGroupingBuilders().addAll(submodule.getGroupingBuilders()); - module.getTypeDefinitions().addAll(submodule.getTypeDefinitions()); - module.getTypeDefinitionBuilders().addAll(submodule.getTypeDefinitionBuilders()); - module.getUsesNodes().addAll(submodule.getUsesNodes()); - module.getUsesNodeBuilders().addAll(submodule.getUsesNodeBuilders()); - module.getAllGroupings().addAll(submodule.getAllGroupings()); - module.getAllUsesNodes().addAll(submodule.getAllUsesNodes()); - module.getRpcs().addAll(submodule.getRpcs()); - module.getAddedRpcs().addAll(submodule.getAddedRpcs()); - module.getNotifications().addAll(submodule.getNotifications()); - module.getAddedNotifications().addAll(submodule.getAddedNotifications()); - module.getIdentities().addAll(submodule.getIdentities()); - module.getAddedIdentities().addAll(submodule.getAddedIdentities()); - module.getFeatures().addAll(submodule.getFeatures()); - module.getAddedFeatures().addAll(submodule.getAddedFeatures()); - module.getDeviations().addAll(submodule.getDeviations()); - module.getDeviationBuilders().addAll(submodule.getDeviationBuilders()); - module.getExtensions().addAll(submodule.getExtensions()); - module.getAddedExtensions().addAll(submodule.getAddedExtensions()); - module.getUnknownNodes().addAll(submodule.getUnknownNodes()); - module.getAllUnknownNodes().addAll(submodule.getAllUnknownNodes()); - } - - private List resolveModuleBuilders(final Collection yangFileStreams, - final SchemaContext context) throws IOException, YangSyntaxErrorException { - Map parsedBuilders = resolveSources(yangFileStreams, context); - ModuleBuilder[] builders = new ModuleBuilder[parsedBuilders.size()]; - parsedBuilders.values().toArray(builders); - - // module dependency graph sorted - List sorted; - if (context == null) { - sorted = ModuleDependencySort.sort(builders); - } else { - sorted = ModuleDependencySort.sortWithContext(context, builders); - } - return sorted; - } - - /** - * Order modules by namespace and revision. - * - * @param modules - * topologically sorted modules - * @return modules ordered by namespace and revision - */ - private static LinkedHashMap> orderModules(final List modules) { - final LinkedHashMap> result = new LinkedHashMap<>(); - for (final ModuleBuilder builder : modules) { - if (builder == null) { - continue; - } - - URI ns = builder.getNamespace(); - Date rev = builder.getRevision(); - if (rev == null) { - rev = new Date(0); - } - - TreeMap builderByRevision = result.get(ns); - if (builderByRevision == null) { - builderByRevision = new TreeMap<>(); - builderByRevision.put(rev, builder); - result.put(ns, builderByRevision); - } else { - builderByRevision.put(rev, builder); - } - + return delegate.buildEffectiveModel(); + } catch (org.opendaylight.yangtools.yang.parser.api.YangParserException e) { + throw mapException(e); } - return result; } - /** - * Find {@code main} dependencies from {@code other} and add them to - * {@code filtered}. - * - * @param main - * main yang module - * @param other - * all loaded modules - * @param filtered - * collection to fill up - */ - private void filterImports(final ModuleBuilder main, final Collection other, - final Collection filtered) { - Map imports = main.getImports(); - - // if this is submodule, add parent to filtered and pick its imports - if (main.isSubmodule()) { - TreeMap dependencies = new TreeMap<>(); - for (ModuleBuilder mb : other) { - if (mb.getName().equals(main.getBelongsTo())) { - dependencies.put(mb.getRevision(), mb); - } - } - ModuleBuilder parent = dependencies.get(dependencies.firstKey()); - filtered.add(parent); - imports.putAll(parent.getImports()); - } - - for (ModuleImport mi : imports.values()) { - for (ModuleBuilder builder : other) { - if (mi.getModuleName().equals(builder.getModuleName())) { - if (mi.getRevision() == null) { - if (!filtered.contains(builder)) { - filtered.add(builder); - filterImports(builder, other, filtered); - } - } else { - if (mi.getRevision().equals(builder.getRevision())) { - if (!filtered.contains(builder)) { - filtered.add(builder); - filterImports(builder, other, filtered); - } - } - } - } - } - } + private static YangParserException mapException( + final org.opendaylight.yangtools.yang.parser.api.YangParserException ex) { + return new YangParserException(ex.getMessage(), ex); } - private Map parseYangSources(final Collection sources) throws IOException, YangSyntaxErrorException { - final Map trees = new HashMap<>(); - for (ByteSource source : sources) { - try (InputStream stream = source.openStream()) { - trees.put(source, parseYangSource(stream)); - } - } - return trees; + private static YangSyntaxErrorException mapException( + final org.opendaylight.yangtools.yang.parser.api.YangSyntaxErrorException ex) { + return new YangSyntaxErrorException(ex.getSource().orElse(null), ex.getLine(), ex.getCharPositionInLine(), + ex.getMessage(), ex); } - - public static YangContext parseYangSource(final InputStream stream) throws IOException, YangSyntaxErrorException { - final YangLexer lexer = new YangLexer(new ANTLRInputStream(stream)); - final CommonTokenStream tokens = new CommonTokenStream(lexer); - final YangParser parser = new YangParser(tokens); - parser.removeErrorListeners(); - - final YangErrorListener errorListener = new YangErrorListener(); - parser.addErrorListener(errorListener); - - final YangContext result = parser.yang(); - errorListener.validate(); - - return result; - } - - /** - * Mini parser: This parsing context does not validate full YANG module, - * only parses header up to the revisions and imports. - * - * @see org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo - */ - public static YangContext parseStreamWithoutErrorListeners(final InputStream yangStream) { - YangContext result = null; - try { - final ANTLRInputStream input = new ANTLRInputStream(yangStream); - final YangLexer lexer = new YangLexer(input); - final CommonTokenStream tokens = new CommonTokenStream(lexer); - final YangParser parser = new YangParser(tokens); - parser.removeErrorListeners(); - result = parser.yang(); - } catch (IOException e) { - LOG.warn("Exception while reading yang file: " + yangStream, e); - } - return result; - } - - /** - * Creates builder-to-module map based on given modules. Method first - * resolve unresolved type references, instantiate groupings through uses - * statements and perform augmentation. - * - * Node resolving must be performed in following order: - *
    - *
  1. - * unresolved type references
  2. - *
  3. - * uses in groupings
  4. - *
  5. - * uses in other nodes
  6. - *
  7. - * augments
  8. - *
- * - * @param modules - * all loaded modules - * @return modules mapped on their builders - */ - private Map build(final Map> modules) { - resolveDirtyNodes(modules); - resolveAugmentsTargetPath(modules); - resolveUsesTargetGrouping(modules); - resolveUsesForGroupings(modules); - resolveUsesForNodes(modules); - resolveAugments(modules); - resolveIdentities(modules); - - // build - final Map result = new LinkedHashMap<>(); - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry childEntry : entry.getValue().entrySet()) { - final ModuleBuilder moduleBuilder = childEntry.getValue(); - final Module module = moduleBuilder.build(); - result.put(moduleBuilder, module); - } - } - return result; - } - - /** - * Resolve all unresolved type references. - * - * @param modules - * all loaded modules - */ - private void resolveDirtyNodes(final Map> modules) { - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry childEntry : entry.getValue().entrySet()) { - final ModuleBuilder module = childEntry.getValue(); - resolveUnknownNodes(modules, module); - resolveDirtyNodes(modules, module); - } - } - } - - /** - * Search for dirty nodes (node which contains UnknownType) and resolve - * unknown types. - * - * @param modules - * all available modules - * @param module - * current module - */ - private void resolveDirtyNodes(final Map> modules, final ModuleBuilder module) { - final Set dirtyNodes = module.getDirtyNodes(); - if (!dirtyNodes.isEmpty()) { - for (TypeAwareBuilder nodeToResolve : dirtyNodes) { - if (nodeToResolve instanceof UnionTypeBuilder) { - // special handling for union types - resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module); - } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) { - // special handling for identityref types - IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef(); - IdentitySchemaNodeBuilder identity = findBaseIdentity(module, idref.getBaseString(), - idref.getLine()); - if (identity == null) { - throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity"); - } - idref.setBaseIdentity(identity); - nodeToResolve.setType(idref.build()); - } else { - resolveType(nodeToResolve, modules, module); - } - } - } - } - - /** - * Traverse through augmentations of modules and fix their child nodes - * schema path. - * - * @param modules - * all loaded modules - */ - private void resolveAugmentsTargetPath(final Map> modules) { - // collect augments from all loaded modules - final List allAugments = new ArrayList<>(); - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - allAugments.addAll(inner.getValue().getAllAugments()); - } - } - - for (AugmentationSchemaBuilder augment : allAugments) { - setCorrectAugmentTargetPath(augment); - } - } - - /** - * Find augment target and set correct schema path for all its child nodes. - * - * @param augment - * augment to resolve - */ - private void setCorrectAugmentTargetPath(final AugmentationSchemaBuilder augment) { - Builder parent = augment.getParent(); - final SchemaPath targetNodeSchemaPath; - - if (parent instanceof UsesNodeBuilder) { - targetNodeSchemaPath = findUsesAugmentTargetNodePath(((UsesNodeBuilder) parent).getParent(), augment); - } else { - targetNodeSchemaPath = augment.getTargetPath(); - } - - for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) { - correctPathForAugmentNodes(childNode, targetNodeSchemaPath); - } - } - - private SchemaPath findUsesAugmentTargetNodePath(DataNodeContainerBuilder usesParent, - AugmentationSchemaBuilder augment) { - QName parentQName = usesParent.getQName(); - final QNameModule qnm; - if (parentQName == null) { - ModuleBuilder m = BuilderUtils.getParentModule(usesParent); - qnm = m.getQNameModule(); - } else { - qnm = parentQName.getModule(); - } - - SchemaPath path = usesParent.getPath(); - for (QName qname : augment.getTargetPath().getPathFromRoot()) { - path = path.createChild(QName.create(qnm, qname.getLocalName())); - } - - return path; - } - - /** - * Set new schema path to node and all its child nodes based on given parent - * path. This method do not change the namespace. - * - * @param node - * node which schema path should be updated - * @param parentPath - * schema path of parent node - */ - private void correctPathForAugmentNodes(final DataSchemaNodeBuilder node, final SchemaPath parentPath) { - SchemaPath newPath = parentPath.createChild(node.getQName()); - node.setPath(newPath); - if (node instanceof DataNodeContainerBuilder) { - for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodeBuilders()) { - correctPathForAugmentNodes(child, node.getPath()); - } - } - if (node instanceof ChoiceBuilder) { - for (ChoiceCaseBuilder child : ((ChoiceBuilder) node).getCases()) { - correctPathForAugmentNodes(child, node.getPath()); - } - } - } - - /** - * Check augments for mandatory nodes. If the target node is in another - * module, then nodes added by the augmentation MUST NOT be mandatory nodes. - * If mandatory node is found, throw an exception. - * - * @param augments - * augments to check - */ - private void checkAugmentMandatoryNodes(final Collection augments) { - for (AugmentationSchemaBuilder augment : augments) { - URI augmentTargetNs = augment.getTargetPath().getPathFromRoot().iterator().next().getNamespace(); - Date augmentTargetRev = augment.getTargetPath().getPathFromRoot().iterator().next().getRevision(); - ModuleBuilder module = BuilderUtils.getParentModule(augment); - - if (augmentTargetNs.equals(module.getNamespace()) && augmentTargetRev.equals(module.getRevision())) { - continue; - } - - for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) { - if (childNode.getConstraints().isMandatory()) { - throw new YangParseException(augment.getModuleName(), augment.getLine(), - "Error in augment parsing: cannot augment mandatory node " - + childNode.getQName().getLocalName()); - } - } - } - } - - /** - * Go through all augment definitions and resolve them. - * - * @param modules - * all loaded modules topologically sorted (based on dependencies - * between each other) - */ - private void resolveAugments(final Map> modules) { - List all = new ArrayList<>(); - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - all.add(inner.getValue()); - } - } - - for (ModuleBuilder mb : all) { - if (mb != null) { - List augments = mb.getAllAugments(); - checkAugmentMandatoryNodes(augments); - Collections.sort(augments, Comparators.AUGMENT_BUILDER_COMP); - for (AugmentationSchemaBuilder augment : augments) { - if (!(augment.isResolved())) { - boolean resolved = resolveAugment(augment, mb, modules); - if (!resolved) { - throw new YangParseException(augment.getModuleName(), augment.getLine(), - "Error in augment parsing: failed to find augment target: " + augment); - } - } - } - } - } - } - - /** - * Perform augmentation defined under uses statement. - * - * @param augment - * augment to resolve - * @param module - * current module - * @param modules - * all loaded modules - * @return true if augment process succeed - */ - private boolean resolveUsesAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module, - final Map> modules) { - if (augment.isResolved()) { - return true; - } - - UsesNodeBuilder usesNode = (UsesNodeBuilder) augment.getParent(); - DataNodeContainerBuilder parentNode = usesNode.getParent(); - Optional potentialTargetNode; - SchemaPath resolvedTargetPath = findUsesAugmentTargetNodePath(parentNode, augment); - if (parentNode instanceof ModuleBuilder && resolvedTargetPath.isAbsolute()) { - // Uses is directly used in module body, we lookup - // We lookup in data namespace to find correct augmentation target - potentialTargetNode = findSchemaNodeInModule(resolvedTargetPath, (ModuleBuilder) parentNode); - } else { - // Uses is used in local context (be it data namespace or grouping - // namespace, - // since all nodes via uses are imported to localName, it is safe to - // to proceed only with local names. - // - // Conflicting elements in other namespaces are still not present - // since resolveUsesAugment occurs before augmenting from external - // modules. - potentialTargetNode = Optional. fromNullable(findSchemaNode(augment.getTargetPath() - .getPathFromRoot(), (SchemaNodeBuilder) parentNode)); - } - - if (potentialTargetNode.isPresent()) { - SchemaNodeBuilder targetNode = potentialTargetNode.get(); - if (targetNode instanceof AugmentationTargetBuilder) { - fillAugmentTarget(augment, targetNode); - ((AugmentationTargetBuilder) targetNode).addAugmentation(augment); - augment.setResolved(true); - return true; - } else { - LOG.warn( - "Error in module {} at line {}: Unsupported augment target: {}. Augmentation process skipped.", - module.getName(), augment.getLine(), potentialTargetNode); - augment.setResolved(true); - return true; - } - } else { - throw new YangParseException(module.getName(), augment.getLine(), String.format( - "Failed to resolve augment in uses. Invalid augment target path: %s", augment.getTargetPath())); - } - - } - - /** - * Find augment target module and perform augmentation. - * - * @param augment - * augment to resolve - * @param module - * current module - * @param modules - * all loaded modules - * @return true if augment process succeed - */ - private boolean resolveAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module, - final Map> modules) { - if (augment.isResolved()) { - return true; - } - - QName targetModuleName = augment.getTargetPath().getPathFromRoot().iterator().next(); - ModuleBuilder targetModule = BuilderUtils.findModule(targetModuleName, modules); - if (targetModule == null) { - throw new YangParseException(module.getModuleName(), augment.getLine(), "Failed to resolve augment " - + augment); - } - - return processAugmentation(augment, targetModule); - } - - /** - * Go through identity statements defined in current module and resolve - * their 'base' statement. - * - * @param modules - * all loaded modules - */ - private void resolveIdentities(final Map> modules) { - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - ModuleBuilder module = inner.getValue(); - final Set identities = module.getAddedIdentities(); - for (IdentitySchemaNodeBuilder identity : identities) { - resolveIdentity(module, identity); - } - } - } - } - - private void resolveIdentity(final ModuleBuilder module, final IdentitySchemaNodeBuilder identity) { - final String baseIdentityName = identity.getBaseIdentityName(); - if (baseIdentityName != null) { - IdentitySchemaNodeBuilder result = null; - if (baseIdentityName.contains(":")) { - final int line = identity.getLine(); - String[] splittedBase = baseIdentityName.split(":"); - if (splittedBase.length > 2) { - throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " - + baseIdentityName); - } - String prefix = splittedBase[0]; - String name = splittedBase[1]; - ModuleBuilder dependentModule = BuilderUtils.getModuleByPrefix(module, prefix); - result = BuilderUtils.findIdentity(dependentModule.getAddedIdentities(), name); - } else { - result = BuilderUtils.findIdentity(module.getAddedIdentities(), baseIdentityName); - } - identity.setBaseIdentity(result); - } - } - - /** - * Find and add reference of uses target grouping. - * - * @param modules - * all loaded modules - */ - private void resolveUsesTargetGrouping(final Map> modules) { - final List allUses = new ArrayList<>(); - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - allUses.addAll(inner.getValue().getAllUsesNodes()); - } - } - for (UsesNodeBuilder usesNode : allUses) { - ModuleBuilder module = BuilderUtils.getParentModule(usesNode); - final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, - module); - usesNode.setGrouping(targetGroupingBuilder); - } - } - - /** - * Resolve uses statements defined in groupings. - * - * @param modules - * all loaded modules - */ - private void resolveUsesForGroupings(final Map> modules) { - final Set allGroupings = new HashSet<>(); - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - ModuleBuilder module = inner.getValue(); - allGroupings.addAll(module.getAllGroupings()); - } - } - final List sorted = GroupingSort.sort(allGroupings); - for (GroupingBuilder gb : sorted) { - List usesNodes = new ArrayList<>(GroupingSort.getAllUsesNodes(gb)); - Collections.sort(usesNodes, new GroupingUtils.UsesComparator()); - for (UsesNodeBuilder usesNode : usesNodes) { - resolveUses(usesNode, modules); - } - } - } - - /** - * Resolve uses statements. - * - * @param modules - * all loaded modules - */ - private void resolveUsesForNodes(final Map> modules) { - for (Map.Entry> entry : modules.entrySet()) { - for (Map.Entry inner : entry.getValue().entrySet()) { - ModuleBuilder module = inner.getValue(); - List usesNodes = module.getAllUsesNodes(); - Collections.sort(usesNodes, new GroupingUtils.UsesComparator()); - for (UsesNodeBuilder usesNode : usesNodes) { - resolveUses(usesNode, modules); - } - } - } - } - - /** - * Find target grouping and copy its child nodes to current location with - * new namespace. - * - * @param usesNode - * uses node to resolve - * @param modules - * all loaded modules - */ - private void resolveUses(final UsesNodeBuilder usesNode, final Map> modules) { - if (!usesNode.isResolved()) { - DataNodeContainerBuilder parent = usesNode.getParent(); - ModuleBuilder module = BuilderUtils.getParentModule(parent); - GroupingBuilder target = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module); - - int index = nodeAfterUsesIndex(usesNode); - List targetNodes = target.instantiateChildNodes(parent); - for (DataSchemaNodeBuilder targetNode : targetNodes) { - parent.addChildNode(index++, targetNode); - } - parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent)); - parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent)); - parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent)); - usesNode.setResolved(true); - for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) { - resolveUsesAugment(augment, module, modules); - } - - GroupingUtils.performRefine(usesNode); - } - } - - private int nodeAfterUsesIndex(final UsesNodeBuilder usesNode) { - DataNodeContainerBuilder parent = usesNode.getParent(); - int usesLine = usesNode.getLine(); - - List childNodes = parent.getChildNodeBuilders(); - if (childNodes.isEmpty()) { - return 0; - } - - DataSchemaNodeBuilder nextNodeAfterUses = null; - for (DataSchemaNodeBuilder childNode : childNodes) { - if (!(childNode.isAddedByUses()) && !(childNode.isAugmenting())) { - if (childNode.getLine() > usesLine) { - nextNodeAfterUses = childNode; - break; - } - } - } - - // uses is declared after child nodes - if (nextNodeAfterUses == null) { - return childNodes.size(); - } - - return parent.getChildNodeBuilders().indexOf(nextNodeAfterUses); - } - - /** - * Try to find extension describing this unknown node and assign it to - * unknown node builder. - * - * @param modules - * all loaded modules - * @param module - * current module - */ - private void resolveUnknownNodes(final Map> modules, final ModuleBuilder module) { - for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) { - QName nodeType = usnb.getNodeType(); - String localName = usnb.getNodeType().getLocalName(); - ModuleBuilder dependentModule = BuilderUtils.findModule(nodeType, modules); - - if (dependentModule == null) { - LOG.warn( - "Error in module {} at line {}: Failed to resolve node {}: no such extension definition found.", - module.getName(), usnb.getLine(), usnb); - continue; - } - - ExtensionBuilder extBuilder = findExtBuilder(localName, dependentModule.getAddedExtensions()); - if (extBuilder == null) { - ExtensionDefinition extDef = findExtDef(localName, dependentModule.getExtensions()); - if (extDef == null) { - LOG.warn( - "Error in module {} at line {}: Failed to resolve node {}: no such extension definition found.", - module.getName(), usnb.getLine(), usnb); - } else { - usnb.setExtensionDefinition(extDef); - } - } else { - usnb.setExtensionBuilder(extBuilder); - } - } - } - - private ExtensionBuilder findExtBuilder(final String name, final Collection extensions) { - for (ExtensionBuilder extension : extensions) { - if (extension.getQName().getLocalName().equals(name)) { - return extension; - } - } - return null; - } - - private ExtensionDefinition findExtDef(final String name, final Collection extensions) { - for (ExtensionDefinition extension : extensions) { - if (extension.getQName().getLocalName().equals(name)) { - return extension; - } - } - return null; - } - }