2 * Copyright (c) 2022 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.restconf.nb.rfc8040.monitoring;
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.monitoring.rev170126.$YangModuleInfoImpl.qnameOf;
13 import com.google.common.annotations.VisibleForTesting;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import javax.annotation.PreDestroy;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.checkerframework.checker.lock.qual.Holding;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.mdsal.common.api.CommitInfo;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
24 import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
25 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
26 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
27 import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
28 import org.opendaylight.restconf.api.query.AbstractReplayParam;
29 import org.opendaylight.restconf.api.query.ChangedLeafNodesOnlyParam;
30 import org.opendaylight.restconf.api.query.DepthParam;
31 import org.opendaylight.restconf.api.query.FieldsParam;
32 import org.opendaylight.restconf.api.query.FilterParam;
33 import org.opendaylight.restconf.api.query.LeafNodesOnlyParam;
34 import org.opendaylight.restconf.api.query.PrettyPrintParam;
35 import org.opendaylight.restconf.api.query.SkipNotificationDataParam;
36 import org.opendaylight.restconf.api.query.WithDefaultsParam;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.monitoring.rev170126.RestconfState;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.monitoring.rev170126.restconf.state.Capabilities;
39 import org.opendaylight.yangtools.concepts.Registration;
40 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
41 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
42 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
43 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
44 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
45 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextListener;
46 import org.osgi.service.component.annotations.Activate;
47 import org.osgi.service.component.annotations.Component;
48 import org.osgi.service.component.annotations.Deactivate;
49 import org.osgi.service.component.annotations.Reference;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
54 * A simple component which maintains {@link Capabilities} in the operational datastore.
57 @Component(service = { })
58 public final class CapabilitiesWriter
59 implements AutoCloseable, EffectiveModelContextListener, DOMTransactionChainListener {
60 private static final Logger LOG = LoggerFactory.getLogger(CapabilitiesWriter.class);
63 static final @NonNull NodeIdentifier CAPABILITY = NodeIdentifier.create(qnameOf("capability"));
65 private static final YangInstanceIdentifier PATH = YangInstanceIdentifier.of(
66 NodeIdentifier.create(RestconfState.QNAME), NodeIdentifier.create(Capabilities.QNAME), CAPABILITY);
68 private final DOMDataBroker dataBroker;
70 private DOMTransactionChain txChain;
71 private Registration reg;
73 private boolean written;
77 public CapabilitiesWriter(@Reference final DOMDataBroker dataBroker,
78 @Reference final DOMSchemaService schemaService) {
79 this.dataBroker = requireNonNull(dataBroker);
80 reg = schemaService.registerSchemaContextListener(this);
86 public synchronized void close() {
92 deleteRestconfState();
93 if (txChain != null) {
99 public synchronized void onTransactionChainFailed(final DOMTransactionChain chain,
100 final DOMDataTreeTransaction transaction, final Throwable cause) {
101 LOG.warn("Transaction chain failed, updates may not have been propagated", cause);
106 public synchronized void onTransactionChainSuccessful(final DOMTransactionChain chain) {
107 LOG.debug("Transaction chain closed successfully");
112 public synchronized void onModelContextUpdated(final EffectiveModelContext newModelContext) {
114 LOG.debug("Ignoring model context update");
118 if (newModelContext.findModuleStatement(RestconfState.QNAME.getModule()).isPresent()) {
119 writeRestconfState();
121 deleteRestconfState();
126 private void deleteRestconfState() {
128 LOG.debug("No state recorded as written, not attempting removal");
132 LOG.debug("Removing ietf-restconf-monitoring state");
133 if (txChain == null) {
134 txChain = dataBroker.createMergingTransactionChain(this);
137 final var tx = txChain.newWriteOnlyTransaction();
138 tx.delete(LogicalDatastoreType.OPERATIONAL, PATH);
139 tx.commit().addCallback(new FutureCallback<CommitInfo>() {
141 public void onSuccess(final CommitInfo result) {
146 public void onFailure(final Throwable cause) {
147 // Ignored, will be reported on the transaction chain
149 }, MoreExecutors.directExecutor());
153 private void writeRestconfState() {
155 LOG.debug("State recorded as written, not updating it");
159 LOG.debug("Updating state of ietf-restconf-monitoring");
160 if (txChain == null) {
161 txChain = dataBroker.createMergingTransactionChain(this);
164 final var tx = txChain.newWriteOnlyTransaction();
165 tx.put(LogicalDatastoreType.OPERATIONAL, PATH, mapCapabilites());
166 tx.commit().addCallback(new FutureCallback<CommitInfo>() {
168 public void onSuccess(final CommitInfo result) {
173 public void onFailure(final Throwable cause) {
174 // Ignored, will be reported on the transaction chain
176 }, MoreExecutors.directExecutor());
179 private synchronized void markWritten() {
180 LOG.debug("State of ietf-restconf-monitoring updated");
184 private synchronized void markUnwritten() {
185 LOG.debug("State of ietf-restconf-monitoring removed");
190 * Create a {@code restconf-state} container.
192 * @return A container holding capabilities
195 static @NonNull LeafSetNode<String> mapCapabilites() {
196 return Builders.<String>orderedLeafSetBuilder()
197 .withNodeIdentifier(CAPABILITY)
198 .withChildValue(DepthParam.capabilityUri().toString())
199 .withChildValue(FieldsParam.capabilityUri().toString())
200 .withChildValue(FilterParam.capabilityUri().toString())
201 .withChildValue(AbstractReplayParam.capabilityUri().toString())
202 .withChildValue(WithDefaultsParam.capabilityUri().toString())
203 .withChildValue(PrettyPrintParam.capabilityUri().toString())
204 .withChildValue(LeafNodesOnlyParam.capabilityUri().toString())
205 .withChildValue(ChangedLeafNodesOnlyParam.capabilityUri().toString())
206 .withChildValue(SkipNotificationDataParam.capabilityUri().toString())