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=48447300ef9699139cea6c389d23bf558ef650c1;hb=936f49c81f8e69826ef2c5a5923dfe697853675f;hp=7cdcfb0ab5117663cf8c886e96539e1aabe7d6b1;hpb=e9f9f9f58e79ea99d4b76637087de1a5df4115db;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 7cdcfb0ab5..48447300ef 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 @@ -9,17 +9,28 @@ package org.opendaylight.yangtools.yang.parser.stmt.reactor; import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableMap; 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 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.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.parser.spi.meta.InferenceException; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder; @@ -27,12 +38,33 @@ 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.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.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.ModuleIdentifierToModuleQName; 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; +import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinitionMap; 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.reactor.StatementContextBase.ContextBuilder; +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.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.slf4j.Logger; +import org.slf4j.LoggerFactory; public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBehaviour.Registry, Mutable { @@ -42,45 +74,82 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh FINISHED } + private static final Logger LOG = LoggerFactory.getLogger(SourceSpecificContext.class); + private final StatementStreamSource source; private final BuildGlobalContext currentContext; private final Collection importedNamespaces = new ArrayList<>(); private final Multimap modifiers = HashMultimap.create(); - private RootStatementContext root; - private ModelProcessingPhase inProgressPhase; - private ModelProcessingPhase finishedPhase; + private final QNameToStatementDefinitionMap qNameToStmtDefMap = new QNameToStatementDefinitionMap(); + private final PrefixToModuleMap prefixToModuleMap = new PrefixToModuleMap(); + private ModelProcessingPhase finishedPhase = ModelProcessingPhase.INIT; + private ModelProcessingPhase inProgressPhase; + private RootStatementContext root; - SourceSpecificContext(BuildGlobalContext currentContext,StatementStreamSource source) { - this.source = source; + SourceSpecificContext(final BuildGlobalContext currentContext, final StatementStreamSource source) { this.currentContext = currentContext; + this.source = source; + } + + public boolean isEnabledSemanticVersioning(){ + return currentContext.isEnabledSemanticVersioning(); + } + + ModelProcessingPhase getInProgressPhase() { + return inProgressPhase; } - StatementDefinitionContext getDefinition(QName name) { + StatementDefinitionContext getDefinition(final QName name) { return currentContext.getStatementDefinition(name); } - ContextBuilder createDeclaredChild(StatementContextBase current, QName name, StatementSourceReference ref) { - StatementDefinitionContext def = getDefinition(name); - Preconditions.checkArgument(def != null, "Statement %s does not have type mapping defined.",name); - if(current == null) { - return createDeclaredRoot(def,ref); + ContextBuilder createDeclaredChild(final StatementContextBase current, final QName name, + final StatementSourceReference ref) { + StatementDefinitionContext def = getDefinition(name); + + if (def == null) { + // unknown-stmts (from import, include or local-scope) + if (qNameToStmtDefMap.get(name) != null) { + final StatementDefinition extension = currentContext.getFromNamespace( + StatementDefinitionNamespace.class, name); + SourceException.throwIfNull(extension, current.getStatementSourceReference(), "Extension %s not found", + name); + + def = new StatementDefinitionContext<>(new UnknownStatementImpl.Definition(extension)); + } else { + // type-body-stmts + def = resolveTypeBodyStmts(name.getLocalName()); + } + } else if (current != null && current.definition().getRepresentingClass().equals(UnknownStatementImpl.class)) { + // FIXME: What's going on here? + final QName qName = Utils.qNameFromArgument(current, name.getLocalName()); + + def = new StatementDefinitionContext<>(new UnknownStatementImpl.Definition( + new ModelDefinedStatementDefinition(qName))); } - return current.substatementBuilder(def,ref); + + Preconditions.checkArgument(def != null, "Statement %s does not have type mapping defined.", name); + if (current == null) { + return createDeclaredRoot(def, ref); + } + return current.substatementBuilder(def, ref); } - @SuppressWarnings({ "rawtypes", "unchecked" }) - private ContextBuilder createDeclaredRoot(StatementDefinitionContext def, StatementSourceReference ref) { - return new ContextBuilder(def,ref) { + @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) { + public StatementContextBase build() { + if (root == null) { root = new RootStatementContext(this, SourceSpecificContext.this); } else { - Preconditions.checkState(root.getIdentifier().equals(getIdentifier()), "Root statement was already defined."); + Preconditions.checkState(root.getIdentifier().equals(createIdentifier()), + "Root statement was already defined as %s.", root.getIdentifier()); } root.resetLists(); return root; @@ -89,7 +158,7 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh }; } - RootStatementContext getRoot() { + RootStatementContext getRoot() { return root; } @@ -97,20 +166,22 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh return root.buildDeclared(); } - EffectiveStatement build() { + EffectiveStatement buildEffective() { return root.buildEffective(); } - void startPhase(ModelProcessingPhase phase) { - @Nullable ModelProcessingPhase previousPhase = phase.getPreviousPhase(); + void startPhase(final ModelProcessingPhase phase) { + @Nullable final ModelProcessingPhase previousPhase = phase.getPreviousPhase(); Preconditions.checkState(Objects.equals(previousPhase, finishedPhase)); Preconditions.checkState(modifiers.get(previousPhase).isEmpty()); inProgressPhase = phase; + LOG.debug("Source {} started phase {}", source, phase); } @Override - public > void addToLocalStorage(Class type, K key, V value) { - if(ImportedNamespaceContext.class.isAssignableFrom(type)) { + public > void addToLocalStorage(final Class type, final K key, + final V value) { + if (ImportedNamespaceContext.class.isAssignableFrom(type)) { importedNamespaces.add((NamespaceStorageNode) value); } getRoot().addToLocalStorage(type, key, value); @@ -118,26 +189,46 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh @Override public StorageNodeType getStorageNodeType() { - return StorageNodeType.SourceLocalSpecial; + return StorageNodeType.SOURCE_LOCAL_SPECIAL; } @Override - public > V getFromLocalStorage(Class type, K key) { + public > V getFromLocalStorage(final Class type, final K key) { final V potentialLocal = getRoot().getFromLocalStorage(type, key); - if(potentialLocal != null) { + if (potentialLocal != null) { return potentialLocal; } - for(NamespaceStorageNode importedSource : importedNamespaces) { - V potential = importedSource.getFromLocalStorage(type, key); - if(potential != null) { + for (final NamespaceStorageNode importedSource : importedNamespaces) { + final V potential = importedSource.getFromLocalStorage(type, key); + if (potential != null) { return potential; } } return null; } + @Nullable @Override - public > NamespaceBehaviour getNamespaceBehaviour(Class type) { + public > Map getAllFromLocalStorage(final Class type) { + final Map potentialLocal = getRoot().getAllFromLocalStorage(type); + + if (potentialLocal != null) { + return potentialLocal; + } + + for (final NamespaceStorageNode importedSource : importedNamespaces) { + final Map potential = importedSource.getAllFromLocalStorage(type); + + if (potential != null) { + return potential; + } + } + return null; + } + + @Override + public > NamespaceBehaviour getNamespaceBehaviour( + final Class type) { return currentContext.getNamespaceBehaviour(type); } @@ -146,29 +237,44 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh return currentContext; } - PhaseCompletionProgress tryToCompletePhase(ModelProcessingPhase phase) throws SourceException { - Collection currentPhaseModifiers = modifiers.get(phase); - Iterator modifier = currentPhaseModifiers.iterator(); + PhaseCompletionProgress tryToCompletePhase(final ModelProcessingPhase phase) throws SourceException { + final Collection currentPhaseModifiers = modifiers.get(phase); + + boolean hasProgressed = tryToProgress(currentPhaseModifiers); + + Preconditions.checkNotNull(this.root, "Malformed source. Valid root element is missing."); + final boolean phaseCompleted = root.tryToCompletePhase(phase); + + hasProgressed |= tryToProgress(currentPhaseModifiers); + + if (phaseCompleted && currentPhaseModifiers.isEmpty()) { + finishedPhase = phase; + LOG.debug("Source {} finished phase {}", source, phase); + return PhaseCompletionProgress.FINISHED; + + } + + return hasProgressed ? PhaseCompletionProgress.PROGRESS : PhaseCompletionProgress.NO_PROGRESS; + } + + + private static boolean tryToProgress(final Collection currentPhaseModifiers) { boolean hasProgressed = false; - while(modifier.hasNext()) { - if(modifier.next().isApplied()) { + + final Iterator modifier = currentPhaseModifiers.iterator(); + while (modifier.hasNext()) { + if (modifier.next().tryApply()) { modifier.remove(); hasProgressed = true; } } - if(root.tryToCompletePhase(phase) && currentPhaseModifiers.isEmpty()) { - finishedPhase = phase; - return PhaseCompletionProgress.FINISHED; - } - if(hasProgressed) { - return PhaseCompletionProgress.PROGRESS; - } - return PhaseCompletionProgress.NO_PROGRESS; + return hasProgressed; + } - ModelActionBuilder newInferenceAction(ModelProcessingPhase phase) { - ModifierImpl action = new ModifierImpl(phase); + ModelActionBuilder newInferenceAction(final ModelProcessingPhase phase) { + final ModifierImpl action = new ModifierImpl(phase); modifiers.put(phase, action); return action; } @@ -179,43 +285,128 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh + finishedPhase + "]"; } - SourceException failModifiers(ModelProcessingPhase identifier) { - InferenceException sourceEx = new InferenceException("Fail to infer source relationships", root.getStatementSourceReference()); - - - for(ModifierImpl mod : modifiers.get(identifier)) { + Optional failModifiers(final ModelProcessingPhase identifier) { + final List exceptions = new ArrayList<>(); + for (final ModifierImpl mod : modifiers.get(identifier)) { try { mod.failModifier(); - } catch (SourceException e) { - sourceEx.addSuppressed(e); + } catch (final SourceException e) { + exceptions.add(e); } } - return sourceEx; + + if (exceptions.isEmpty()) { + 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()); + } + + return Optional.of(e); } void loadStatements() throws SourceException { + LOG.trace("Source {} loading statements for phase {}", source, inProgressPhase); + switch (inProgressPhase) { - case SourceLinkage: - source.writeLinkage(new StatementContextWriter(this, inProgressPhase),stmtDef()); - break; - case StatementDefinition: - source.writeLinkageAndStatementDefinitions(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes()); - case FullDeclaration: - source.writeFull(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes()); + case SOURCE_PRE_LINKAGE: + source.writePreLinkage(new StatementContextWriter(this, inProgressPhase), stmtDef()); + break; + case SOURCE_LINKAGE: + source.writeLinkage(new StatementContextWriter(this, inProgressPhase), stmtDef(), preLinkagePrefixes()); + break; + case STATEMENT_DEFINITION: + source.writeLinkageAndStatementDefinitions(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes()); + break; + case FULL_DECLARATION: + source.writeFull(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes()); + break; + default: + 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; + } + for (final Entry prefixToNamespace : prefixToNamespaceMap.entrySet()) { + preLinkagePrefixes.put(prefixToNamespace.getKey(), QNameModule.create(prefixToNamespace.getValue(), null)); + } + + return preLinkagePrefixes; + } + private PrefixToModule prefixes() { - // TODO Auto-generated method stub - return null; + final Map allPrefixes = getRoot().getAllFromNamespace(ImpPrefixToModuleIdentifier + .class); + final Map belongsToPrefixes = getRoot().getAllFromNamespace + (BelongsToPrefixToModuleIdentifier.class); + if (belongsToPrefixes != null) { + allPrefixes.putAll(belongsToPrefixes); + } + + for (final Entry stringModuleIdentifierEntry : allPrefixes.entrySet()) { + final QNameModule namespace = getRoot().getFromNamespace(ModuleIdentifierToModuleQName.class, + stringModuleIdentifierEntry.getValue()); + prefixToModuleMap.put(stringModuleIdentifierEntry.getKey(), namespace); + } + return prefixToModuleMap; } private QNameToStatementDefinition stmtDef() { - // TODO Auto-generated method stub - return null; - } + // regular YANG statements and extension supports added + final ImmutableMap> definitions = currentContext.getSupportsForPhase( + inProgressPhase).getDefinitions(); + for (final Entry> entry : definitions.entrySet()) { + qNameToStmtDefMap.put(entry.getKey(), entry.getValue()); + } + + // extensions added + if (inProgressPhase.equals(ModelProcessingPhase.FULL_DECLARATION)) { + final Map>> extensions = + currentContext.getAllFromNamespace(ExtensionNamespace.class); + if (extensions != null) { + for (final Entry>> extension : + extensions.entrySet()) { + if(qNameToStmtDefMap.get(extension.getKey()) == null) { + qNameToStmtDefMap.put((extension.getKey()), + (StatementDefinition) ((StatementContextBase) extension.getValue()).definition() + .getFactory()); + } + } + } + } + return qNameToStmtDefMap; + } }