Add AbstractMountPointContextFactory 20/83220/2
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 23 Jul 2019 23:58:44 +0000 (01:58 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 24 Jul 2019 08:44:46 +0000 (10:44 +0200)
This factory has model-specific information about RFC8528, so that
it is able to form an accurate view of mount points defined by inline
data.

Change-Id: I3350403c3fb3e1e074649536511eb7935f0ff6c9
JIRA: YANGTOOLS-1010
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/rfc8528-data-util/src/main/java/org/opendaylight/yangtools/rcf8528/data/util/AbstractDynamicMountPointContextFactory.java
yang/rfc8528-data-util/src/main/java/org/opendaylight/yangtools/rcf8528/data/util/AbstractMountPointContextFactory.java [new file with mode: 0644]
yang/rfc8528-data-util/src/main/java/org/opendaylight/yangtools/rcf8528/data/util/ImmutableMountPointContext.java [new file with mode: 0644]

index c0a64d2c5260ecd92e230beb443c11ae23ee1931..3d9e9920a80123446fef4b60b8d81610be6db11c 100644 (file)
@@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory;
  * Abstract base class for dynamic resolvers.
  */
 @Beta
+// FIXME: 4.0.0: consider integrating into AbstractMountPointContextFactory
 public abstract class AbstractDynamicMountPointContextFactory extends AbstractIdentifiable<MountPointIdentifier>
         implements MountPointContextFactory {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractDynamicMountPointContextFactory.class);
diff --git a/yang/rfc8528-data-util/src/main/java/org/opendaylight/yangtools/rcf8528/data/util/AbstractMountPointContextFactory.java b/yang/rfc8528-data-util/src/main/java/org/opendaylight/yangtools/rcf8528/data/util/AbstractMountPointContextFactory.java
new file mode 100644 (file)
index 0000000..9009eb8
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.rcf8528.data.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableSet;
+import java.util.Iterator;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.yangtools.concepts.AbstractIdentifiable;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
+import org.opendaylight.yangtools.rfc8528.data.api.MountPointContextFactory;
+import org.opendaylight.yangtools.rfc8528.data.api.MountPointIdentifier;
+import org.opendaylight.yangtools.rfc8528.model.api.SchemaMountConstants;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract base class for MountPointContextFactory implementations, which can process RFC8525 mount point definitions.
+ */
+@Beta
+@NonNullByDefault
+public abstract class AbstractMountPointContextFactory extends AbstractDynamicMountPointContextFactory {
+    /**
+     * Definition of a MountPoint, as known to RFC8528.
+     */
+    protected static final class MountPointDefinition extends AbstractIdentifiable<MountPointIdentifier>
+            implements Immutable {
+        private final ImmutableSet<String> parentReferences;
+        private final boolean config;
+
+        MountPointDefinition(final MountPointIdentifier identifier, final boolean config,
+                final ImmutableSet<String> parentReferences) {
+            super(identifier);
+            this.config = config;
+            this.parentReferences = requireNonNull(parentReferences);
+        }
+
+        public boolean getConfig() {
+            return config;
+        }
+
+        // FIXME: 4.0.0: make this return a set of XPath expressions
+        public ImmutableSet<String> getParentReferences() {
+            return parentReferences;
+        }
+
+        @Override
+        protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
+            return super.addToStringAttributes(toStringHelper)
+                    .add("config", config)
+                    .add("parentReferences", parentReferences);
+        }
+    }
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractMountPointContextFactory.class);
+    private static final NodeIdentifier SCHEMA_MOUNTS = NodeIdentifier.create(
+        QName.create(SchemaMountConstants.RFC8528_MODULE, "schema-mounts").intern());
+    private static final NodeIdentifier MOUNT_POINT = NodeIdentifier.create(
+        QName.create(SchemaMountConstants.RFC8528_MODULE, "mount-point").intern());
+    private static final NodeIdentifier CONFIG = NodeIdentifier.create(
+        QName.create(SchemaMountConstants.RFC8528_MODULE, "config").intern());
+    private static final NodeIdentifier MODULE = NodeIdentifier.create(
+        QName.create(SchemaMountConstants.RFC8528_MODULE, "module").intern());
+    private static final NodeIdentifier LABEL = NodeIdentifier.create(
+        QName.create(SchemaMountConstants.RFC8528_MODULE, "label").intern());
+    private static final NodeIdentifier INLINE = NodeIdentifier.create(
+        QName.create(SchemaMountConstants.RFC8528_MODULE, "inline").intern());
+    private static final NodeIdentifier SHARED_SCHEMA = NodeIdentifier.create(
+        QName.create(SchemaMountConstants.RFC8528_MODULE, "shared-schema").intern());
+    private static final NodeIdentifier PARENT_REFERENCE = NodeIdentifier.create(
+        QName.create(SchemaMountConstants.RFC8528_MODULE, "parent-reference").intern());
+
+    protected AbstractMountPointContextFactory(final MountPointIdentifier mountId) {
+        super(mountId);
+    }
+
+    @Override
+    protected final MountPointContext createMountPointContext(final SchemaContext schemaContext,
+            final ContainerNode mountData) {
+        checkArgument(SCHEMA_MOUNTS.equals(mountData.getIdentifier()), "Unexpected top-level container %s", mountData);
+
+        final Optional<DataContainerChild<?, ?>> optMountPoint = mountData.getChild(MOUNT_POINT);
+        if (!optMountPoint.isPresent()) {
+            LOG.debug("mount-point list not present in {}", mountData);
+            return new EmptyMountPointContext(schemaContext);
+        }
+
+        final DataContainerChild<?, ?> mountPoint = optMountPoint.get();
+        checkArgument(mountPoint instanceof MapNode, "mount-point list %s is not a MapNode", mountPoint);
+
+        return new ImmutableMountPointContext(schemaContext, ((MapNode) mountPoint).getValue().stream().map(entry -> {
+            final String moduleName = entry.getChild(MODULE).map(mod -> {
+                checkArgument(mod instanceof LeafNode, "Unexpected module leaf %s", mod);
+                final Object value = mod.getValue();
+                checkArgument(value instanceof String, "Unexpected module leaf value %s", value);
+                return (String) value;
+            }).orElseThrow(() -> new IllegalArgumentException("Mount module missing in " + entry));
+            final Iterator<Module> it = schemaContext.findModules(moduleName).iterator();
+            checkArgument(it.hasNext(), "Failed to find a module named %s", moduleName);
+            final QNameModule module = it.next().getQNameModule();
+
+            return new MountPointDefinition(
+                MountPointIdentifier.of(QName.create(module, entry.getChild(LABEL).map(lbl -> {
+                    checkArgument(lbl instanceof LeafNode, "Unexpected label leaf %s", lbl);
+                    final Object value = lbl.getValue();
+                    checkArgument(value instanceof String, "Unexpected label leaf value %s", value);
+                    return (String) value;
+                }).orElseThrow(() -> new IllegalArgumentException("Mount module missing in " + entry)))),
+                entry.getChild(CONFIG).map(cfg -> {
+                    checkArgument(cfg instanceof LeafNode, "Unexpected config leaf %s", cfg);
+                    final Object value = cfg.getValue();
+                    checkArgument(value instanceof Boolean, "Unexpected config leaf value %s", cfg);
+                    return (Boolean) value;
+                }).orElse(Boolean.TRUE),
+                entry.getChild(SHARED_SCHEMA).map(sharedSchema -> {
+                    checkArgument(sharedSchema instanceof ContainerNode, "Unexpected shared-schema container %s",
+                        sharedSchema);
+                    return ((ContainerNode) sharedSchema).getChild(PARENT_REFERENCE).map(parentRef -> {
+                        // FIXME: decode
+                        return ImmutableSet.<String>of();
+                    }).orElseGet(ImmutableSet::of);
+                }).orElseGet(() -> {
+                    checkArgument(entry.getChild(INLINE).isPresent(), "Unhandled schema-ref type in %s", entry);
+                    return ImmutableSet.of();
+                }));
+        }).collect(Collectors.toList()), this::createContextFactory);
+    }
+
+    /**
+     * Create a fresh {@link MountPointContextFactory} for a nested {@link MountPointDefinition}.
+     *
+     * @param mountPoint Mount point definition
+     * @return A new factory, dealing with mount points nested within the mount point.
+     */
+    protected abstract MountPointContextFactory createContextFactory(MountPointDefinition mountPoint);
+}
diff --git a/yang/rfc8528-data-util/src/main/java/org/opendaylight/yangtools/rcf8528/data/util/ImmutableMountPointContext.java b/yang/rfc8528-data-util/src/main/java/org/opendaylight/yangtools/rcf8528/data/util/ImmutableMountPointContext.java
new file mode 100644 (file)
index 0000000..c996e5e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 PANTHEON.tech s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.rcf8528.data.util;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import java.util.Optional;
+import java.util.function.Function;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.rcf8528.data.util.AbstractMountPointContextFactory.MountPointDefinition;
+import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
+import org.opendaylight.yangtools.rfc8528.data.api.MountPointContextFactory;
+import org.opendaylight.yangtools.rfc8528.data.api.MountPointIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.util.AbstractSchemaContextProvider;
+
+final class ImmutableMountPointContext extends AbstractSchemaContextProvider implements Immutable, MountPointContext {
+    private final ImmutableMap<MountPointIdentifier, MountPointDefinition> mountPoints;
+    private final Function<MountPointDefinition, MountPointContextFactory> createFactory;
+
+    ImmutableMountPointContext(final SchemaContext schemaContext, final Iterable<MountPointDefinition> mountPoints,
+            final Function<MountPointDefinition, MountPointContextFactory> createFactory) {
+        super(schemaContext);
+        this.mountPoints = Maps.uniqueIndex(mountPoints, MountPointDefinition::getIdentifier);
+        this.createFactory = requireNonNull(createFactory);
+    }
+
+    @Override
+    public Optional<MountPointContextFactory> findMountPoint(final MountPointIdentifier label) {
+        final MountPointDefinition def = mountPoints.get(requireNonNull(label));
+        return def == null ? Optional.empty() : Optional.of(createFactory.apply(def));
+    }
+
+    @Override
+    protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+        return super.addToStringAttributes(helper).add("mountPoints", mountPoints);
+    }
+}