X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-rfc7950%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Frfc7950%2Fstmt%2FAbstractEffectiveModule.java;h=aab5cb9ac333835b953d68c5fee8a504e4a12408;hb=60aaa85b10b02b29f357fb53fed5723a498e1cef;hp=3b7dc1f8aa8f9de01a4b9a279704615bea88aea1;hpb=dbe90727194b03e303eb1a245f98eb210f33b512;p=yangtools.git diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/AbstractEffectiveModule.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/AbstractEffectiveModule.java index 3b7dc1f8aa..aab5cb9ac3 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/AbstractEffectiveModule.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/AbstractEffectiveModule.java @@ -7,294 +7,124 @@ */ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt; -import static com.google.common.base.Preconditions.checkState; +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.base.Verify; +import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; 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 java.net.URI; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedHashMap; +import java.util.Collection; import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.yangtools.concepts.SemVer; import org.opendaylight.yangtools.openconfig.model.api.OpenConfigVersionEffectiveStatement; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.common.UnqualifiedQName; import org.opendaylight.yangtools.yang.common.YangVersion; import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; -import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.Deviation; import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition; import org.opendaylight.yangtools.yang.model.api.FeatureDefinition; import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; -import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.ModuleImport; +import org.opendaylight.yangtools.yang.model.api.ModuleLike; import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; -import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; -import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode; import org.opendaylight.yangtools.yang.model.api.UsesNode; -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.EffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.BelongsToEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; import org.opendaylight.yangtools.yang.model.api.stmt.ContactEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeAwareEffectiveStatement; +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.SubmoduleEffectiveStatement; -import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.YangVersionEffectiveStatement; -import org.opendaylight.yangtools.yang.parser.spi.meta.MutableStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.compat.NotificationNodeContainerCompat; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredEffectiveStatement.DefaultWithDataTree.WithSubstatements; +import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.DocumentedNodeMixin; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; -import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; -import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx; +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 -public abstract class AbstractEffectiveModule> extends - AbstractSchemaEffectiveDocumentedNode implements Module, MutableStatement { - private final String name; +public abstract class AbstractEffectiveModule, + E extends DataTreeAwareEffectiveStatement> + extends WithSubstatements + implements ModuleLike, DocumentedNodeMixin, + NotificationNodeContainerCompat { private final String prefix; - private final YangVersion yangVersion; - private final String organization; - private final String contact; - private final Set imports; - private final Set features; - private final Set notifications; - private final Set augmentations; - private final Set rpcs; - private final Set deviations; - private final List extensionNodes; - private final Set identities; - private final @NonNull List unknownNodes; - private final Map childNodes; - private final Set groupings; - private final Set uses; - private final Set> typeDefinitions; - private final Set publicChildNodes; - private final SemVer semanticVersion; - - private Set>> - submoduleContextsToBuild; - private Set submodules; - private boolean sealed; - - protected AbstractEffectiveModule(final StmtContext> ctx) { - super(ctx); - - this.name = argument(); - - final EffectiveStatement parentOfPrefix; - if (ctx.getPublicDefinition() == YangStmtMapping.SUBMODULE) { - final Optional optParent = - findFirstEffectiveSubstatement(BelongsToEffectiveStatement.class); - SourceException.throwIf(!optParent.isPresent(), ctx.getStatementSourceReference(), - "Unable to find belongs-to statement in submodule %s.", ctx.getStatementArgument()); - parentOfPrefix = optParent.get(); - } else { - parentOfPrefix = this; - } - - final Optional<@NonNull PrefixEffectiveStatement> prefixStmt = parentOfPrefix.findFirstEffectiveSubstatement( - PrefixEffectiveStatement.class); - SourceException.throwIf(!prefixStmt.isPresent(), ctx.getStatementSourceReference(), - "Unable to resolve prefix for module or submodule %s.", ctx.getStatementArgument()); - this.prefix = prefixStmt.get().argument(); - this.yangVersion = findFirstEffectiveSubstatementArgument(YangVersionEffectiveStatement.class) - .orElse(YangVersion.VERSION_1); - this.semanticVersion = findFirstEffectiveSubstatementArgument(OpenConfigVersionEffectiveStatement.class) - .orElse(null); - this.organization = findFirstEffectiveSubstatementArgument(OrganizationEffectiveStatement.class) - .orElse(null); - this.contact = findFirstEffectiveSubstatementArgument(ContactEffectiveStatement.class) - .orElse(null); - - // init submodules and substatements of submodules - final List> substatementsOfSubmodules; - final Map> includedSubmodulesMap = ctx - .getAllFromCurrentStmtCtxNamespace(IncludedSubmoduleNameToModuleCtx.class); - - if (includedSubmodulesMap == null || includedSubmodulesMap.isEmpty()) { - this.submodules = ImmutableSet.of(); - this.submoduleContextsToBuild = ImmutableSet.of(); - substatementsOfSubmodules = ImmutableList.of(); - } else if (YangStmtMapping.MODULE.equals(ctx.getPublicDefinition())) { - /* - * Aggregation of substatements from submodules should be done only - * for modules. In case of submodules it does not make sense because - * of possible circular chains of includes between submodules. - */ - final Set submodulesInit = new HashSet<>(); - final List> substatementsOfSubmodulesInit = new ArrayList<>(); - for (final StmtContext submoduleCtx : includedSubmodulesMap.values()) { - final EffectiveStatement submodule = submoduleCtx.buildEffective(); - Verify.verify(submodule instanceof SubmoduleEffectiveStatement); - Verify.verify(submodule instanceof Module, "Submodule statement %s is not a Module", submodule); - submodulesInit.add((Module) submodule); - substatementsOfSubmodulesInit.addAll(submodule.effectiveSubstatements().stream() - .filter(sub -> sub instanceof SchemaNode || sub instanceof DataNodeContainer) - .collect(Collectors.toList())); - } - - this.submodules = ImmutableSet.copyOf(submodulesInit); - this.submoduleContextsToBuild = ImmutableSet.of(); - substatementsOfSubmodules = ImmutableList.copyOf(substatementsOfSubmodulesInit); - } else { - /* - * Because of possible circular chains of includes between submodules we can - * collect only submodule contexts here and then build them during - * sealing of this statement. - */ - final Set>> - submoduleContextsInit = new HashSet<>(); - for (final StmtContext submoduleCtx : includedSubmodulesMap.values()) { - submoduleContextsInit.add( - (StmtContext>)submoduleCtx); - } - - this.submoduleContextsToBuild = ImmutableSet.copyOf(submoduleContextsInit); - substatementsOfSubmodules = ImmutableList.of(); - } - - if (!submoduleContextsToBuild.isEmpty()) { - ((Mutable) ctx).addMutableStmtToSeal(this); - sealed = false; - } else { - sealed = true; - } - - // init substatements collections - final List> effectiveSubstatements = new ArrayList<>(); - effectiveSubstatements.addAll(effectiveSubstatements()); - effectiveSubstatements.addAll(substatementsOfSubmodules); - - final List unknownNodesInit = new ArrayList<>(); - final Set augmentationsInit = new LinkedHashSet<>(); - final Set importsInit = new HashSet<>(); - final Set notificationsInit = new HashSet<>(); - final Set rpcsInit = new HashSet<>(); - final Set deviationsInit = new HashSet<>(); - final Set identitiesInit = new HashSet<>(); - final Set featuresInit = new HashSet<>(); - final List extensionNodesInit = new ArrayList<>(); - - final Map mutableChildNodes = new LinkedHashMap<>(); - final Set mutableGroupings = new HashSet<>(); - final Set mutableUses = new HashSet<>(); + private final ImmutableSet groupings; + private final ImmutableSet uses; + private final ImmutableSet> typeDefinitions; + private final ImmutableMap> schemaTreeNamespace; + + protected AbstractEffectiveModule(final D declared, + final StmtContext> ctx, + final ImmutableList> substatements, final String prefix) { + super(declared, ctx, substatements); + + // This check is rather weird, but comes from our desire to lower memory footprint while providing both + // EffectiveStatements and SchemaNode interfaces -- which do not overlap completely where child lookups are + // concerned. This ensures that we have SchemaTree index available for use with child lookups. + final Map> schemaTree = + createSchemaTreeNamespace(ctx.getStatementSourceReference(), effectiveSubstatements()); + schemaTreeNamespace = ImmutableMap.copyOf(schemaTree); + + // Data tree check, not currently used + createDataTreeNamespace(ctx.getStatementSourceReference(), schemaTree.values(), schemaTreeNamespace); + + this.prefix = requireNonNull(prefix); + + final Set mutableGroupings = new LinkedHashSet<>(); + final Set mutableUses = new LinkedHashSet<>(); final Set> mutableTypeDefinitions = new LinkedHashSet<>(); - final Set mutablePublicChildNodes = new LinkedHashSet<>(); - for (final EffectiveStatement effectiveStatement : effectiveSubstatements) { - if (effectiveStatement instanceof UnknownSchemaNode) { - unknownNodesInit.add((UnknownSchemaNode) effectiveStatement); - } - if (effectiveStatement instanceof AugmentationSchemaNode) { - augmentationsInit.add((AugmentationSchemaNode) effectiveStatement); - } - if (effectiveStatement instanceof ModuleImport) { - importsInit.add((ModuleImport) effectiveStatement); - } - if (effectiveStatement instanceof NotificationDefinition) { - notificationsInit.add((NotificationDefinition) effectiveStatement); - } - if (effectiveStatement instanceof RpcDefinition) { - rpcsInit.add((RpcDefinition) effectiveStatement); - } - if (effectiveStatement instanceof Deviation) { - deviationsInit.add((Deviation) effectiveStatement); - } - if (effectiveStatement instanceof IdentitySchemaNode) { - identitiesInit.add((IdentitySchemaNode) effectiveStatement); - } - if (effectiveStatement instanceof FeatureDefinition) { - featuresInit.add((FeatureDefinition) effectiveStatement); - } - if (effectiveStatement instanceof ExtensionDefinition) { - extensionNodesInit.add((ExtensionDefinition) effectiveStatement); - } - if (effectiveStatement instanceof DataSchemaNode) { - final DataSchemaNode dataSchemaNode = (DataSchemaNode) effectiveStatement; - if (!mutableChildNodes.containsKey(dataSchemaNode.getQName())) { - mutableChildNodes.put(dataSchemaNode.getQName(), dataSchemaNode); - mutablePublicChildNodes.add(dataSchemaNode); - } else { - throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement); - } - } - if (effectiveStatement instanceof UsesNode) { - final UsesNode usesNode = (UsesNode) effectiveStatement; - if (!mutableUses.contains(usesNode)) { - mutableUses.add(usesNode); - } else { - throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement); - } + for (final EffectiveStatement effectiveStatement : effectiveSubstatements()) { + if (effectiveStatement instanceof UsesNode && !mutableUses.add((UsesNode) effectiveStatement)) { + throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement); } if (effectiveStatement instanceof TypedefEffectiveStatement) { - final TypedefEffectiveStatement typeDef = (TypedefEffectiveStatement) effectiveStatement; - final TypeDefinition type = typeDef.getTypeDefinition(); - if (!mutableTypeDefinitions.contains(type)) { - mutableTypeDefinitions.add(type); - } else { + final TypeDefinition type = ((TypedefEffectiveStatement) effectiveStatement).getTypeDefinition(); + if (!mutableTypeDefinitions.add(type)) { throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement); } } - if (effectiveStatement instanceof GroupingDefinition) { - final GroupingDefinition grp = (GroupingDefinition) effectiveStatement; - if (!mutableGroupings.contains(grp)) { - mutableGroupings.add(grp); - } else { - throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement); - } + if (effectiveStatement instanceof GroupingDefinition + && !mutableGroupings.add((GroupingDefinition) effectiveStatement)) { + throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement); } } - this.unknownNodes = ImmutableList.copyOf(unknownNodesInit); - this.augmentations = ImmutableSet.copyOf(augmentationsInit); - this.imports = ImmutableSet.copyOf(importsInit); - this.notifications = ImmutableSet.copyOf(notificationsInit); - this.rpcs = ImmutableSet.copyOf(rpcsInit); - this.deviations = ImmutableSet.copyOf(deviationsInit); - this.identities = ImmutableSet.copyOf(identitiesInit); - this.features = ImmutableSet.copyOf(featuresInit); - this.extensionNodes = ImmutableList.copyOf(extensionNodesInit); - - this.childNodes = ImmutableMap.copyOf(mutableChildNodes); this.groupings = ImmutableSet.copyOf(mutableGroupings); - this.publicChildNodes = ImmutableSet.copyOf(mutablePublicChildNodes); this.typeDefinitions = ImmutableSet.copyOf(mutableTypeDefinitions); this.uses = ImmutableSet.copyOf(mutableUses); - } @Override - public URI getNamespace() { - return getQNameModule().getNamespace(); + public UnqualifiedQName argument() { + return getDeclared().argument(); } @Override public String getName() { - return name; - } - - @Override - public Optional getRevision() { - return getQNameModule().getRevision(); + return argument().getLocalName(); } @Override @@ -304,121 +134,135 @@ public abstract class AbstractEffectiveModule getOrganization() { - return Optional.ofNullable(organization); + return findFirstEffectiveSubstatementArgument(OrganizationEffectiveStatement.class); } @Override public Optional getContact() { - return Optional.ofNullable(contact); - } - - @Override - public Set getImports() { - return imports; - } - - @Override - public Set getSubmodules() { - checkState(sealed, "Attempt to get base submodules from unsealed submodule effective statement %s", - getQNameModule()); - return submodules; + return findFirstEffectiveSubstatementArgument(ContactEffectiveStatement.class); } @Override - public Set getFeatures() { - return features; + public Collection getImports() { + return filterSubstatements(ModuleImport.class); } @Override - public Set getNotifications() { - return notifications; + public Collection getFeatures() { + return filterSubstatements(FeatureDefinition.class); } @Override - public Set getAugmentations() { - return augmentations; + public Collection getNotifications() { + return filterSubstatements(NotificationDefinition.class); } @Override - public Set getRpcs() { - return rpcs; + public Collection getAugmentations() { + return filterSubstatements(AugmentationSchemaNode.class); } @Override - public Set getDeviations() { - return deviations; + public Collection getRpcs() { + return filterSubstatements(RpcDefinition.class); } @Override - public List getExtensionSchemaNodes() { - return extensionNodes; + public Collection getDeviations() { + return filterSubstatements(Deviation.class); } @Override - public Set getIdentities() { - return identities; + public Collection getExtensionSchemaNodes() { + return filterSubstatements(ExtensionDefinition.class); } @Override - public List getUnknownSchemaNodes() { - return unknownNodes; + public Collection getIdentities() { + return filterSubstatements(IdentitySchemaNode.class); } @Override - public final Set> getTypeDefinitions() { + public final Collection> getTypeDefinitions() { return typeDefinitions; } @Override - public final Set getChildNodes() { - return publicChildNodes; + public final Collection getChildNodes() { + return filterSubstatements(DataSchemaNode.class); } @Override - public final Set getGroupings() { + public final Collection getGroupings() { return groupings; } @Override @SuppressWarnings("checkstyle:hiddenField") public final Optional findDataChildByName(final QName name) { - // Child nodes are keyed by their container name, so we can do a direct lookup - return Optional.ofNullable(childNodes.get(requireNonNull(name))); + final SchemaTreeEffectiveStatement child = schemaTreeNamespace.get(requireNonNull(name)); + return child instanceof DataSchemaNode ? Optional.of((DataSchemaNode) child) : Optional.empty(); } @Override - public Set getUses() { + public Collection getUses() { return uses; } @Override public Optional getSemanticVersion() { - return Optional.ofNullable(semanticVersion); + return findFirstEffectiveSubstatementArgument(OpenConfigVersionEffectiveStatement.class); + } + + @Override + @SuppressWarnings("unchecked") + protected > Optional> getNamespaceContents( + final Class namespace) { + if (SchemaTreeAwareEffectiveStatement.Namespace.class.equals(namespace)) { + return Optional.of((Map) schemaTreeNamespace); + } + return super.getNamespaceContents(namespace); } @Override public String toString() { return MoreObjects.toStringHelper(this).omitNullValues() - .add("name", name) + .add("name", getName()) .add("namespace", getNamespace()) .add("revision", getRevision().orElse(null)) .add("prefix", prefix) - .add("yangVersion", yangVersion) + .add("yangVersion", getYangVersion()) .toString(); } - @Override - public void seal() { - if (!sealed) { - submodules = ImmutableSet.copyOf(Iterables.transform(submoduleContextsToBuild, - ctx -> (Module) ctx.buildEffective())); - submoduleContextsToBuild = ImmutableSet.of(); - sealed = true; - } + protected static final @NonNull String findPrefix(final @NonNull StmtContext ctx, + final String type, final String name) { + return SourceException.throwIfNull( + 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 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()); + }); + } + + @SuppressWarnings("unchecked") + private @NonNull Collection filterSubstatements(final Class type) { + return (Collection) Collections2.filter(effectiveSubstatements(), type::isInstance); } }