X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=inline;f=yang%2Fyang-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fstmt%2Freactor%2FSourceSpecificContext.java;h=dadc28d952e0a8920f7e3bc64cf5ddc4cbb8ec7e;hb=refs%2Fchanges%2F97%2F49697%2F7;hp=3f34be5ffb38b84388327172a199b8a482d9640b;hpb=2e27c9ea697333fc9b63ffc85522be46e0526044;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 3f34be5ffb..dadc28d952 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,39 +8,46 @@ 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.ImmutableTable; import com.google.common.collect.Multimap; +import com.google.common.collect.Table; +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.YangConstants; +import org.opendaylight.yangtools.yang.common.YangVersion; import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; +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.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.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.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.StmtContext; +import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle; +import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToModuleContext; 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.ImpPrefixToNamespace; +import org.opendaylight.yangtools.yang.parser.spi.source.ImportedModuleContext; import org.opendaylight.yangtools.yang.parser.spi.source.ModuleIdentifierToModuleQName; import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule; import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModuleMap; @@ -55,10 +62,14 @@ 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.ModelDefinedStatementDefinition; 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.opendaylight.yangtools.yang.parser.stmt.rfc7950.LeafrefSpecificationRfc7950Support; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBehaviour.Registry, Mutable { @@ -68,99 +79,144 @@ 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(); + @SuppressWarnings({"rawtypes", "unchecked"}) + private final class RootContextBuilder extends ContextBuilder { + RootContextBuilder(final StatementDefinitionContext def, final StatementSourceReference sourceRef) { + super(def, sourceRef); + } - private RootStatementContext root; + @Override + public StatementContextBase build() { + /* + * If root is null or root version is other than default, + * we need to create new root. + */ + if (root == null) { + root = new RootStatementContext(this, SourceSpecificContext.this); + } else if (!RootStatementContext.DEFAULT_VERSION.equals(root.getRootVersion()) + && inProgressPhase == ModelProcessingPhase.SOURCE_LINKAGE) { + root = new RootStatementContext(this, SourceSpecificContext.this, root.getRootVersion()); + } else { + final QName rootStatement = root.definition().getStatementName(); + final String rootArgument = root.rawStatementArgument(); - private ModelProcessingPhase inProgressPhase; - private ModelProcessingPhase finishedPhase = ModelProcessingPhase.INIT; + Preconditions.checkState(Objects.equals(getDefinition().getStatementName(), rootStatement) + && Objects.equals(getRawArgument(), rootArgument), + "Root statement was already defined as '%s %s'.", rootStatement, rootArgument); + } + root.resetLists(); + return root; + } + } + + private static final Logger LOG = LoggerFactory.getLogger(SourceSpecificContext.class); + private static final Table> BUILTIN_TYPE_SUPPORTS = + ImmutableTable.>builder() + .put(YangVersion.VERSION_1, TypeUtils.DECIMAL64, new Decimal64SpecificationImpl.Definition()) + .put(YangVersion.VERSION_1, TypeUtils.UNION, new UnionSpecificationImpl.Definition()) + .put(YangVersion.VERSION_1, TypeUtils.ENUMERATION, new EnumSpecificationImpl.Definition()) + .put(YangVersion.VERSION_1, TypeUtils.LEAF_REF, new LeafrefSpecificationImpl.Definition()) + .put(YangVersion.VERSION_1_1, TypeUtils.LEAF_REF, new LeafrefSpecificationRfc7950Support()) + .put(YangVersion.VERSION_1, TypeUtils.BITS, new BitsSpecificationImpl.Definition()) + .put(YangVersion.VERSION_1, TypeUtils.IDENTITY_REF, new IdentityRefSpecificationImpl.Definition()) + .put(YangVersion.VERSION_1, TypeUtils.INSTANCE_IDENTIFIER, new InstanceIdentifierSpecificationImpl.Definition()) + .build(); + + private static final QName TYPE = YangStmtMapping.TYPE.getStatementName(); + + 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); + } + + boolean isEnabledSemanticVersioning(){ + return currentContext.isEnabledSemanticVersioning(); } ModelProcessingPhase getInProgressPhase() { return inProgressPhase; } - StatementDefinitionContext getDefinition(final QName name) { - return currentContext.getStatementDefinition(name); - } + ContextBuilder createDeclaredChild(final StatementContextBase current, final int childId, + QName name, final String argument, final StatementSourceReference ref) { + // FIXME: BUG-7038: Refactor/clean up this special case + if (TYPE.equals(name)) { + SourceException.throwIfNull(argument, ref, "Type statement requires an argument"); + if (TypeUtils.isYangTypeBodyStmtString(argument)) { + name = QName.create(YangConstants.RFC6020_YIN_MODULE, argument); + } else { + name = QName.create(YangConstants.RFC6020_YIN_MODULE, TYPE.getLocalName()); + } + } - ContextBuilder createDeclaredChild(final StatementContextBase current, final QName name, final StatementSourceReference ref) { - StatementDefinitionContext def = getDefinition(name); + StatementDefinitionContext def = currentContext.getStatementDefinition(getRootVersion(), name); if (def == null) { - //unknown-stmts (from import, include or local-scope) - if (qNameToStmtDefMap.get(Utils.trimPrefix(name)) != null) { - QName key = Utils.qNameFromArgument(current, name.getLocalName()); - if (key != null) { - final StatementContextBase extension = (StatementContextBase) currentContext - .getAllFromNamespace(ExtensionNamespace.class).get(key); - 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 IllegalArgumentException("Not found unknown statement: " + name); - } - } + final StatementSupport extension = qNameToStmtDefMap.get(name); + if (extension != null) { + def = new StatementDefinitionContext<>(extension); } else { - //type-body-stmts - def = resolveTypeBodyStmts(name.getLocalName()); + // type-body-stmts + def = resolveTypeBodyStmts(name.getLocalName(), getRootVersion()); } - } - 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))); + } else if (current != null && current.definition().getRepresentingClass().equals(UnknownStatementImpl.class)) { + /* + * This code wraps statements encountered inside an extension so they do not get confused with regular + * statements. + * + * FIXME: BUG-7037: re-evaluate whether this is really needed, as this is a very expensive way of making + * this work. We really should be peeking into the extension definition to find these nodes, + * as otherwise we are not reusing definitions nor support for these nodes. + */ + final QName qName = Utils.qNameFromArgument(current, name.getLocalName()); + def = new StatementDefinitionContext<>(new UnknownStatementImpl.Definition( + new ModelDefinedStatementDefinition(qName))); } Preconditions.checkArgument(def != null, "Statement %s does not have type mapping defined.", name); + final ContextBuilder ret; if (current == null) { - return createDeclaredRoot(def, ref); + ret = new RootContextBuilder(def, ref); + } else { + ret = current.substatementBuilder(childId, def, ref); } - 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 (argument != null) { + ret.setArgument(argument, ref); + } - }; + return ret; } 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(); } @@ -170,17 +226,34 @@ 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); } @Override - public > void addToLocalStorage(final Class type, final K key, final V value) { - if (ImportedNamespaceContext.class.isAssignableFrom(type)) { - importedNamespaces.add((NamespaceStorageNode) value); + public > void addToLocalStorage(final Class type, final K key, + final V 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); } + + // RootStatementContext takes care of IncludedModuleContext and the rest... getRoot().addToLocalStorage(type, key, value); } @@ -195,8 +268,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; } @@ -208,7 +282,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; } @@ -224,7 +297,8 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh } @Override - public > NamespaceBehaviour getNamespaceBehaviour(final Class type) { + public > NamespaceBehaviour getNamespaceBehaviour( + final Class type) { return currentContext.getNamespaceBehaviour(type); } @@ -234,30 +308,29 @@ 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; + + final Iterator modifier = currentPhaseModifiers.iterator(); while (modifier.hasNext()) { if (modifier.next().tryApply()) { modifier.remove(); @@ -266,11 +339,10 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh } return hasProgressed; - } ModelActionBuilder newInferenceAction(final ModelProcessingPhase phase) { - ModifierImpl action = new ModifierImpl(phase); + final ModifierImpl action = new ModifierImpl(phase); modifiers.put(phase, action); return action; } @@ -281,35 +353,37 @@ 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()); break; case STATEMENT_DEFINITION: source.writeLinkageAndStatementDefinitions(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes()); @@ -322,25 +396,27 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh } } - 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 static StatementDefinitionContext resolveTypeBodyStmts(final String typeArgument, + final YangVersion version) { + StatementSupport support = BUILTIN_TYPE_SUPPORTS.get(version, typeArgument); + + if (support == null) { + support = BUILTIN_TYPE_SUPPORTS.get(YangVersion.VERSION_1, typeArgument); + } + + return support == null ? null : new StatementDefinitionContext<>(support); + } + + 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, null))); + return preLinkagePrefixes; } private PrefixToModule prefixes() { @@ -348,40 +424,45 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh .class); final Map belongsToPrefixes = getRoot().getAllFromNamespace (BelongsToPrefixToModuleIdentifier.class); - if (belongsToPrefixes != null) + 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); } + + allPrefixes.forEach((key, value) -> + prefixToModuleMap.put(key, getRoot().getFromNamespace(ModuleIdentifierToModuleQName.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; } + + public Set getSupportedVersions() { + return currentContext.getSupportedVersions(); + } }