a5e1f8190b62a25e99a8b339234b7e67a84f792f
[netconf.git] /
1 /*
2  * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.restconf.subscription;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import java.net.URI;
15 import java.time.Instant;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.mdsal.common.api.CommitInfo;
19 import org.opendaylight.restconf.notifications.mdsal.MdsalNotificationService;
20 import org.opendaylight.restconf.notifications.mdsal.SubscriptionStateService;
21 import org.opendaylight.restconf.server.api.ServerException;
22 import org.opendaylight.restconf.server.api.ServerRequest;
23 import org.opendaylight.restconf.server.spi.OperationInput;
24 import org.opendaylight.restconf.server.spi.RpcImplementation;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.subscribed.notifications.rev190909.KillSubscription;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.subscribed.notifications.rev190909.KillSubscriptionInput;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.subscribed.notifications.rev190909.KillSubscriptionOutput;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.subscribed.notifications.rev190909.NoSuchSubscription;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.subscribed.notifications.rev190909.subscriptions.Subscription;
30 import org.opendaylight.yangtools.yang.common.ErrorTag;
31 import org.opendaylight.yangtools.yang.common.ErrorType;
32 import org.opendaylight.yangtools.yang.common.QName;
33 import org.opendaylight.yangtools.yang.common.Uint32;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
36 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
37 import org.osgi.service.component.annotations.Activate;
38 import org.osgi.service.component.annotations.Component;
39 import org.osgi.service.component.annotations.Reference;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * RESTCONF implementation of {@link KillSubscription}.
45  */
46 @Singleton
47 @Component(service = RpcImplementation.class)
48 public final class KillSubscriptionRpc extends RpcImplementation {
49     private static final YangInstanceIdentifier.NodeIdentifier SUBSCRIPTION_ID =
50         YangInstanceIdentifier.NodeIdentifier.create(QName.create(KillSubscriptionInput.QNAME, "id").intern());
51
52     private static final Logger LOG = LoggerFactory.getLogger(KillSubscriptionRpc.class);
53
54     private final MdsalNotificationService mdsalService;
55     private final SubscriptionStateService subscriptionStateService;
56     private final SubscriptionStateMachine stateMachine;
57
58     @Inject
59     @Activate
60     public KillSubscriptionRpc(@Reference final MdsalNotificationService mdsalService,
61             @Reference final SubscriptionStateService subscriptionStateService,
62             @Reference final SubscriptionStateMachine stateMachine) {
63         super(KillSubscription.QNAME);
64         this.mdsalService = requireNonNull(mdsalService);
65         this.subscriptionStateService = requireNonNull(subscriptionStateService);
66         this.stateMachine = requireNonNull(stateMachine);
67     }
68
69     @Override
70     public void invoke(final ServerRequest<ContainerNode> request, final URI restconfURI, final OperationInput input) {
71         final var body = input.input();
72         final Uint32 id;
73         try {
74             id = leaf(body, SUBSCRIPTION_ID, Uint32.class);
75         } catch (IllegalArgumentException e) {
76             request.completeWith(new ServerException(ErrorType.APPLICATION, ErrorTag.BAD_ELEMENT, e));
77             return;
78         }
79         if (id == null) {
80             request.completeWith(new ServerException(ErrorType.APPLICATION, ErrorTag.MISSING_ELEMENT,
81                 "No id specified"));
82             return;
83         }
84         final var state = stateMachine.getSubscriptionState(id);
85         if (state == null) {
86             request.completeWith(new ServerException(ErrorType.APPLICATION, ErrorTag.MISSING_ELEMENT,
87                 "No subscription with given ID."));
88             return;
89         }
90         if (state != SubscriptionState.ACTIVE && state != SubscriptionState.SUSPENDED) {
91             request.completeWith(new ServerException(ErrorType.APPLICATION, ErrorTag.BAD_ELEMENT,
92                 "There is no active or suspended subscription with given ID."));
93             return;
94         }
95
96         mdsalService.deleteSubscription(SubscriptionUtil.SUBSCRIPTIONS.node(YangInstanceIdentifier
97                 .NodeIdentifierWithPredicates.of(Subscription.QNAME, SubscriptionUtil.QNAME_ID, id)))
98             .addCallback(new FutureCallback<CommitInfo>() {
99                 @Override
100                 public void onSuccess(final CommitInfo result) {
101                     request.completeWith(ImmutableNodes.newContainerBuilder()
102                         .withNodeIdentifier(YangInstanceIdentifier.NodeIdentifier.create(KillSubscriptionOutput.QNAME))
103                         .build());
104                     stateMachine.moveTo(id, SubscriptionState.END);
105                     try {
106                         subscriptionStateService.subscriptionTerminated(Instant.now(), id, NoSuchSubscription.QNAME);
107                     } catch (InterruptedException e) {
108                         LOG.warn("Could not send subscription terminated notification", e);
109                     }
110                 }
111
112                 @Override
113                 public void onFailure(final Throwable throwable) {
114                     request.completeWith(new ServerException(ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED,
115                         throwable.getMessage()));
116                 }
117             }, MoreExecutors.directExecutor());
118     }
119 }