X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=restconf%2Frestconf-nb-bierman02%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetconf%2Fsal%2Frestconf%2Fimpl%2FControllerContext.java;h=cc01ef9fe477410590be4a659429d6fdb701237e;hb=9cc114dc8e4109893e2346477b5ae14391afe01c;hp=80dabef6a7950790b186a9cd88bd57dcbc8dc76f;hpb=edf3b06cb4e53a91f3756663dfbea9a1eb9154d1;p=netconf.git diff --git a/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/ControllerContext.java b/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/ControllerContext.java index 80dabef6a7..cc01ef9fe4 100644 --- a/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/ControllerContext.java +++ b/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/ControllerContext.java @@ -7,8 +7,10 @@ */ package org.opendaylight.netconf.sal.restconf.impl; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; + import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; @@ -16,10 +18,8 @@ import com.google.common.collect.Iterables; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.Closeable; import java.io.UnsupportedEncodingException; -import java.net.URI; import java.net.URLDecoder; import java.net.URLEncoder; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -29,55 +29,57 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import javax.inject.Singleton; import javax.ws.rs.core.Response.Status; -import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException; -import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation; -import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; -import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; -import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; +import org.opendaylight.mdsal.dom.api.DOMMountPoint; +import org.opendaylight.mdsal.dom.api.DOMMountPointService; import org.opendaylight.mdsal.dom.api.DOMSchemaService; import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider; import org.opendaylight.netconf.sal.rest.api.Draft02; import org.opendaylight.netconf.sal.rest.api.Draft02.RestConfModule; import org.opendaylight.restconf.common.context.InstanceIdentifierContext; import org.opendaylight.restconf.common.errors.RestconfDocumentedException; -import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag; -import org.opendaylight.restconf.common.errors.RestconfError.ErrorType; import org.opendaylight.restconf.common.util.RestUtil; -import org.opendaylight.yangtools.concepts.Codec; +import org.opendaylight.yangtools.concepts.IllegalArgumentCodec; import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.common.ErrorTag; +import org.opendaylight.yangtools.yang.common.ErrorType; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.common.XMLNamespace; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode; +import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode; import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode; import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextListener; import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition; -import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil; +import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public final class ControllerContext implements SchemaContextListener, Closeable { +@Singleton +public final class ControllerContext implements EffectiveModelContextListener, Closeable { // FIXME: this should be in md-sal somewhere public static final String MOUNT = "yang-ext:mount"; @@ -89,38 +91,42 @@ public final class ControllerContext implements SchemaContextListener, Closeable private static final String MOUNT_NODE = "mount"; - private static final Charset URI_ENCODING_CHARSET = StandardCharsets.UTF_8; - private static final Splitter SLASH_SPLITTER = Splitter.on('/'); private final AtomicReference> qnameToRpc = new AtomicReference<>(Collections.emptyMap()); private final DOMMountPointService mountService; private final DOMYangTextSourceProvider yangTextSourceProvider; - private final ListenerRegistration listenerRegistration; - private volatile SchemaContext globalSchema; + private final ListenerRegistration listenerRegistration; + private volatile EffectiveModelContext globalSchema; private volatile DataNormalizer dataNormalizer; - private ControllerContext(DOMSchemaService schemaService, DOMMountPointService mountService, - DOMYangTextSourceProvider yangTextSourceProvider) { + @Inject + public ControllerContext(final DOMSchemaService schemaService, final DOMMountPointService mountService, + final DOMSchemaService domSchemaService) { this.mountService = mountService; - this.yangTextSourceProvider = yangTextSourceProvider; + yangTextSourceProvider = domSchemaService.getExtensions().getInstance(DOMYangTextSourceProvider.class); - onGlobalContextUpdated(schemaService.getGlobalContext()); + onModelContextUpdated(schemaService.getGlobalContext()); listenerRegistration = schemaService.registerSchemaContextListener(this); } - public static ControllerContext newInstance(DOMSchemaService schemaService, DOMMountPointService mountService, - DOMSchemaService domSchemaService) { - final DOMYangTextSourceProvider yangTextSourceProvider = - (DOMYangTextSourceProvider) domSchemaService.getSupportedExtensions().get(DOMYangTextSourceProvider.class); - - return new ControllerContext(schemaService, mountService, yangTextSourceProvider); + /** + * Factory method. + * + * @deprecated Just use the + * {@link #ControllerContext(DOMSchemaService, DOMMountPointService, DOMSchemaService)} + * constructor instead. + */ + @Deprecated + public static ControllerContext newInstance(final DOMSchemaService schemaService, + final DOMMountPointService mountService, final DOMSchemaService domSchemaService) { + return new ControllerContext(schemaService, mountService, domSchemaService); } - private void setGlobalSchema(final SchemaContext globalSchema) { + private void setGlobalSchema(final EffectiveModelContext globalSchema) { this.globalSchema = globalSchema; - this.dataNormalizer = new DataNormalizer(globalSchema); + dataNormalizer = new DataNormalizer(globalSchema); } public DOMYangTextSourceProvider getYangTextSourceProvider() { @@ -128,39 +134,39 @@ public final class ControllerContext implements SchemaContextListener, Closeable } private void checkPreconditions() { - if (this.globalSchema == null) { + if (globalSchema == null) { throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE); } } @Override + @PreDestroy public void close() { listenerRegistration.close(); } - public void setSchemas(final SchemaContext schemas) { - onGlobalContextUpdated(schemas); + public void setSchemas(final EffectiveModelContext schemas) { + onModelContextUpdated(schemas); } - public InstanceIdentifierContext toInstanceIdentifier(final String restconfInstance) { + public InstanceIdentifierContext toInstanceIdentifier(final String restconfInstance) { return toIdentifier(restconfInstance, false); } - public SchemaContext getGlobalSchema() { - return this.globalSchema; + public EffectiveModelContext getGlobalSchema() { + return globalSchema; } - public InstanceIdentifierContext toMountPointIdentifier(final String restconfInstance) { + public InstanceIdentifierContext toMountPointIdentifier(final String restconfInstance) { return toIdentifier(restconfInstance, true); } - private InstanceIdentifierContext toIdentifier(final String restconfInstance, - final boolean toMountPointIdentifier) { + private InstanceIdentifierContext toIdentifier(final String restconfInstance, + final boolean toMountPointIdentifier) { checkPreconditions(); if (restconfInstance == null) { - return new InstanceIdentifierContext<>(YangInstanceIdentifier.EMPTY, this.globalSchema, null, - this.globalSchema); + return new InstanceIdentifierContext(YangInstanceIdentifier.empty(), globalSchema, null, globalSchema); } final List pathArgs = urlPathArgsDecode(SLASH_SPLITTER.split(restconfInstance)); @@ -177,14 +183,14 @@ public final class ControllerContext implements SchemaContextListener, Closeable } final InstanceIdentifierBuilder builder = YangInstanceIdentifier.builder(); - final Set latestModule = this.globalSchema.findModules(startModule); + final Collection latestModule = globalSchema.findModules(startModule); if (latestModule.isEmpty()) { throw new RestconfDocumentedException("The module named '" + startModule + "' does not exist.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); } - final InstanceIdentifierContext iiWithSchemaNode = + final InstanceIdentifierContext iiWithSchemaNode = collectPathArguments(builder, pathArgs, latestModule.iterator().next(), null, toMountPointIdentifier); if (iiWithSchemaNode == null) { @@ -218,51 +224,45 @@ public final class ControllerContext implements SchemaContextListener, Closeable public Module findModuleByName(final String moduleName) { checkPreconditions(); - Preconditions.checkArgument(moduleName != null && !moduleName.isEmpty()); - return this.globalSchema.findModules(moduleName).stream().findFirst().orElse(null); + checkArgument(moduleName != null && !moduleName.isEmpty()); + return globalSchema.findModules(moduleName).stream().findFirst().orElse(null); } - public Module findModuleByName(final DOMMountPoint mountPoint, final String moduleName) { - Preconditions.checkArgument(moduleName != null && mountPoint != null); - - final SchemaContext mountPointSchema = mountPoint.getSchemaContext(); - if (mountPointSchema == null) { - return null; - } + public static Module findModuleByName(final DOMMountPoint mountPoint, final String moduleName) { + checkArgument(moduleName != null && mountPoint != null); - return mountPointSchema.findModules(moduleName).stream().findFirst().orElse(null); + final EffectiveModelContext mountPointSchema = getModelContext(mountPoint); + return mountPointSchema == null ? null + : mountPointSchema.findModules(moduleName).stream().findFirst().orElse(null); } - public Module findModuleByNamespace(final URI namespace) { + public Module findModuleByNamespace(final XMLNamespace namespace) { checkPreconditions(); - Preconditions.checkArgument(namespace != null); - return this.globalSchema.findModules(namespace).stream().findFirst().orElse(null); + checkArgument(namespace != null); + return globalSchema.findModules(namespace).stream().findFirst().orElse(null); } - public Module findModuleByNamespace(final DOMMountPoint mountPoint, final URI namespace) { - Preconditions.checkArgument(namespace != null && mountPoint != null); + public static Module findModuleByNamespace(final DOMMountPoint mountPoint, final XMLNamespace namespace) { + checkArgument(namespace != null && mountPoint != null); - final SchemaContext mountPointSchema = mountPoint.getSchemaContext(); - if (mountPointSchema == null) { - return null; - } - - return mountPointSchema.findModules(namespace).stream().findFirst().orElse(null); + final EffectiveModelContext mountPointSchema = getModelContext(mountPoint); + return mountPointSchema == null ? null + : mountPointSchema.findModules(namespace).stream().findFirst().orElse(null); } public Module findModuleByNameAndRevision(final String name, final Revision revision) { checkPreconditions(); - Preconditions.checkArgument(name != null && revision != null); + checkArgument(name != null && revision != null); - return this.globalSchema.findModule(name, revision).orElse(null); + return globalSchema.findModule(name, revision).orElse(null); } public Module findModuleByNameAndRevision(final DOMMountPoint mountPoint, final String name, final Revision revision) { checkPreconditions(); - Preconditions.checkArgument(name != null && revision != null && mountPoint != null); + checkArgument(name != null && revision != null && mountPoint != null); - final SchemaContext schemaContext = mountPoint.getSchemaContext(); + final EffectiveModelContext schemaContext = getModelContext(mountPoint); return schemaContext == null ? null : schemaContext.findModule(name, revision).orElse(null); } @@ -272,7 +272,7 @@ public final class ControllerContext implements SchemaContextListener, Closeable final Iterable elements = path.getPathArguments(); final PathArgument head = elements.iterator().next(); final QName startQName = head.getNodeType(); - final Module initialModule = this.globalSchema.findModule(startQName.getModule()).orElse(null); + final Module initialModule = globalSchema.findModule(startQName.getModule()).orElse(null); DataNodeContainer node = initialModule; for (final PathArgument element : elements) { final QName _nodeType = element.getNodeType(); @@ -293,11 +293,11 @@ public final class ControllerContext implements SchemaContextListener, Closeable final StringBuilder builder = new StringBuilder(); final PathArgument head = elements.iterator().next(); final QName startQName = head.getNodeType(); - final SchemaContext schemaContext; + final EffectiveModelContext schemaContext; if (mount != null) { - schemaContext = mount.getSchemaContext(); + schemaContext = getModelContext(mount); } else { - schemaContext = this.globalSchema; + schemaContext = globalSchema; } final Module initialModule = schemaContext.findModule(startQName.getModule()).orElse(null); DataNodeContainer node = initialModule; @@ -305,7 +305,7 @@ public final class ControllerContext implements SchemaContextListener, Closeable if (!(element instanceof AugmentationIdentifier)) { final QName _nodeType = element.getNodeType(); final DataSchemaNode potentialNode = childByQName(node, _nodeType); - if (!(element instanceof NodeIdentifier && potentialNode instanceof ListSchemaNode) + if ((!(element instanceof NodeIdentifier) || !(potentialNode instanceof ListSchemaNode)) && !(potentialNode instanceof ChoiceSchemaNode)) { builder.append(convertToRestconfIdentifier(element, potentialNode, mount)); if (potentialNode instanceof DataNodeContainer) { @@ -318,69 +318,58 @@ public final class ControllerContext implements SchemaContextListener, Closeable return builder.toString(); } - public String findModuleNameByNamespace(final URI namespace) { + public String findModuleNameByNamespace(final XMLNamespace namespace) { checkPreconditions(); final Module module = this.findModuleByNamespace(namespace); return module == null ? null : module.getName(); } - public String findModuleNameByNamespace(final DOMMountPoint mountPoint, final URI namespace) { - final Module module = this.findModuleByNamespace(mountPoint, namespace); + public static String findModuleNameByNamespace(final DOMMountPoint mountPoint, final XMLNamespace namespace) { + final Module module = findModuleByNamespace(mountPoint, namespace); return module == null ? null : module.getName(); } - public URI findNamespaceByModuleName(final String moduleName) { + public XMLNamespace findNamespaceByModuleName(final String moduleName) { final Module module = this.findModuleByName(moduleName); return module == null ? null : module.getNamespace(); } - public URI findNamespaceByModuleName(final DOMMountPoint mountPoint, final String moduleName) { - final Module module = this.findModuleByName(mountPoint, moduleName); + public static XMLNamespace findNamespaceByModuleName(final DOMMountPoint mountPoint, final String moduleName) { + final Module module = findModuleByName(mountPoint, moduleName); return module == null ? null : module.getNamespace(); } - public Set getAllModules(final DOMMountPoint mountPoint) { + public Collection getAllModules(final DOMMountPoint mountPoint) { checkPreconditions(); - final SchemaContext schemaContext = mountPoint == null ? null : mountPoint.getSchemaContext(); + final EffectiveModelContext schemaContext = mountPoint == null ? null : getModelContext(mountPoint); return schemaContext == null ? null : schemaContext.getModules(); } - public Set getAllModules() { + public Collection getAllModules() { checkPreconditions(); - return this.globalSchema.getModules(); + return globalSchema.getModules(); } - private static CharSequence toRestconfIdentifier(final SchemaContext context, final QName qname) { + private static String toRestconfIdentifier(final EffectiveModelContext context, final QName qname) { final Module schema = context.findModule(qname.getModule()).orElse(null); return schema == null ? null : schema.getName() + ':' + qname.getLocalName(); } - public CharSequence toRestconfIdentifier(final QName qname, final DOMMountPoint mount) { - final SchemaContext schema; - if (mount != null) { - schema = mount.getSchemaContext(); - } else { - checkPreconditions(); - schema = this.globalSchema; - } - - return toRestconfIdentifier(schema, qname); + public String toRestconfIdentifier(final QName qname, final DOMMountPoint mountPoint) { + return mountPoint != null ? toRestconfIdentifier(getModelContext(mountPoint), qname) + : toRestconfIdentifier(qname); } - public CharSequence toRestconfIdentifier(final QName qname) { + public String toRestconfIdentifier(final QName qname) { checkPreconditions(); - return toRestconfIdentifier(this.globalSchema, qname); + return toRestconfIdentifier(globalSchema, qname); } - public CharSequence toRestconfIdentifier(final DOMMountPoint mountPoint, final QName qname) { - if (mountPoint == null) { - return null; - } - - return toRestconfIdentifier(mountPoint.getSchemaContext(), qname); + public static String toRestconfIdentifier(final DOMMountPoint mountPoint, final QName qname) { + return mountPoint == null ? null : toRestconfIdentifier(getModelContext(mountPoint), qname); } public Module getRestconfModule() { @@ -393,9 +382,9 @@ public final class ControllerContext implements SchemaContextListener, Closeable return null; } - final Set groupings = restconfModule.getGroupings(); + final Collection groupings = restconfModule.getGroupings(); - final Iterable filteredGroups = Iterables.filter(groupings, + final Iterable filteredGroups = Iterables.filter(groupings, g -> RestConfModule.ERRORS_GROUPING_SCHEMA_NODE.equals(g.getQName().getLocalName())); final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null); @@ -416,8 +405,8 @@ public final class ControllerContext implements SchemaContextListener, Closeable return null; } - final Set groupings = restconfModule.getGroupings(); - final Iterable filteredGroups = Iterables.filter(groupings, + final Collection groupings = restconfModule.getGroupings(); + final Iterable filteredGroups = Iterables.filter(groupings, g -> RestConfModule.RESTCONF_GROUPING_SCHEMA_NODE.equals(g.getQName().getLocalName())); final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null); @@ -461,7 +450,7 @@ public final class ControllerContext implements SchemaContextListener, Closeable } private static DataSchemaNode childByQName(final ChoiceSchemaNode container, final QName name) { - for (final CaseSchemaNode caze : container.getCases().values()) { + for (final CaseSchemaNode caze : container.getCases()) { final DataSchemaNode ret = childByQName(caze, name); if (ret != null) { return ret; @@ -472,7 +461,7 @@ public final class ControllerContext implements SchemaContextListener, Closeable } private static DataSchemaNode childByQName(final CaseSchemaNode container, final QName name) { - return container.getDataChildByName(name); + return container.dataChildByName(name); } private static DataSchemaNode childByQName(final ContainerSchemaNode container, final QName name) { @@ -512,7 +501,7 @@ public final class ControllerContext implements SchemaContextListener, Closeable } private static DataSchemaNode dataNodeChildByQName(final DataNodeContainer container, final QName name) { - final DataSchemaNode ret = container.getDataChildByName(name); + final DataSchemaNode ret = container.dataChildByName(name); if (ret == null) { for (final DataSchemaNode node : container.getChildNodes()) { if (node instanceof ChoiceSchemaNode) { @@ -529,27 +518,32 @@ public final class ControllerContext implements SchemaContextListener, Closeable private String toUriString(final Object object, final LeafSchemaNode leafNode, final DOMMountPoint mount) throws UnsupportedEncodingException { - final Codec codec = RestCodec.from(leafNode.getType(), mount, this); - // FIXME: UrlEncoder looks up a well-known charset, we need something that will use it directly - return object == null ? "" : URLEncoder.encode(codec.serialize(object).toString(), URI_ENCODING_CHARSET.name()); + final IllegalArgumentCodec codec = RestCodec.from(leafNode.getType(), mount, this); + return object == null ? "" : URLEncoder.encode(codec.serialize(object).toString(), StandardCharsets.UTF_8); } @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", justification = "Unrecognised NullableDecl") - private InstanceIdentifierContext collectPathArguments(final InstanceIdentifierBuilder builder, + private InstanceIdentifierContext collectPathArguments(final InstanceIdentifierBuilder builder, final List strings, final DataNodeContainer parentNode, final DOMMountPoint mountPoint, final boolean returnJustMountPoint) { - Preconditions.checkNotNull(strings); + requireNonNull(strings); if (parentNode == null) { return null; } if (strings.isEmpty()) { - return createContext(builder.build(), (DataSchemaNode) parentNode, - mountPoint,mountPoint != null ? mountPoint.getSchemaContext() : this.globalSchema); + return createContext(builder.build(), (DataSchemaNode) parentNode, mountPoint, + mountPoint != null ? getModelContext(mountPoint) : globalSchema); } final String head = strings.iterator().next(); + + if (head.isEmpty()) { + final List remaining = strings.subList(1, strings.size()); + return collectPathArguments(builder, remaining, parentNode, mountPoint, returnJustMountPoint); + } + final String nodeName = toNodeName(head); final String moduleName = toModuleName(head); @@ -561,30 +555,30 @@ public final class ControllerContext implements SchemaContextListener, Closeable ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED); } - if (this.mountService == null) { + if (mountService == null) { throw new RestconfDocumentedException( "MountService was not found. Finding behind mount points does not work.", ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED); } - final YangInstanceIdentifier partialPath = this.dataNormalizer.toNormalized(builder.build()); - final Optional mountOpt = this.mountService.getMountPoint(partialPath); - if (!mountOpt.isPresent()) { + final YangInstanceIdentifier partialPath = dataNormalizer.toNormalized(builder.build()); + final Optional mountOpt = mountService.getMountPoint(partialPath); + if (mountOpt.isEmpty()) { LOG.debug("Instance identifier to missing mount point: {}", partialPath); throw new RestconfDocumentedException("Mount point does not exist.", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING); } final DOMMountPoint mount = mountOpt.get(); - final SchemaContext mountPointSchema = mount.getSchemaContext(); + final EffectiveModelContext mountPointSchema = getModelContext(mount); if (mountPointSchema == null) { throw new RestconfDocumentedException("Mount point does not contain any schema with modules.", ErrorType.APPLICATION, ErrorTag.UNKNOWN_ELEMENT); } if (returnJustMountPoint || strings.size() == 1) { - final YangInstanceIdentifier instance = YangInstanceIdentifier.builder().build(); - return new InstanceIdentifierContext<>(instance, mountPointSchema, mount,mountPointSchema); + return new InstanceIdentifierContext(YangInstanceIdentifier.empty(), mountPointSchema, mount, + mountPointSchema); } final String moduleNameBehindMountPoint = toModuleName(strings.get(1)); @@ -594,7 +588,8 @@ public final class ControllerContext implements SchemaContextListener, Closeable ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE); } - final Iterator it = mountPointSchema.findModules(moduleNameBehindMountPoint).iterator(); + final Iterator it = mountPointSchema.findModules(moduleNameBehindMountPoint) + .iterator(); if (!it.hasNext()) { throw new RestconfDocumentedException("\"" + moduleNameBehindMountPoint + "\" module does not exist in mount point.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); @@ -608,13 +603,13 @@ public final class ControllerContext implements SchemaContextListener, Closeable Module module = null; if (mountPoint == null) { checkPreconditions(); - module = this.globalSchema.findModules(moduleName).stream().findFirst().orElse(null); + module = globalSchema.findModules(moduleName).stream().findFirst().orElse(null); if (module == null) { throw new RestconfDocumentedException("\"" + moduleName + "\" module does not exist.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT); } } else { - final SchemaContext schemaContext = mountPoint.getSchemaContext(); + final EffectiveModelContext schemaContext = getModelContext(mountPoint); if (schemaContext != null) { module = schemaContext.findModules(moduleName).stream().findFirst().orElse(null); } else { @@ -637,8 +632,8 @@ public final class ControllerContext implements SchemaContextListener, Closeable rpc = getRpcDefinition(module, rpcName); } if (rpc != null) { - return new InstanceIdentifierContext<>(builder.build(), rpc, mountPoint, - mountPoint != null ? mountPoint.getSchemaContext() : this.globalSchema); + return new InstanceIdentifierContext(builder.build(), rpc, mountPoint, + mountPoint != null ? getModelContext(mountPoint) : globalSchema); } } @@ -717,18 +712,19 @@ public final class ControllerContext implements SchemaContextListener, Closeable } return createContext(builder.build(), targetNode, mountPoint, - mountPoint != null ? mountPoint.getSchemaContext() : this.globalSchema); + mountPoint != null ? getModelContext(mountPoint) : globalSchema); } - private static InstanceIdentifierContext createContext(final YangInstanceIdentifier instance, - final DataSchemaNode dataSchemaNode, final DOMMountPoint mountPoint, final SchemaContext schemaContext) { + private static InstanceIdentifierContext createContext(final YangInstanceIdentifier instance, + final DataSchemaNode dataSchemaNode, final DOMMountPoint mountPoint, + final EffectiveModelContext schemaContext) { final YangInstanceIdentifier instanceIdentifier = new DataNormalizer(schemaContext).toNormalized(instance); - return new InstanceIdentifierContext<>(instanceIdentifier, dataSchemaNode, mountPoint, schemaContext); + return new InstanceIdentifierContext(instanceIdentifier, dataSchemaNode, mountPoint, schemaContext); } public static DataSchemaNode findInstanceDataChildByNameAndNamespace(final DataNodeContainer container, - final String name, final URI namespace) { - Preconditions.checkNotNull(namespace); + final String name, final XMLNamespace namespace) { + requireNonNull(namespace); final Iterable result = Iterables.filter(findInstanceDataChildrenByName(container, name), node -> namespace.equals(node.getQName().getNamespace())); @@ -737,18 +733,16 @@ public final class ControllerContext implements SchemaContextListener, Closeable public static List findInstanceDataChildrenByName(final DataNodeContainer container, final String name) { - Preconditions.checkNotNull(container); - Preconditions.checkNotNull(name); - final List instantiatedDataNodeContainers = new ArrayList<>(); - collectInstanceDataNodeContainers(instantiatedDataNodeContainers, container, name); + collectInstanceDataNodeContainers(instantiatedDataNodeContainers, requireNonNull(container), + requireNonNull(name)); return instantiatedDataNodeContainers; } private static void collectInstanceDataNodeContainers(final List potentialSchemaNodes, final DataNodeContainer container, final String name) { - final Iterable nodes = Iterables.filter(container.getChildNodes(), + final Iterable nodes = Iterables.filter(container.getChildNodes(), node -> name.equals(node.getQName().getLocalName())); // Can't combine this loop with the filter above because the filter is @@ -761,8 +755,8 @@ public final class ControllerContext implements SchemaContextListener, Closeable final Iterable choiceNodes = Iterables.filter(container.getChildNodes(), ChoiceSchemaNode.class); - final Iterable> map = Iterables.transform(choiceNodes, - choice -> choice.getCases().values()); + final Iterable> map = Iterables.transform(choiceNodes, + ChoiceSchemaNode::getCases); for (final CaseSchemaNode caze : Iterables.concat(map)) { collectInstanceDataNodeContainers(potentialSchemaNodes, caze, name); } @@ -771,22 +765,22 @@ public final class ControllerContext implements SchemaContextListener, Closeable public static boolean isInstantiatedDataSchema(final DataSchemaNode node) { return node instanceof LeafSchemaNode || node instanceof LeafListSchemaNode || node instanceof ContainerSchemaNode || node instanceof ListSchemaNode - || node instanceof AnyXmlSchemaNode; + || node instanceof AnyxmlSchemaNode; } private void addKeyValue(final HashMap map, final DataSchemaNode node, final String uriValue, final DOMMountPoint mountPoint) { - Preconditions.checkNotNull(uriValue); - Preconditions.checkArgument(node instanceof LeafSchemaNode); + checkArgument(node instanceof LeafSchemaNode); - final SchemaContext schemaContext = mountPoint == null ? this.globalSchema : mountPoint.getSchemaContext(); - final String urlDecoded = urlPathArgDecode(uriValue); + final EffectiveModelContext schemaContext = mountPoint == null ? globalSchema : getModelContext(mountPoint); + final String urlDecoded = urlPathArgDecode(requireNonNull(uriValue)); TypeDefinition typedef = ((LeafSchemaNode) node).getType(); final TypeDefinition baseType = RestUtil.resolveBaseTypeFrom(typedef); if (baseType instanceof LeafrefTypeDefinition) { - typedef = SchemaContextUtil.getBaseTypeForLeafRef((LeafrefTypeDefinition) baseType, schemaContext, node); + typedef = SchemaInferenceStack.ofInstantiatedPath(schemaContext, node.getPath()) + .resolveLeafref((LeafrefTypeDefinition) baseType); } - final Codec codec = RestCodec.from(typedef, mountPoint, this); + final IllegalArgumentCodec codec = RestCodec.from(typedef, mountPoint, this); Object decoded = codec.deserialize(urlDecoded); String additionalInfo = ""; if (decoded == null) { @@ -833,8 +827,8 @@ public final class ControllerContext implements SchemaContextListener, Closeable return str.substring(idx + 1); } - private QName toQName(final SchemaContext schemaContext, final String name, - final java.util.Optional revisionDate) { + private QName toQName(final EffectiveModelContext schemaContext, final String name, + final Optional revisionDate) { checkPreconditions(); final String module = toModuleName(name); final String node = toNodeName(name); @@ -842,11 +836,11 @@ public final class ControllerContext implements SchemaContextListener, Closeable return m == null ? null : QName.create(m.getQNameModule(), node); } - private QName toQName(final SchemaContext schemaContext, final String name) { + private QName toQName(final EffectiveModelContext schemaContext, final String name) { checkPreconditions(); final String module = toModuleName(name); final String node = toNodeName(name); - final Set modules = schemaContext.findModules(module); + final Collection modules = schemaContext.findModules(module); return modules.isEmpty() ? null : QName.create(modules.iterator().next().getQNameModule(), node); } @@ -854,14 +848,14 @@ public final class ControllerContext implements SchemaContextListener, Closeable return node instanceof ListSchemaNode || node instanceof ContainerSchemaNode; } - public RpcDefinition getRpcDefinition(final String name, final java.util.Optional revisionDate) { - final QName validName = toQName(this.globalSchema, name, revisionDate); - return validName == null ? null : this.qnameToRpc.get().get(validName); + public RpcDefinition getRpcDefinition(final String name, final Optional revisionDate) { + final QName validName = toQName(globalSchema, name, revisionDate); + return validName == null ? null : qnameToRpc.get().get(validName); } public RpcDefinition getRpcDefinition(final String name) { - final QName validName = toQName(this.globalSchema, name); - return validName == null ? null : this.qnameToRpc.get().get(validName); + final QName validName = toQName(globalSchema, name); + return validName == null ? null : qnameToRpc.get().get(validName); } private static RpcDefinition getRpcDefinition(final Module module, final String rpcName) { @@ -875,9 +869,9 @@ public final class ControllerContext implements SchemaContextListener, Closeable } @Override - public void onGlobalContextUpdated(final SchemaContext context) { + public void onModelContextUpdated(final EffectiveModelContext context) { if (context != null) { - final Collection defs = context.getOperations(); + final Collection defs = context.getOperations(); final Map newMap = new HashMap<>(defs.size()); for (final RpcDefinition operation : defs) { @@ -885,36 +879,25 @@ public final class ControllerContext implements SchemaContextListener, Closeable } // FIXME: still not completely atomic - this.qnameToRpc.set(ImmutableMap.copyOf(newMap)); + qnameToRpc.set(ImmutableMap.copyOf(newMap)); setGlobalSchema(context); } } - public static List urlPathArgsDecode(final Iterable strings) { - try { - final List decodedPathArgs = new ArrayList<>(); - for (final String pathArg : strings) { - final String _decode = URLDecoder.decode(pathArg, URI_ENCODING_CHARSET.name()); - decodedPathArgs.add(_decode); - } - return decodedPathArgs; - } catch (final UnsupportedEncodingException e) { - throw new RestconfDocumentedException("Invalid URL path '" + strings + "': " + e.getMessage(), - ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, e); + private static List urlPathArgsDecode(final Iterable strings) { + final List decodedPathArgs = new ArrayList<>(); + for (final String pathArg : strings) { + final String _decode = URLDecoder.decode(pathArg, StandardCharsets.UTF_8); + decodedPathArgs.add(_decode); } + return decodedPathArgs; } - public String urlPathArgDecode(final String pathArg) { - if (pathArg != null) { - try { - return URLDecoder.decode(pathArg, URI_ENCODING_CHARSET.name()); - } catch (final UnsupportedEncodingException e) { - throw new RestconfDocumentedException("Invalid URL path arg '" + pathArg + "': " + e.getMessage(), - ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, e); - } + static String urlPathArgDecode(final String pathArg) { + if (pathArg == null) { + return null; } - - return null; + return URLDecoder.decode(pathArg, StandardCharsets.UTF_8); } private CharSequence convertToRestconfIdentifier(final PathArgument argument, final DataSchemaNode node, @@ -939,12 +922,8 @@ public final class ControllerContext implements SchemaContextListener, Closeable final ListSchemaNode node, final DOMMountPoint mount) { final QName nodeType = argument.getNodeType(); final CharSequence nodeIdentifier = this.toRestconfIdentifier(nodeType, mount); - final Map keyValues = argument.getKeyValues(); - final StringBuilder builder = new StringBuilder(); - builder.append('/'); - builder.append(nodeIdentifier); - builder.append('/'); + final StringBuilder builder = new StringBuilder().append('/').append(nodeIdentifier).append('/'); final List keyDefinition = node.getKeyDefinition(); boolean hasElements = false; @@ -957,12 +936,14 @@ public final class ControllerContext implements SchemaContextListener, Closeable builder.append('/'); } + checkState(listChild instanceof LeafSchemaNode, + "List key has to consist of leaves, not %s", listChild); + + final Object value = argument.getValue(key); try { - Preconditions.checkState(listChild instanceof LeafSchemaNode, - "List key has to consist of leaves, not %s", listChild); - builder.append(toUriString(keyValues.get(key), (LeafSchemaNode)listChild, mount)); + builder.append(toUriString(value, (LeafSchemaNode)listChild, mount)); } catch (final UnsupportedEncodingException e) { - LOG.error("Error parsing URI: {}", keyValues.get(key), e); + LOG.error("Error parsing URI: {}", value, e); return null; } break; @@ -975,7 +956,7 @@ public final class ControllerContext implements SchemaContextListener, Closeable public YangInstanceIdentifier toNormalized(final YangInstanceIdentifier legacy) { try { - return this.dataNormalizer.toNormalized(legacy); + return dataNormalizer.toNormalized(legacy); } catch (final NullPointerException e) { throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible", e); } @@ -983,7 +964,7 @@ public final class ControllerContext implements SchemaContextListener, Closeable public YangInstanceIdentifier toXpathRepresentation(final YangInstanceIdentifier instanceIdentifier) { try { - return this.dataNormalizer.toLegacy(instanceIdentifier); + return dataNormalizer.toLegacy(instanceIdentifier); } catch (final NullPointerException e) { throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible", e); } catch (final DataNormalizationException e) { @@ -994,14 +975,16 @@ public final class ControllerContext implements SchemaContextListener, Closeable public boolean isNodeMixin(final YangInstanceIdentifier path) { final DataNormalizationOperation operation; try { - operation = this.dataNormalizer.getOperation(path); + operation = dataNormalizer.getOperation(path); } catch (final DataNormalizationException e) { throw new RestconfDocumentedException("Data normalizer failed. Normalization isn't possible", e); } return operation.isMixin(); } - public DataNormalizationOperation getRootOperation() { - return this.dataNormalizer.getRootOperation(); + private static EffectiveModelContext getModelContext(final DOMMountPoint mountPoint) { + return mountPoint.getService(DOMSchemaService.class) + .flatMap(svc -> Optional.ofNullable(svc.getGlobalContext())) + .orElse(null); } }