Factor out MdsalDatabindProvider
[netconf.git] / restconf / restconf-nb / src / main / java / org / opendaylight / restconf / server / mdsal / MdsalDatabindProvider.java
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.server.mdsal;
9
10 import static com.google.common.base.Verify.verifyNotNull;
11
12 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
13 import java.lang.invoke.MethodHandles;
14 import java.lang.invoke.VarHandle;
15 import javax.annotation.PreDestroy;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
21 import org.opendaylight.mdsal.dom.api.DOMSchemaService.YangTextSourceExtension;
22 import org.opendaylight.restconf.server.api.DatabindContext;
23 import org.opendaylight.restconf.server.spi.DatabindProvider;
24 import org.opendaylight.yangtools.concepts.Registration;
25 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
26 import org.osgi.service.component.annotations.Activate;
27 import org.osgi.service.component.annotations.Component;
28 import org.osgi.service.component.annotations.Deactivate;
29 import org.osgi.service.component.annotations.Reference;
30
31 /**
32  * A {@link DatabindProvider} tracking a {@link DOMSchemaService}.
33  */
34 @Singleton
35 @Component(service = { DatabindProvider.class, MdsalDatabindProvider.class })
36 public final class MdsalDatabindProvider implements DatabindProvider, AutoCloseable {
37     private static final VarHandle CURRENT_DATABIND;
38
39     static {
40         try {
41             CURRENT_DATABIND = MethodHandles.lookup()
42                 .findVarHandle(MdsalDatabindProvider.class, "currentDatabind", DatabindContext.class);
43         } catch (NoSuchFieldException | IllegalAccessException e) {
44             throw new ExceptionInInitializerError(e);
45         }
46     }
47
48     private final @Nullable YangTextSourceExtension sourceProvider;
49     private final Registration reg;
50
51     @SuppressFBWarnings(value = "URF_UNREAD_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749")
52     private volatile DatabindContext currentDatabind;
53
54     @Inject
55     @Activate
56     public MdsalDatabindProvider(@Reference final DOMSchemaService schemaService) {
57         sourceProvider = schemaService.extension(YangTextSourceExtension.class);
58         currentDatabind = DatabindContext.ofModel(schemaService.getGlobalContext());
59         reg = schemaService.registerSchemaContextListener(this::onModelContextUpdated);
60     }
61
62     @PreDestroy
63     @Deactivate
64     @Override
65     public void close() {
66         reg.close();
67     }
68
69     @Override
70     public DatabindContext currentDatabind() {
71         return verifyNotNull((@NonNull DatabindContext) CURRENT_DATABIND.getAcquire(this));
72     }
73
74     @Nullable YangTextSourceExtension sourceProvider() {
75         return sourceProvider;
76     }
77
78     private void onModelContextUpdated(final EffectiveModelContext newModelContext) {
79         final var local = currentDatabind;
80         if (!newModelContext.equals(local.modelContext())) {
81             CURRENT_DATABIND.setRelease(this, DatabindContext.ofModel(newModelContext));
82         }
83     }
84 }