2 * Copyright (c) 2020 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.mdsal.binding.dom.adapter.query;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import com.google.common.base.Throwables;
14 import com.google.common.cache.CacheBuilder;
15 import com.google.common.cache.CacheLoader;
16 import com.google.common.cache.LoadingCache;
17 import java.util.ServiceLoader;
18 import java.util.concurrent.ExecutionException;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.kohsuke.MetaInfServices;
23 import org.opendaylight.mdsal.binding.api.query.DescendantQueryBuilder;
24 import org.opendaylight.mdsal.binding.api.query.QueryFactory;
25 import org.opendaylight.mdsal.binding.api.query.QueryStructureException;
26 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree;
27 import org.opendaylight.mdsal.binding.dom.codec.spi.BindingSchemaMapping;
28 import org.opendaylight.yangtools.yang.binding.DataObject;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
31 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
32 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
39 public final class DefaultQueryFactory implements QueryFactory {
40 private record MethodId(@NonNull DataNodeContainer parent, @NonNull String methodName) {
42 requireNonNull(parent);
43 requireNonNull(methodName);
47 private static final Logger LOG = LoggerFactory.getLogger(DefaultQueryFactory.class);
49 private final LoadingCache<MethodId, NodeIdentifier> knownMethods = CacheBuilder.newBuilder().build(
50 new CacheLoader<MethodId, NodeIdentifier>() {
52 public NodeIdentifier load(final MethodId key) {
53 final DataNodeContainer parent = key.parent;
54 final String methodName = key.methodName;
56 for (DataSchemaNode child : parent.getChildNodes()) {
57 if (methodName.equals(BindingSchemaMapping.getGetterMethodName(child))) {
58 return NodeIdentifier.create(child.getQName());
61 throw new QueryStructureException("Failed to find schema matching " + methodName + " in " + parent);
64 private final @NonNull BindingCodecTree codec;
66 public DefaultQueryFactory() {
67 this(ServiceLoader.load(BindingCodecTree.class).findFirst().orElseThrow());
71 public DefaultQueryFactory(final BindingCodecTree codec) {
72 this.codec = requireNonNull(codec);
76 public <T extends DataObject> DescendantQueryBuilder<T> querySubtree(final InstanceIdentifier<T> rootPath) {
77 return new DefaultDescendantQueryBuilder<>(this, rootPath);
80 @NonNull BindingCodecTree codec() {
84 @NonNull NodeIdentifier findChild(final DataNodeContainer parent, final String methodName) {
86 return knownMethods.get(new MethodId(parent, methodName));
87 } catch (ExecutionException e) {
88 LOG.debug("Failed to find method for {}", methodName, e);
89 final Throwable cause = e.getCause();
90 Throwables.throwIfUnchecked(cause);
91 throw new IllegalStateException("Failed to load cache", e);