import com.google.common.annotations.Beta;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+/**
+ * Representation of {@code submodule} statement. Note that implementations of this interface are required to provide
+ * {@link ModuleEffectiveStatement.PrefixToEffectiveModuleNamespace} and
+ * {@link ModuleEffectiveStatement.QNameModuleToPrefixNamespace} namespaces.
+ */
@Beta
public interface SubmoduleEffectiveStatement extends EffectiveStatement<String, SubmoduleStatement> {
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement.QNameModuleToPrefixNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
/**
* Utility class for formatting {@link DeclaredStatement}s.
*/
public YangTextSnippet toYangTextSnippet(final ModuleEffectiveStatement module,
final DeclaredStatement<?> statement) {
- return new YangTextSnippet(statement, module.findAll(QNameModuleToPrefixNamespace.class), ignoredStatements,
+ return new YangTextSnippet(statement, StatementPrefixResolver.forModule(module), ignoredStatements,
+ omitDefaultStatements);
+ }
+
+ public YangTextSnippet toYangTextSnippet(final SubmoduleEffectiveStatement submodule,
+ final DeclaredStatement<?> statement) {
+ return new YangTextSnippet(statement, StatementPrefixResolver.forSubmodule(submodule), ignoredStatements,
omitDefaultStatements);
}
+++ /dev/null
-/*
- * Copyright (c) 2018 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.model.export;
-
-import static com.google.common.base.Verify.verify;
-
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Optional;
-import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.common.Revision;
-import org.opendaylight.yangtools.yang.common.YangConstants;
-
-/**
- * Internal shared helpers.
- * @author Robert Varga
- *
- */
-final class ExportUtils {
- private ExportUtils() {
- // Hidden on purpose
- }
-
- static Optional<String> statementPrefix(final Map<QNameModule, String> namespaces, final QName stmtName) {
- final QNameModule namespace = stmtName.getModule();
- if (YangConstants.RFC6020_YIN_MODULE.equals(namespace)) {
- return Optional.empty();
- }
-
- // Non-default namespace, a prefix is needed
- @Nullable String prefix = namespaces.get(namespace);
- if (prefix == null && !namespace.getRevision().isPresent()) {
- // FIXME: this is an artifact of commonly-bound statements in parser, which means a statement's name
- // does not have a Revision. We'll need to find a solution to this which is acceptable. There
- // are multiple ways of fixing this:
- // - perhaps EffectiveModuleStatement should be giving us a statement-to-EffectiveModule map?
- // - or DeclaredStatement should provide the prefix?
- // The second one seems cleaner, as that means we would not have perform any lookup at all...
- Entry<QNameModule, @NonNull String> match = null;
- for (Entry<QNameModule, @NonNull String> entry : namespaces.entrySet()) {
- final QNameModule ns = entry.getKey();
- if (namespace.equals(ns.withoutRevision()) && (match == null
- || Revision.compare(match.getKey().getRevision(), ns.getRevision()) < 0)) {
- match = entry;
- }
- }
-
- if (match != null) {
- prefix = match.getValue();
- }
- }
-
- if (prefix == null) {
- throw new IllegalArgumentException("Failed to find prefix for statement " + stmtName);
- }
-
- verify(!prefix.isEmpty(), "Empty prefix for statement %s", stmtName);
- return Optional.of(prefix);
- }
-}
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Optional;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
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.common.YangConstants;
import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
return new SimpleImmutableEntry<>(prefix, module.getNamespace().toString());
}
- Entry<String, String> prefixAndNamespaceForStatement(final QName stmtName) {
- final Optional<String> prefix = ExportUtils.statementPrefix(moduleToPrefix, stmtName);
- if (!prefix.isPresent()) {
- return YIN_PREFIX_AND_NAMESPACE;
- }
-
- return new SimpleImmutableEntry<>(prefix.get(), stmtName.getNamespace().toString());
- }
-
Map<String, String> prefixesAndNamespaces() {
return Maps.transformValues(prefixToModule, module -> module.localQNameModule().getNamespace().toString());
}
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech, 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.model.export;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement.NameToEffectiveSubmoduleNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement.QNameModuleToPrefixNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
+
+/**
+ * Utility resolver to disambiguate imports.
+ */
+final class StatementPrefixResolver {
+ private static final class Conflict {
+ private final Collection<Entry<DeclaredStatement<?>, String>> statements;
+
+ Conflict(final Collection<Entry<DeclaredStatement<?>, String>> entries) {
+ this.statements = requireNonNull(entries);
+ }
+
+ @Nullable String findPrefix(final DeclaredStatement<?> stmt) {
+ return statements.stream().filter(entry -> contains(entry.getKey(), stmt)).findFirst().map(Entry::getValue)
+ .orElse(null);
+ }
+
+ private static boolean contains(final DeclaredStatement<?> haystack, final DeclaredStatement<?> needle) {
+ if (haystack == needle) {
+ return true;
+ }
+ for (DeclaredStatement<?> child : haystack.declaredSubstatements()) {
+ if (contains(child, needle)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private final Map<QNameModule, ?> lookup;
+
+ private StatementPrefixResolver(final Map<QNameModule, String> map) {
+ this.lookup = ImmutableMap.copyOf(map);
+ }
+
+ private StatementPrefixResolver(final ImmutableMap<QNameModule, ?> map) {
+ this.lookup = requireNonNull(map);
+ }
+
+ static StatementPrefixResolver forModule(final ModuleEffectiveStatement module) {
+ final Map<QNameModule, String> imports = module.getAll(QNameModuleToPrefixNamespace.class);
+ final Collection<SubmoduleEffectiveStatement> submodules = module.getAll(
+ NameToEffectiveSubmoduleNamespace.class).values();
+ if (submodules.isEmpty()) {
+ // Simple: it's just the module
+ return new StatementPrefixResolver(imports);
+ }
+
+ // Stage one: check what everyone thinks about imports
+ final Map<String, Multimap<QNameModule, EffectiveStatement<?, ?>>> prefixToNamespaces = new HashMap<>();
+ indexPrefixes(prefixToNamespaces, imports, module);
+ for (SubmoduleEffectiveStatement submodule : submodules) {
+ indexPrefixes(prefixToNamespaces, submodule.getAll(QNameModuleToPrefixNamespace.class), submodule);
+ }
+
+ // Stage two: resolve first order of conflicts, potentially completely resolving mappings...
+ final Builder<QNameModule, Object> builder = ImmutableMap.builderWithExpectedSize(prefixToNamespaces.size());
+
+ // ... first resolve unambiguous mappings ...
+ final Iterator<Entry<String, Multimap<QNameModule, EffectiveStatement<?, ?>>>> it =
+ prefixToNamespaces.entrySet().iterator();
+ while (it.hasNext()) {
+ final Entry<String, Multimap<QNameModule, EffectiveStatement<?, ?>>> entry = it.next();
+ final Multimap<QNameModule, EffectiveStatement<?, ?>> modules = entry.getValue();
+ if (modules.size() == 1) {
+ builder.put(modules.keys().iterator().next(), entry.getKey());
+ it.remove();
+ }
+ }
+
+ // .. check for any remaining conflicts ...
+ if (!prefixToNamespaces.isEmpty()) {
+ final Multimap<QNameModule, Entry<DeclaredStatement<?>, String>> conflicts = ArrayListMultimap.create();
+ for (Entry<String, Multimap<QNameModule, EffectiveStatement<?, ?>>> entry : prefixToNamespaces.entrySet()) {
+ for (Entry<QNameModule, EffectiveStatement<?, ?>> namespace : entry.getValue().entries()) {
+ conflicts.put(namespace.getKey(), new SimpleImmutableEntry<>(namespace.getValue().getDeclared(),
+ entry.getKey()));
+ }
+ }
+
+ builder.putAll(Maps.transformValues(conflicts.asMap(), Conflict::new));
+ }
+
+ return new StatementPrefixResolver(builder.build());
+ }
+
+ static StatementPrefixResolver forSubmodule(final SubmoduleEffectiveStatement submodule) {
+ return new StatementPrefixResolver(submodule.getAll(QNameModuleToPrefixNamespace.class));
+ }
+
+ Optional<String> findPrefix(final DeclaredStatement<?> stmt) {
+ final QNameModule module = stmt.statementDefinition().getStatementName().getModule();
+ if (YangConstants.RFC6020_YIN_MODULE.equals(module)) {
+ return Optional.empty();
+ }
+
+ final Object obj = lookup.get(module);
+ if (obj != null) {
+ return decodeEntry(obj, stmt);
+ }
+ if (module.getRevision().isPresent()) {
+ throw new IllegalArgumentException("Failed to find prefix for statement " + stmt);
+ }
+
+ // FIXME: this is an artifact of commonly-bound statements in parser, which means a statement's name
+ // does not have a Revision. We'll need to find a solution to this which is acceptable. There
+ // are multiple ways of fixing this:
+ // - perhaps EffectiveModuleStatement should be giving us a statement-to-EffectiveModule map?
+ // - or DeclaredStatement should provide the prefix?
+ // The second one seems cleaner, as that means we would not have perform any lookup at all...
+ Entry<QNameModule, ?> match = null;
+ for (Entry<QNameModule, ?> entry : lookup.entrySet()) {
+ final QNameModule ns = entry.getKey();
+ if (module.equals(ns.withoutRevision()) && (match == null
+ || Revision.compare(match.getKey().getRevision(), ns.getRevision()) < 0)) {
+ match = entry;
+ }
+ }
+
+ return match == null ? null : decodeEntry(match.getValue(), stmt);
+ }
+
+ private static Optional<String> decodeEntry(final Object entry, final DeclaredStatement<?> stmt) {
+ if (entry instanceof String) {
+ return Optional.of((String)entry);
+ }
+ verify(entry instanceof Conflict, "Unexpected entry %s", entry);
+ final String prefix = ((Conflict) entry).findPrefix(stmt);
+ checkArgument(prefix != null, "Failed to find prefix for statement %s", stmt);
+ verify(!prefix.isEmpty(), "Empty prefix for statement %s", stmt);
+ return Optional.of(prefix);
+ }
+
+ private static void indexPrefixes(final Map<String, Multimap<QNameModule, EffectiveStatement<?, ?>>> map,
+ final Map<QNameModule, String> imports, final EffectiveStatement<?, ?> stmt) {
+ for (Entry<QNameModule, String> entry : imports.entrySet()) {
+ map.computeIfAbsent(entry.getValue(), key -> ArrayListMultimap.create()).put(entry.getKey(), stmt);
+ }
+ }
+}
import com.google.common.annotations.Beta;
import java.util.Iterator;
-import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.opendaylight.yangtools.concepts.Immutable;
-import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
@NonNullByDefault({ PARAMETER, RETURN_TYPE })
public final class YangTextSnippet implements Immutable, Iterable<@NonNull String> {
private final Set<@NonNull StatementDefinition> ignoredStatements;
- private final Map<QNameModule, @NonNull String> mapper;
+ private final StatementPrefixResolver resolver;
private final DeclaredStatement<?> statement;
private final boolean omitDefaultStatements;
- YangTextSnippet(final DeclaredStatement<?> statement, final Map<QNameModule, @NonNull String> namespaces,
+ YangTextSnippet(final DeclaredStatement<?> statement, final StatementPrefixResolver resolver,
final Set<@NonNull StatementDefinition> ignoredStatements, final boolean omitDefaultStatements) {
this.statement = requireNonNull(statement);
- this.mapper = requireNonNull(namespaces);
+ this.resolver = requireNonNull(resolver);
this.ignoredStatements = requireNonNull(ignoredStatements);
this.omitDefaultStatements = omitDefaultStatements;
}
@Override
public Iterator<@NonNull String> iterator() {
- return new YangTextSnippetIterator(statement, mapper, ignoredStatements, omitDefaultStatements);
+ return new YangTextSnippetIterator(statement, resolver, ignoredStatements, omitDefaultStatements);
}
@Override
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
-import java.util.Map;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
private final Queue<String> strings = new ArrayDeque<>(8);
// Let's be modest, 16-level deep constructs are not exactly common.
private final Deque<Iterator<? extends DeclaredStatement<?>>> stack = new ArrayDeque<>(8);
- private final Map<QNameModule, @NonNull String> namespaces;
private final Set<StatementDefinition> ignoredStatements;
+ private final StatementPrefixResolver resolver;
private final boolean omitDefaultStatements;
- YangTextSnippetIterator(final DeclaredStatement<?> stmt, final Map<QNameModule, @NonNull String> namespaces,
+ YangTextSnippetIterator(final DeclaredStatement<?> stmt, final StatementPrefixResolver resolver,
final Set<StatementDefinition> ignoredStatements, final boolean omitDefaultStatements) {
- this.namespaces = requireNonNull(namespaces);
+ this.resolver = requireNonNull(resolver);
this.ignoredStatements = requireNonNull(ignoredStatements);
this.omitDefaultStatements = omitDefaultStatements;
pushStatement(requireNonNull(stmt));
addIndent();
// Add statement prefixed with namespace if needed
- final QName stmtName = def.getStatementName();
- final Optional<String> prefix = ExportUtils.statementPrefix(namespaces, stmtName);
+ final Optional<String> prefix = resolver.findPrefix(stmt);
if (prefix.isPresent()) {
strings.add(prefix.get());
strings.add(":");
}
- strings.add(stmtName.getLocalName());
+ strings.add(def.getStatementName().getLocalName());
// Add argument, quoted and properly indented if need be
addArgument(def, stmt.rawArgument());
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.opendaylight.yangtools.yang.model.export.DeclaredStatementFormatter.defaultInstance;
+import java.util.Collection;
import org.junit.Test;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement.NameToEffectiveSubmoduleNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
public class YangTextSnippetTest {
@Test
public void testNotification() {
final SchemaContext schema = YangParserTestUtils.parseYangResource("/bugs/bug2444/yang/notification.yang");
+ assertFormat(schema.getModules());
+ }
+
+ @Test
+ public void testSubmoduleNamespaces() throws Exception {
+ SchemaContext schema = YangParserTestUtils.parseYangResourceDirectory("/bugs/yt992");
+ assertFormat(schema.getModules());
+ }
- for (Module module : schema.getModules()) {
+ private static void assertFormat(final Collection<? extends Module> modules) {
+ for (Module module : modules) {
assertTrue(module instanceof ModuleEffectiveStatement);
final ModuleEffectiveStatement stmt = (ModuleEffectiveStatement) module;
+ assertNotNull(formatModule(stmt));
- final String str = DeclaredStatementFormatter.defaultInstance().toYangTextSnippet(stmt, stmt.getDeclared())
- .toString();
- assertNotNull(str);
+ for (SubmoduleEffectiveStatement substmt : stmt.getAll(NameToEffectiveSubmoduleNamespace.class).values()) {
+ assertNotNull(formatSubmodule(substmt));
+ }
}
}
+
+ private static String formatModule(final ModuleEffectiveStatement stmt) {
+ return defaultInstance().toYangTextSnippet(stmt, stmt.getDeclared()).toString();
+ }
+
+ private static String formatSubmodule(final SubmoduleEffectiveStatement stmt) {
+ return defaultInstance().toYangTextSnippet(stmt, stmt.getDeclared()).toString();
+ }
}
--- /dev/null
+module module1 {
+ yang-version "1.1";
+ namespace "urn:example:module1";
+ prefix "module1";
+
+ include module1submodule1;
+
+ revision "2019-05-17" {
+ }
+
+ container cont1 {
+ uses submodule-grouping;
+ }
+}
\ No newline at end of file
--- /dev/null
+submodule module1submodule1 {
+ yang-version "1.1";
+ belongs-to "module1" {
+ prefix "module1";
+ }
+
+ import module2 {
+ prefix "module2";
+ }
+
+ revision "2019-05-17" {
+ }
+
+ grouping submodule-grouping {
+ uses module2:grouping1;
+
+ leaf leaf2 {
+ type string;
+ module2:ext1 "param1";
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+module module2 {
+ yang-version "1.1";
+ namespace "urn:example:module2";
+ prefix "module2";
+
+ revision "2019-05-17" {
+ }
+
+ grouping grouping1 {
+ leaf leaf1 {
+ type string;
+ }
+ }
+
+ extension ext1 {
+ argument "parameter";
+ }
+}
\ No newline at end of file
*/
package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
+import static com.google.common.base.Verify.verifyNotNull;
import static java.util.Objects.requireNonNull;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
import java.net.URI;
import java.util.ArrayList;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ContactEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ImportEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.OrganizationEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.PrefixEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.YangVersionEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.compat.NotificationNodeContainerCompat;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
@Beta
StmtContextUtils.firstAttributeOf(ctx.declaredSubstatements(), PrefixStatement.class),
ctx.getStatementSourceReference(), "Unable to resolve prefix for %s %s.", type, name);
}
+
+ // Alright. this is quite ugly
+ protected final void appendPrefixes(final StmtContext<?, ?, ?> ctx,
+ final Builder<String, ModuleEffectiveStatement> builder) {
+ streamEffectiveSubstatements(ImportEffectiveStatement.class)
+ .map(imp -> imp.findFirstEffectiveSubstatementArgument(PrefixEffectiveStatement.class).get())
+ .forEach(pfx -> {
+ final StmtContext<?, ?, ?> importedCtx =
+ verifyNotNull(ctx.getFromNamespace(ImportPrefixToModuleCtx.class, pfx),
+ "Failed to resolve prefix %s", pfx);
+ builder.put(pfx, (ModuleEffectiveStatement) importedCtx.buildEffective());
+ });
+ }
}
import org.opendaylight.yangtools.yang.model.api.stmt.IdentityEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.IdentityEffectiveStatementNamespace;
import org.opendaylight.yangtools.yang.model.api.stmt.IdentityStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.ImportEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.PrefixEffectiveStatement;
import org.opendaylight.yangtools.yang.parser.spi.FeatureNamespace;
import org.opendaylight.yangtools.yang.parser.spi.IdentityNamespace;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
final String localPrefix = findFirstEffectiveSubstatementArgument(PrefixEffectiveStatement.class).get();
final Builder<String, ModuleEffectiveStatement> prefixToModuleBuilder = ImmutableMap.builder();
prefixToModuleBuilder.put(localPrefix, this);
-
- streamEffectiveSubstatements(ImportEffectiveStatement.class)
- .map(imp -> imp.findFirstEffectiveSubstatementArgument(PrefixEffectiveStatement.class).get())
- .forEach(prefix -> {
- final StmtContext<?, ?, ?> importedCtx =
- verifyNotNull(ctx.getFromNamespace(ImportPrefixToModuleCtx.class, prefix),
- "Failed to resolve prefix %s", prefix);
- prefixToModuleBuilder.put(prefix, (ModuleEffectiveStatement) importedCtx.buildEffective());
- });
+ appendPrefixes(ctx, prefixToModuleBuilder);
prefixToModule = prefixToModuleBuilder.build();
final Map<QNameModule, String> tmp = Maps.newLinkedHashMapWithExpectedSize(prefixToModule.size() + 1);
import static com.google.common.base.Preconditions.checkState;
import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
import java.util.HashSet;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.yang.common.Revision;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
import org.opendaylight.yangtools.yang.model.api.stmt.BelongsToStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement.PrefixToEffectiveModuleNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement.QNameModuleToPrefixNamespace;
import org.opendaylight.yangtools.yang.model.api.stmt.RevisionEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
final class SubmoduleEffectiveStatementImpl extends AbstractEffectiveModule<SubmoduleStatement>
implements SubmoduleEffectiveStatement, MutableStatement {
-
+ private final ImmutableMap<String, ModuleEffectiveStatement> prefixToModule;
+ private final ImmutableMap<QNameModule, String> namespaceToPrefix;
private final QNameModule qnameModule;
private Set<StmtContext<?, SubmoduleStatement, EffectiveStatement<String, SubmoduleStatement>>> submoduleContexts;
final QNameModule belongsToModuleQName = ctx.getFromNamespace(ModuleNameToModuleQName.class,
belongsToModuleName);
+ final Builder<String, ModuleEffectiveStatement> prefixToModuleBuilder = ImmutableMap.builder();
+ appendPrefixes(ctx, prefixToModuleBuilder);
+ prefixToModule = prefixToModuleBuilder.build();
+
+ final Map<QNameModule, String> tmp = Maps.newLinkedHashMapWithExpectedSize(prefixToModule.size());
+ for (Entry<String, ModuleEffectiveStatement> e : prefixToModule.entrySet()) {
+ tmp.putIfAbsent(e.getValue().localQNameModule(), e.getKey());
+ }
+ namespaceToPrefix = ImmutableMap.copyOf(tmp);
+
final Optional<Revision> submoduleRevision = findFirstEffectiveSubstatementArgument(
RevisionEffectiveStatement.class);
this.qnameModule = QNameModule.create(belongsToModuleQName.getNamespace(), submoduleRevision).intern();
return qnameModule;
}
+ @Override
+ @SuppressWarnings("unchecked")
+ public <K, V, N extends IdentifierNamespace<K, V>> Optional<? extends Map<K, V>> getNamespaceContents(
+ final @NonNull Class<N> namespace) {
+ if (PrefixToEffectiveModuleNamespace.class.equals(namespace)) {
+ return Optional.of((Map<K, V>) prefixToModule);
+ }
+ if (QNameModuleToPrefixNamespace.class.equals(namespace)) {
+ return Optional.of((Map<K, V>) namespaceToPrefix);
+ }
+ return super.getNamespaceContents(namespace);
+ }
+
@Override
public Set<Module> getSubmodules() {
checkState(sealed, "Attempt to get base submodules from unsealed submodule effective statement %s",