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%2Fstmt%2Freactor%2FSourceSpecificContext.java;h=68c58b96acd251ac594fd68ead09fbeb9db33394;hb=de477e03ba921c71877a357e76a364324406b7c5;hp=fb23468d8d3aa2a44b9735b1230ce4ee7b1e28b7;hpb=afc9771f12441ce707dac07ad282fbbd4022bfb2;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java index fb23468d8d..68c58b96ac 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java @@ -8,40 +8,48 @@ package org.opendaylight.yangtools.yang.parser.stmt.reactor; import com.google.common.base.Preconditions; +import com.google.common.base.Verify; import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; +import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Objects; +import java.util.Optional; +import java.util.Set; import javax.annotation.Nullable; import org.opendaylight.yangtools.concepts.Mutable; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.YangVersion; import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; 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.meta.IdentifierNamespace; -import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition; -import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement; -import org.opendaylight.yangtools.yang.parser.spi.ExtensionNamespace; -import org.opendaylight.yangtools.yang.parser.spi.meta.ImportedNamespaceContext; +import org.opendaylight.yangtools.yang.model.api.meta.StatementSource; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase; +import org.opendaylight.yangtools.yang.parser.spi.meta.MutableStatement; import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour; import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode; import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType; -import org.opendaylight.yangtools.yang.parser.spi.meta.QNameCacheNamespace; +import org.opendaylight.yangtools.yang.parser.spi.meta.StatementDefinitionNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport; +import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; -import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleIdentifier; -import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier; -import org.opendaylight.yangtools.yang.parser.spi.source.ModuleIdentifierToModuleQName; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils; +import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToModuleContext; +import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleCtx; +import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace; +import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx; +import org.opendaylight.yangtools.yang.parser.spi.source.ImportedModuleContext; +import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName; import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule; import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModuleMap; import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition; @@ -49,16 +57,8 @@ import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinit import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference; import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.BitsSpecificationImpl; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Decimal64SpecificationImpl; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.EnumSpecificationImpl; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.IdentityRefSpecificationImpl; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.InstanceIdentifierSpecificationImpl; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.LeafrefSpecificationImpl; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.TypeUtils; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.UnionSpecificationImpl; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.UnknownStatementImpl; -import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBehaviour.Registry, Mutable { @@ -68,100 +68,125 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh FINISHED } - private final StatementStreamSource source; - private final BuildGlobalContext currentContext; - private final Collection importedNamespaces = new ArrayList<>(); - private final Multimap modifiers = HashMultimap.create(); - - private RootStatementContext root; + private static final Logger LOG = LoggerFactory.getLogger(SourceSpecificContext.class); - private ModelProcessingPhase inProgressPhase; - private ModelProcessingPhase finishedPhase = ModelProcessingPhase.INIT; - private final QNameToStatementDefinitionMap qNameToStmtDefMap = new QNameToStatementDefinitionMap(); + private final Multimap modifiers = HashMultimap.create(); + private final QNameToStatementDefinitionMap qnameToStmtDefMap = new QNameToStatementDefinitionMap(); private final PrefixToModuleMap prefixToModuleMap = new PrefixToModuleMap(); + private final BuildGlobalContext currentContext; + private final StatementStreamSource source; + /* + * "imported" namespaces in this source -- this points to RootStatementContexts of + * - modules imported via 'import' statement + * - parent module, declared via 'belongs-to' statement + */ + private Collection> importedNamespaces = ImmutableList.of(); + private ModelProcessingPhase finishedPhase = ModelProcessingPhase.INIT; + private ModelProcessingPhase inProgressPhase; + private RootStatementContext root; SourceSpecificContext(final BuildGlobalContext currentContext, final StatementStreamSource source) { - this.source = source; - this.currentContext = currentContext; + this.currentContext = Preconditions.checkNotNull(currentContext); + this.source = Preconditions.checkNotNull(source); } - ModelProcessingPhase getInProgressPhase() { - return inProgressPhase; + boolean isEnabledSemanticVersioning() { + return currentContext.isEnabledSemanticVersioning(); } - StatementDefinitionContext getDefinition(final QName name) { - return currentContext.getStatementDefinition(name); + ModelProcessingPhase getInProgressPhase() { + return inProgressPhase; } - ContextBuilder createDeclaredChild(final StatementContextBase current, final QName name, - final StatementSourceReference ref) { - StatementDefinitionContext def = getDefinition(name); + StatementContextBase createDeclaredChild(final StatementContextBase current, final int childId, + final QName name, final String argument, final StatementSourceReference ref) { + if (current != null) { + // Fast path: we are entering a statement which was emitted in previous phase + StatementContextBase existing = current.lookupSubstatement(childId); + while (existing != null && StatementSource.CONTEXT == existing.getStatementSource()) { + existing = existing.lookupSubstatement(childId); + } + if (existing != null) { + return existing; + } + } + StatementDefinitionContext def = currentContext.getStatementDefinition(getRootVersion(), name); if (def == null) { - // unknown-stmts (from import, include or local-scope) - if (qNameToStmtDefMap.get(name) != null) { - final StatementContextBase extension = - (StatementContextBase) currentContext.getAllFromNamespace(ExtensionNamespace.class).get(name); + def = currentContext.getModelDefinedStatementDefinition(name); + if (def == null) { + final StatementSupport extension = qnameToStmtDefMap.get(name); if (extension != null) { - final QName arg = (QName) extension.getStatementArgument(); - final QName qName = current.getFromNamespace(QNameCacheNamespace.class, - QName.create(arg, extension.getIdentifier().getArgument())); - - def = new StatementDefinitionContext<>(new UnknownStatementImpl.Definition( - getNewStatementDefinition(qName))); - } else { - throw new SourceException("Extension not found: " + name, - current.getStatementSourceReference()); + def = new StatementDefinitionContext<>(extension); + currentContext.putModelDefinedStatementDefinition(name, def); } - } else { - // type-body-stmts - def = resolveTypeBodyStmts(name.getLocalName()); } + } else if (current != null && StmtContextUtils.isUnrecognizedStatement(current)) { + /* + * This code wraps statements encountered inside an extension so + * they do not get confused with regular statements. + */ + def = Preconditions.checkNotNull(current.definition().getAsUnknownStatementDefinition(def), + "Unable to create unknown statement definition of yang statement %s in unknown statement %s", def, + current); } - else if (current != null && current.definition().getRepresentingClass().equals(UnknownStatementImpl.class)) { - QName qName = Utils.qNameFromArgument(current, name.getLocalName()); - def = new StatementDefinitionContext<>(new UnknownStatementImpl.Definition - (getNewStatementDefinition(qName))); + InferenceException.throwIfNull(def, ref, "Statement %s does not have type mapping defined.", name); + if (def.hasArgument()) { + SourceException.throwIfNull(argument, ref, "Statement %s requires an argument", name); + } else { + SourceException.throwIf(argument != null, ref, "Statement %s does not take argument", name); } - Preconditions.checkArgument(def != null, "Statement %s does not have type mapping defined.", name); - if (current == null) { - return createDeclaredRoot(def, ref); + /* + * If the current statement definition has argument specific + * sub-definitions, get argument specific sub-definition based on given + * argument (e.g. type statement need to be specialized based on its + * argument). + */ + if (def.hasArgumentSpecificSubDefinitions()) { + def = def.getSubDefinitionSpecificForArgument(argument); } - return current.substatementBuilder(def, ref); - } - - // FIXME: This should be populated differently - StatementDefinition getNewStatementDefinition(final QName qName) { - return new ModelDefinedStatementDefinition(qName); - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - private ContextBuilder createDeclaredRoot(final StatementDefinitionContext def, - final StatementSourceReference ref) { - return new ContextBuilder(def, ref) { - @Override - public StatementContextBase build() throws SourceException { - if (root == null) { - root = new RootStatementContext(this, SourceSpecificContext.this); - } else { - Preconditions.checkState(root.getIdentifier().equals(createIdentifier()), - "Root statement was already defined as %s.", root.getIdentifier()); - } - root.resetLists(); - return root; - } + if (current != null) { + return current.createSubstatement(childId, def, ref, argument); + } - }; + /* + * If root is null or root version is other than default, + * we need to create new root. + */ + if (root == null) { + root = new RootStatementContext<>(this, def, ref, argument); + } else if (!RootStatementContext.DEFAULT_VERSION.equals(root.getRootVersion()) + && inProgressPhase == ModelProcessingPhase.SOURCE_LINKAGE) { + root = new RootStatementContext<>(this, def, ref, argument, root.getRootVersion(), + root.getRootIdentifier()); + } else { + final QName rootStatement = root.definition().getStatementName(); + final String rootArgument = root.rawStatementArgument(); + + Preconditions.checkState(Objects.equals(def.getStatementName(), rootStatement) + && Objects.equals(argument, rootArgument), "Root statement was already defined as '%s %s'.", + rootStatement, rootArgument); + } + return root; } RootStatementContext getRoot() { return root; } + /** + * Return version of root statement context. + * + * @return version of root statement context + */ + YangVersion getRootVersion() { + return root != null ? root.getRootVersion() : RootStatementContext.DEFAULT_VERSION; + } + DeclaredStatement buildDeclared() { return root.buildDeclared(); } @@ -171,20 +196,49 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh } void startPhase(final ModelProcessingPhase phase) { - @Nullable - ModelProcessingPhase previousPhase = phase.getPreviousPhase(); - Preconditions.checkState(Objects.equals(previousPhase, finishedPhase)); - Preconditions.checkState(modifiers.get(previousPhase).isEmpty()); + @Nullable final ModelProcessingPhase previousPhase = phase.getPreviousPhase(); + Verify.verify(Objects.equals(previousPhase, finishedPhase), + "Phase sequencing violation: previous phase should be %s, source %s has %s", previousPhase, source, + finishedPhase); + + final Collection previousModifiers = modifiers.get(previousPhase); + Preconditions.checkState(previousModifiers.isEmpty(), + "Previous phase %s has unresolved modifiers %s in source %s", previousPhase, previousModifiers, source); + inProgressPhase = phase; + LOG.debug("Source {} started phase {}", source, phase); + } + + private void updateImportedNamespaces(final Class type, final Object value) { + if (BelongsToModuleContext.class.isAssignableFrom(type) || ImportedModuleContext.class.isAssignableFrom(type)) { + if (importedNamespaces.isEmpty()) { + importedNamespaces = new ArrayList<>(1); + } + + Verify.verify(value instanceof RootStatementContext); + importedNamespaces.add((RootStatementContext) value); + } + } + + @Override + public > V putToLocalStorage(final Class type, final K key, + final V value) { + // RootStatementContext takes care of IncludedModuleContext and the rest... + final V ret = getRoot().putToLocalStorage(type, key, value); + // FIXME: what about duplicates? + updateImportedNamespaces(type, value); + return ret; } @Override - public > void addToLocalStorage(final Class type, final K key, + public > V putToLocalStorageIfAbsent(final Class type, final K key, final V value) { - if (ImportedNamespaceContext.class.isAssignableFrom(type)) { - importedNamespaces.add((NamespaceStorageNode) value); + // RootStatementContext takes care of IncludedModuleContext and the rest... + final V ret = getRoot().putToLocalStorageIfAbsent(type, key, value); + if (ret == null) { + updateImportedNamespaces(type, value); } - getRoot().addToLocalStorage(type, key, value); + return ret; } @Override @@ -198,8 +252,9 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh if (potentialLocal != null) { return potentialLocal; } - for (NamespaceStorageNode importedSource : importedNamespaces) { - V potential = importedSource.getFromLocalStorage(type, key); + + for (final NamespaceStorageNode importedSource : importedNamespaces) { + final V potential = importedSource.getFromLocalStorage(type, key); if (potential != null) { return potential; } @@ -211,7 +266,6 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh @Override public > Map getAllFromLocalStorage(final Class type) { final Map potentialLocal = getRoot().getAllFromLocalStorage(type); - if (potentialLocal != null) { return potentialLocal; } @@ -238,30 +292,30 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh } PhaseCompletionProgress tryToCompletePhase(final ModelProcessingPhase phase) throws SourceException { - Collection currentPhaseModifiers = modifiers.get(phase); + final Collection currentPhaseModifiers = modifiers.get(phase); boolean hasProgressed = tryToProgress(currentPhaseModifiers); - boolean phaseCompleted = root.tryToCompletePhase(phase); + Preconditions.checkNotNull(this.root, "Malformed source. Valid root element is missing."); + final boolean phaseCompleted = root.tryToCompletePhase(phase); - hasProgressed = (tryToProgress(currentPhaseModifiers) | hasProgressed); + hasProgressed |= tryToProgress(currentPhaseModifiers); - if (phaseCompleted && (currentPhaseModifiers.isEmpty())) { + if (phaseCompleted && currentPhaseModifiers.isEmpty()) { finishedPhase = phase; + LOG.debug("Source {} finished phase {}", source, phase); return PhaseCompletionProgress.FINISHED; } - if (hasProgressed) { - return PhaseCompletionProgress.PROGRESS; - } - return PhaseCompletionProgress.NO_PROGRESS; - } + return hasProgressed ? PhaseCompletionProgress.PROGRESS : PhaseCompletionProgress.NO_PROGRESS; + } private static boolean tryToProgress(final Collection currentPhaseModifiers) { - - Iterator modifier = currentPhaseModifiers.iterator(); boolean hasProgressed = false; + + // Try making forward progress ... + final Iterator modifier = currentPhaseModifiers.iterator(); while (modifier.hasNext()) { if (modifier.next().tryApply()) { modifier.remove(); @@ -270,11 +324,10 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh } return hasProgressed; - } ModelActionBuilder newInferenceAction(final ModelProcessingPhase phase) { - ModifierImpl action = new ModifierImpl(phase); + final ModifierImpl action = new ModifierImpl(); modifiers.put(phase, action); return action; } @@ -285,107 +338,123 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh + finishedPhase + "]"; } - SourceException failModifiers(final ModelProcessingPhase identifier) { + Optional failModifiers(final ModelProcessingPhase identifier) { final List exceptions = new ArrayList<>(); - for (ModifierImpl mod : modifiers.get(identifier)) { + for (final ModifierImpl mod : modifiers.get(identifier)) { try { mod.failModifier(); - } catch (SourceException e) { + } catch (final SourceException e) { exceptions.add(e); } } - final String message = String.format("Yang model processing phase %s failed", identifier); if (exceptions.isEmpty()) { - return new InferenceException(message, root.getStatementSourceReference()); + return Optional.empty(); } + final String message = String.format("Yang model processing phase %s failed", identifier); final InferenceException e = new InferenceException(message, root.getStatementSourceReference(), exceptions.get(0)); - final Iterator it = exceptions.listIterator(1); - while (it.hasNext()) { - e.addSuppressed(it.next()); - } + exceptions.listIterator(1).forEachRemaining(e::addSuppressed); - return e; + return Optional.of(e); } void loadStatements() throws SourceException { + LOG.trace("Source {} loading statements for phase {}", source, inProgressPhase); + switch (inProgressPhase) { + case SOURCE_PRE_LINKAGE: + source.writePreLinkage(new StatementContextWriter(this, inProgressPhase), stmtDef()); + break; case SOURCE_LINKAGE: - source.writeLinkage(new StatementContextWriter(this, inProgressPhase), stmtDef()); + source.writeLinkage(new StatementContextWriter(this, inProgressPhase), stmtDef(), preLinkagePrefixes(), + getRootVersion()); break; case STATEMENT_DEFINITION: - source.writeLinkageAndStatementDefinitions(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes()); + source.writeLinkageAndStatementDefinitions(new StatementContextWriter(this, inProgressPhase), stmtDef(), + prefixes(), getRootVersion()); break; case FULL_DECLARATION: - source.writeFull(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes()); + source.writeFull(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes(), + getRootVersion()); break; default: break; } } - private static StatementDefinitionContext resolveTypeBodyStmts(final String typeArgument) { - switch (typeArgument) { - case TypeUtils.DECIMAL64: - return new StatementDefinitionContext<>(new Decimal64SpecificationImpl.Definition()); - case TypeUtils.UNION: - return new StatementDefinitionContext<>(new UnionSpecificationImpl.Definition()); - case TypeUtils.ENUMERATION: - return new StatementDefinitionContext<>(new EnumSpecificationImpl.Definition()); - case TypeUtils.LEAF_REF: - return new StatementDefinitionContext<>(new LeafrefSpecificationImpl.Definition()); - case TypeUtils.BITS: - return new StatementDefinitionContext<>(new BitsSpecificationImpl.Definition()); - case TypeUtils.IDENTITY_REF: - return new StatementDefinitionContext<>(new IdentityRefSpecificationImpl.Definition()); - case TypeUtils.INSTANCE_IDENTIFIER: - return new StatementDefinitionContext<>(new InstanceIdentifierSpecificationImpl.Definition()); - default: - return null; + private PrefixToModule preLinkagePrefixes() { + final PrefixToModuleMap preLinkagePrefixes = new PrefixToModuleMap(true); + final Map prefixToNamespaceMap = getAllFromLocalStorage(ImpPrefixToNamespace.class); + if (prefixToNamespaceMap == null) { + //:FIXME if it is a submodule without any import, the map is null. Handle also submodules and includes... + return null; } + + prefixToNamespaceMap.forEach((key, value) -> preLinkagePrefixes.put(key, QNameModule.create(value))); + return preLinkagePrefixes; } private PrefixToModule prefixes() { - final Map allPrefixes = getRoot().getAllFromNamespace(ImpPrefixToModuleIdentifier - .class); - final Map belongsToPrefixes = getRoot().getAllFromNamespace - (BelongsToPrefixToModuleIdentifier.class); - if (belongsToPrefixes != null) - allPrefixes.putAll(belongsToPrefixes); - - for (Entry stringModuleIdentifierEntry : allPrefixes.entrySet()) { - final QNameModule namespace = getRoot().getFromNamespace(ModuleIdentifierToModuleQName.class, - stringModuleIdentifierEntry.getValue()); - prefixToModuleMap.put(stringModuleIdentifierEntry.getKey(), namespace); + final Map> allImports = getRoot().getAllFromNamespace( + ImportPrefixToModuleCtx.class); + if (allImports != null) { + allImports.forEach((key, value) -> + prefixToModuleMap.put(key, getRoot().getFromNamespace(ModuleCtxToModuleQName.class, value))); } + + final Map> allBelongsTo = getRoot().getAllFromNamespace( + BelongsToPrefixToModuleCtx.class); + if (allBelongsTo != null) { + allBelongsTo.forEach((key, value) -> + prefixToModuleMap.put(key, getRoot().getFromNamespace(ModuleCtxToModuleQName.class, value))); + } + return prefixToModuleMap; } private QNameToStatementDefinition stmtDef() { - // regular YANG statements added - ImmutableMap> definitions = currentContext.getSupportsForPhase( - inProgressPhase).getDefinitions(); - for (Map.Entry> entry : definitions.entrySet()) { - qNameToStmtDefMap.put(entry.getKey(), entry.getValue()); + // regular YANG statements and extension supports added + final StatementSupportBundle supportsForPhase = currentContext.getSupportsForPhase(inProgressPhase); + qnameToStmtDefMap.putAll(supportsForPhase.getCommonDefinitions()); + qnameToStmtDefMap.putAll(supportsForPhase.getDefinitionsSpecificForVersion(getRootVersion())); + + // No further actions needed + if (inProgressPhase != ModelProcessingPhase.FULL_DECLARATION) { + return qnameToStmtDefMap; } - // extensions added - if (inProgressPhase.equals(ModelProcessingPhase.FULL_DECLARATION)) { - Map>> extensions = currentContext - .getAllFromNamespace(ExtensionNamespace.class); - if (extensions != null) { - for (Map.Entry>> extension : extensions - .entrySet()) { - qNameToStmtDefMap - .put((extension.getKey()), - (StatementDefinition) ((StatementContextBase) extension - .getValue()).definition() - .getFactory()); + // We need to any and all extension statements which have been declared in the context + final Map> extensions = currentContext.getAllFromNamespace( + StatementDefinitionNamespace.class); + if (extensions != null) { + extensions.forEach((qname, support) -> { + final StatementSupport existing = qnameToStmtDefMap.putIfAbsent(qname, support); + if (existing != null) { + LOG.debug("Source {} already defines statement {} as {}", source, qname, existing); + } else { + LOG.debug("Source {} defined statement {} as {}", source, qname, support); } - } + }); } - return qNameToStmtDefMap; + + return qnameToStmtDefMap; + } + + public Set getSupportedVersions() { + return currentContext.getSupportedVersions(); + } + + void addMutableStmtToSeal(final MutableStatement mutableStatement) { + currentContext.addMutableStmtToSeal(mutableStatement); + } + + Collection getRequiredSources() { + return root.getRequiredSources(); + } + + ModuleIdentifier getRootIdentifier() { + return root.getRootIdentifier(); } }