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 static final class MethodId {
41 final DataNodeContainer parent;
42 final String methodName;
44 MethodId(final DataNodeContainer parent, final String methodName) {
45 this.parent = requireNonNull(parent);
46 this.methodName = requireNonNull(methodName);
50 public int hashCode() {
51 return parent.hashCode() * 31 + methodName.hashCode();
55 public boolean equals(final Object obj) {
56 if (!(obj instanceof MethodId)) {
59 final MethodId other = (MethodId) obj;
60 return methodName.equals(other.methodName) && parent.equals(other.parent);
64 private static final Logger LOG = LoggerFactory.getLogger(DefaultQueryFactory.class);
66 private final LoadingCache<MethodId, NodeIdentifier> knownMethods = CacheBuilder.newBuilder().build(
67 new CacheLoader<MethodId, NodeIdentifier>() {
69 public NodeIdentifier load(final MethodId key) {
70 final DataNodeContainer parent = key.parent;
71 final String methodName = key.methodName;
73 for (DataSchemaNode child : parent.getChildNodes()) {
74 if (methodName.equals(BindingSchemaMapping.getGetterMethodName(child))) {
75 return NodeIdentifier.create(child.getQName());
78 throw new QueryStructureException("Failed to find schema matching " + methodName + " in " + parent);
81 private final @NonNull BindingCodecTree codec;
83 public DefaultQueryFactory() {
84 this(ServiceLoader.load(BindingCodecTree.class).findFirst().orElseThrow());
88 public DefaultQueryFactory(final BindingCodecTree codec) {
89 this.codec = requireNonNull(codec);
93 public <T extends DataObject> DescendantQueryBuilder<T> querySubtree(final InstanceIdentifier<T> rootPath) {
94 return new DefaultDescendantQueryBuilder<>(this, rootPath);
97 @NonNull BindingCodecTree codec() {
101 @NonNull NodeIdentifier findChild(final DataNodeContainer parent, final String methodName) {
103 return knownMethods.get(new MethodId(parent, methodName));
104 } catch (ExecutionException e) {
105 LOG.debug("Failed to find method for {}", methodName, e);
106 final Throwable cause = e.getCause();
107 Throwables.throwIfUnchecked(cause);
108 throw new IllegalStateException("Failed to load cache", e);