Expose EffectiveModuleStatement prefix mapping 91/67891/8
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 3 Feb 2018 12:35:24 +0000 (13:35 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 5 Feb 2018 00:00:11 +0000 (01:00 +0100)
ModuleEffectiveStatement should expose mapping of prefixes
to imported modules (and self) as well as reverse mapping of
QNameModule to prefix, so that users can map properly map
QNames encountered within a module.

This patch exposes that information via two new namespaces,
which are present only in ModuleEffectiveStatements. Furthermore
EffectiveStatementBase is updated to allow subclasses to contain
namespaces.

JIRA: MDSAL-301
Change-Id: I5139c32eff18c1fa703dd8d3c98882939f82b109
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/meta/EffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/meta/IdentifierNamespace.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/ModuleEffectiveStatement.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStatementBase.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/module/ModuleEffectiveStatementImpl.java

index 4815715f7b93f8e05371a4996f23f20c1e7e1812..2c4ff1d3fbdcd6d7f8dd49c21d96a12b7d7fffa8 100644 (file)
@@ -7,13 +7,17 @@
  */
 package org.opendaylight.yangtools.yang.model.api.meta;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableMap;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Stream;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import org.eclipse.jdt.annotation.NonNull;
 
 /**
  * Effective model statement which should be used to derive application behaviour.
@@ -58,19 +62,29 @@ public interface EffectiveStatement<A, S extends DeclaredStatement<A>> extends M
     /**
      * Returns all local values from supplied namespace.
      *
-     * @param <K>
-     *            Identifier type
-     * @param <V>
-     *            Value type
-     * @param <N>
-     *            Namespace identifier type
-     * @param namespace
-     *            Namespace type
+     * @param <K> Identifier type
+     * @param <V> Value type
+     * @param <N> Namespace identifier type
+     * @param namespace Namespace type
      * @return Value if present, null otherwise.
      */
     @Nullable
     <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAll(@Nonnull Class<N> namespace);
 
+    /**
+     * Returns all local values from supplied namespace.
+     *
+     * @param <K> Identifier type
+     * @param <V> Value type
+     * @param <N> Namespace identifier type
+     * @param namespace Namespace type
+     * @return Key-value mappings, empty if the namespace does not exist.
+     */
+    default <K, V, N extends IdentifierNamespace<K, V>> @NonNull Map<K, V> findAll(@NonNull final Class<N> namespace) {
+        final Map<K, V> map = getAll(requireNonNull(namespace));
+        return map == null ? ImmutableMap.of() : map;
+    }
+
     /**
      * Returns a collection of all effective substatements.
      *
index f06850b27b0d55c05e6f178021a46e747634b95c..c6179847629a6ffe07b20b18ba0b57674c689583 100644 (file)
@@ -13,17 +13,15 @@ import javax.annotation.Nullable;
 /**
  * Model specific namespace which allows access to specific
  *
- * {@link IdentifierNamespace} serves as common superclass for YANG model
- * namespaces, which are type-captured subclasses. This type capture
- * of namespace allows for handy type-safe reading methods
- * such as {@link EffectiveStatement#get(Class, Object)} and still
- * allows introduction of new namespaces without need to change
+ * {@link IdentifierNamespace} serves as common superclass for YANG model namespaces, which are type-captured
+ * subclasses. This type capture of namespace allows for handy type-safe reading methods such as
+ * {@link EffectiveStatement#get(Class, Object)} and still allows introduction of new namespaces without need to change
  * model APIs.
  *
  * @param <K> Identifier type
  * @param <V> Value type
  */
-public interface IdentifierNamespace<K,V> {
+public interface IdentifierNamespace<K, V> {
     /**
      * Returns value associated with supplied identifier.
      *
index 068f3e7b28896cae5bd3eae0063c1592bda24343..2feac3d08fb0698b82c9dee0ea5dc241baa5f4f5 100644 (file)
@@ -8,9 +8,40 @@
 package org.opendaylight.yangtools.yang.model.api.stmt;
 
 import com.google.common.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
 
 @Beta
 public interface ModuleEffectiveStatement extends EffectiveStatement<String, ModuleStatement> {
+    /**
+     * Namespace mapping all known prefixes in a module to their modules. Note this namespace includes the module
+     * in which it is instantiated.
+     */
+    abstract class PrefixToEffectiveModuleNamespace implements IdentifierNamespace<String, ModuleEffectiveStatement> {
+        private PrefixToEffectiveModuleNamespace() {
+            // This class should never be subclassed
+        }
+    }
 
+    /**
+     * Namespace mapping all known {@link QNameModule}s to their encoding prefixes. This includes the declaration
+     * from prefix/namespace/revision and all imports as they were resolved.
+     */
+    abstract class QNameModuleToPrefixNamespace implements IdentifierNamespace<QNameModule, String> {
+        private QNameModuleToPrefixNamespace() {
+            // This class should never be subclassed
+        }
+    }
+
+    /**
+     * Get the local QNameModule of this module. All implementations need to override this default method.
+     *
+     * @return Local QNameModule
+     */
+    // FIXME: 3.0.0 make this method non-default
+    default @NonNull QNameModule localQNameModule() {
+        throw new UnsupportedOperationException(getClass() + " is missing an implementation");
+    }
 }
index 3392b33a3f75a48637ff030d590505f61ae4f5df..1f4fa40c3da46fc96aa72085a616a0fd24e3341f 100644 (file)
@@ -7,15 +7,20 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
 
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.function.Predicate;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
@@ -70,12 +75,24 @@ public abstract class EffectiveStatementBase<A, D extends DeclaredStatement<A>>
     @Override
     public final <K, V, N extends IdentifierNamespace<K, V>> V get(@Nonnull final Class<N> namespace,
             @Nonnull final K identifier) {
-        throw new UnsupportedOperationException("Not implemented yet.");
+        return findAll(namespace).get(requireNonNull(identifier));
     }
 
     @Override
     public final <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAll(@Nonnull final Class<N> namespace) {
-        throw new UnsupportedOperationException("Not implemented yet.");
+        return getNamespaceContents(requireNonNull(namespace)).orElse(null);
+    }
+
+    /**
+     * Return the statement-specific contents of specified namespace, if available.
+     *
+     * @param namespace Requested namespace
+     * @return Namespace contents, if available.
+     */
+    @Beta
+    protected <K, V, N extends IdentifierNamespace<K, V>> Optional<? extends Map<K, V>> getNamespaceContents(
+            final @NonNull Class<N> namespace) {
+        return Optional.empty();
     }
 
     @Nonnull
index 1059e7544087e1cdb961eb9b5222687a6c3af0a0..a0f0101fb3f02c06c5f13d993821cc4248a87a8e 100644 (file)
@@ -7,31 +7,84 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.module;
 
-import com.google.common.base.Verify;
+import static com.google.common.base.Verify.verifyNotNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Maps;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 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.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.rfc7950.stmt.AbstractEffectiveModule;
 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.ModuleCtxToModuleQName;
 
 final class ModuleEffectiveStatementImpl extends AbstractEffectiveModule<ModuleStatement>
         implements ModuleEffectiveStatement {
-    private final QNameModule qnameModule;
+    private final Map<String, ModuleEffectiveStatement> prefixToModule;
+    private final Map<QNameModule, String> namespaceToPrefix;
+    private final @NonNull QNameModule qnameModule;
 
     ModuleEffectiveStatementImpl(
             final StmtContext<String, ModuleStatement, EffectiveStatement<String, ModuleStatement>> ctx) {
         super(ctx);
-        qnameModule = Verify.verifyNotNull(ctx.getFromNamespace(ModuleCtxToModuleQName.class, ctx));
+        qnameModule = verifyNotNull(ctx.getFromNamespace(ModuleCtxToModuleQName.class, ctx));
+
+        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());
+                });
+        prefixToModule = prefixToModuleBuilder.build();
+
+        final Map<QNameModule, String> tmp = Maps.newLinkedHashMapWithExpectedSize(prefixToModule.size() + 1);
+        tmp.put(qnameModule, localPrefix);
+        for (Entry<String, ModuleEffectiveStatement> e : prefixToModule.entrySet()) {
+            tmp.putIfAbsent(e.getValue().localQNameModule(), e.getKey());
+        }
+        namespaceToPrefix = ImmutableMap.copyOf(tmp);
     }
 
     @Override
-    public QNameModule getQNameModule() {
+    public @NonNull QNameModule localQNameModule() {
         return qnameModule;
     }
 
+    @Override
+    public @NonNull QNameModule getQNameModule() {
+        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 int hashCode() {
         final int prime = 31;
@@ -62,5 +115,4 @@ final class ModuleEffectiveStatementImpl extends AbstractEffectiveModule<ModuleS
         }
         return true;
     }
-
 }