2 * Copyright (c) 2019 PANTHEON.tech s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.rfc8528.data.util;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import com.google.common.base.MoreObjects.ToStringHelper;
15 import com.google.common.collect.ImmutableSet;
16 import java.util.Iterator;
17 import java.util.stream.Collectors;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.opendaylight.yangtools.concepts.AbstractSimpleIdentifiable;
20 import org.opendaylight.yangtools.concepts.Immutable;
21 import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
22 import org.opendaylight.yangtools.rfc8528.data.api.MountPointContextFactory;
23 import org.opendaylight.yangtools.rfc8528.data.api.MountPointIdentifier;
24 import org.opendaylight.yangtools.rfc8528.model.api.SchemaMountConstants;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.common.QNameModule;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
31 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
33 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
34 import org.opendaylight.yangtools.yang.model.api.Module;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * Abstract base class for MountPointContextFactory implementations, which can process RFC8525 mount point definitions.
43 public abstract class AbstractMountPointContextFactory extends AbstractDynamicMountPointContextFactory {
45 * Definition of a MountPoint, as known to RFC8528.
47 protected static final class MountPointDefinition extends AbstractSimpleIdentifiable<MountPointIdentifier>
48 implements Immutable {
49 private final ImmutableSet<String> parentReferences;
50 private final boolean config;
52 MountPointDefinition(final MountPointIdentifier identifier, final boolean config,
53 final ImmutableSet<String> parentReferences) {
56 this.parentReferences = requireNonNull(parentReferences);
59 public boolean getConfig() {
63 // FIXME: 7.0.0: make this return a set of XPath expressions
64 public ImmutableSet<String> getParentReferences() {
65 return parentReferences;
69 protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
70 return super.addToStringAttributes(toStringHelper)
71 .add("config", config)
72 .add("parentReferences", parentReferences);
76 private static final Logger LOG = LoggerFactory.getLogger(AbstractMountPointContextFactory.class);
77 private static final NodeIdentifier SCHEMA_MOUNTS = NodeIdentifier.create(
78 QName.create(SchemaMountConstants.RFC8528_MODULE, "schema-mounts").intern());
79 private static final NodeIdentifier MOUNT_POINT = NodeIdentifier.create(
80 QName.create(SchemaMountConstants.RFC8528_MODULE, "mount-point").intern());
81 private static final NodeIdentifier CONFIG = NodeIdentifier.create(
82 QName.create(SchemaMountConstants.RFC8528_MODULE, "config").intern());
83 private static final NodeIdentifier MODULE = NodeIdentifier.create(
84 QName.create(SchemaMountConstants.RFC8528_MODULE, "module").intern());
85 private static final NodeIdentifier LABEL = NodeIdentifier.create(
86 QName.create(SchemaMountConstants.RFC8528_MODULE, "label").intern());
87 private static final NodeIdentifier SCHEMA_REF = NodeIdentifier.create(
88 QName.create(SchemaMountConstants.RFC8528_MODULE, "schema-ref").intern());
89 private static final NodeIdentifier INLINE = NodeIdentifier.create(
90 QName.create(SchemaMountConstants.RFC8528_MODULE, "inline").intern());
91 private static final NodeIdentifier SHARED_SCHEMA = NodeIdentifier.create(
92 QName.create(SchemaMountConstants.RFC8528_MODULE, "shared-schema").intern());
93 private static final NodeIdentifier PARENT_REFERENCE = NodeIdentifier.create(
94 QName.create(SchemaMountConstants.RFC8528_MODULE, "parent-reference").intern());
96 protected AbstractMountPointContextFactory(final MountPointIdentifier mountId) {
101 protected final MountPointContext createMountPointContext(final EffectiveModelContext schemaContext,
102 final ContainerNode mountData) {
103 checkArgument(SCHEMA_MOUNTS.equals(mountData.getIdentifier()), "Unexpected top-level container %s", mountData);
105 final DataContainerChild mountPoint = mountData.childByArg(MOUNT_POINT);
106 if (mountPoint == null) {
107 LOG.debug("mount-point list not present in {}", mountData);
108 return new EmptyMountPointContext(schemaContext);
110 checkArgument(mountPoint instanceof MapNode, "mount-point list %s is not a MapNode", mountPoint);
112 return new ImmutableMountPointContext(schemaContext, ((MapNode) mountPoint).body().stream().map(entry -> {
113 final String moduleName = entry.findChildByArg(MODULE).map(mod -> {
114 checkArgument(mod instanceof LeafNode, "Unexpected module leaf %s", mod);
115 final Object value = mod.body();
116 checkArgument(value instanceof String, "Unexpected module leaf value %s", value);
117 return (String) value;
118 }).orElseThrow(() -> new IllegalArgumentException("Mount module missing in " + entry));
119 final Iterator<? extends Module> it = schemaContext.findModules(moduleName).iterator();
120 checkArgument(it.hasNext(), "Failed to find a module named %s", moduleName);
121 final QNameModule module = it.next().getQNameModule();
123 return new MountPointDefinition(
124 MountPointIdentifier.of(QName.create(module, entry.findChildByArg(LABEL).map(lbl -> {
125 checkArgument(lbl instanceof LeafNode, "Unexpected label leaf %s", lbl);
126 final Object value = lbl.body();
127 checkArgument(value instanceof String, "Unexpected label leaf value %s", value);
128 return (String) value;
129 }).orElseThrow(() -> new IllegalArgumentException("Mount module missing in " + entry)))),
130 entry.findChildByArg(CONFIG).map(cfg -> {
131 checkArgument(cfg instanceof LeafNode, "Unexpected config leaf %s", cfg);
132 final Object value = cfg.body();
133 checkArgument(value instanceof Boolean, "Unexpected config leaf value %s", cfg);
134 return (Boolean) value;
135 }).orElse(Boolean.TRUE),
136 getSchema(entry.findChildByArg(SCHEMA_REF)
137 .orElseThrow(() -> new IllegalArgumentException("Missing schema-ref choice in " + entry))));
138 }).collect(Collectors.toList()), this::createContextFactory);
141 private static ImmutableSet<String> getSchema(final DataContainerChild child) {
142 checkArgument(child instanceof ChoiceNode, "Unexpected schema-ref choice %s", child);
143 final ChoiceNode schemaRef = (ChoiceNode) child;
145 return schemaRef.findChildByArg(SHARED_SCHEMA).map(sharedSchema -> {
146 checkArgument(sharedSchema instanceof ContainerNode, "Unexpected shared-schema container %s", sharedSchema);
147 return ((ContainerNode) sharedSchema).findChildByArg(PARENT_REFERENCE)
148 // FIXME: 7.0.0: parse XPaths. Do we have enough context for that?
149 .map(parentRef -> ImmutableSet.<String>of())
150 .orElseGet(ImmutableSet::of);
152 checkArgument(schemaRef.findChildByArg(INLINE).isPresent(), "Unhandled schema-ref type in %s", schemaRef);
153 return ImmutableSet.of();
158 * Create a fresh {@link MountPointContextFactory} for a nested {@link MountPointDefinition}.
160 * @param mountPoint Mount point definition
161 * @return A new factory, dealing with mount points nested within the mount point.
163 protected abstract MountPointContextFactory createContextFactory(MountPointDefinition mountPoint);