8c0b167db6967ea29a3ba6dfdff9c7925fb2d874
[mdsal.git] / dom / mdsal-dom-schema-osgi / src / main / java / org / opendaylight / mdsal / dom / schema / osgi / impl / RegularYangModuleInfoRegistry.java
1 /*
2  * Copyright (c) 2017, 2020 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.mdsal.dom.schema.osgi.impl;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.collect.ImmutableList;
13 import java.util.List;
14 import java.util.NoSuchElementException;
15 import org.checkerframework.checker.lock.qual.GuardedBy;
16 import org.checkerframework.checker.lock.qual.Holding;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.mdsal.binding.runtime.api.ModuleInfoSnapshot;
19 import org.opendaylight.mdsal.binding.runtime.spi.ModuleInfoSnapshotResolver;
20 import org.opendaylight.yangtools.concepts.AbstractRegistration;
21 import org.opendaylight.yangtools.concepts.ObjectRegistration;
22 import org.opendaylight.yangtools.concepts.Registration;
23 import org.opendaylight.yangtools.yang.binding.DataRoot;
24 import org.opendaylight.yangtools.yang.binding.YangFeatureProvider;
25 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
26 import org.opendaylight.yangtools.yang.parser.api.YangParserFactory;
27 import org.osgi.service.component.ComponentFactory;
28 import org.osgi.service.component.ComponentInstance;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33  * Update SchemaContext service in Service Registry each time new YangModuleInfo is added or removed.
34  */
35 final class RegularYangModuleInfoRegistry extends YangModuleInfoRegistry {
36     private static final Logger LOG = LoggerFactory.getLogger(RegularYangModuleInfoRegistry.class);
37
38     private final ComponentFactory<OSGiModuleInfoSnapshotImpl> contextFactory;
39     private final ModuleInfoSnapshotResolver resolver;
40
41     @GuardedBy("this")
42     private ComponentInstance<OSGiModuleInfoSnapshotImpl> currentInstance;
43     @GuardedBy("this")
44     private ModuleInfoSnapshot currentSnapshot;
45     @GuardedBy("this")
46     private int generation;
47
48     private volatile boolean ignoreScanner = true;
49
50     RegularYangModuleInfoRegistry(final ComponentFactory<OSGiModuleInfoSnapshotImpl> contextFactory,
51             final YangParserFactory factory) {
52         this.contextFactory = requireNonNull(contextFactory);
53         resolver = new ModuleInfoSnapshotResolver("dom-schema-osgi", factory);
54     }
55
56     // Invocation from scanner, we may want to ignore this in order to not process partial updates
57     @Override
58     void scannerUpdate() {
59         if (!ignoreScanner) {
60             synchronized (this) {
61                 updateService();
62             }
63         }
64     }
65
66     @Override
67     synchronized void scannerShutdown() {
68         ignoreScanner = true;
69     }
70
71     @Override
72     synchronized void enableScannerAndUpdate() {
73         ignoreScanner = false;
74         updateService();
75     }
76
77     @Override
78     synchronized void close() {
79         ignoreScanner = true;
80         if (currentInstance != null) {
81             currentInstance.dispose();
82             currentInstance = null;
83         }
84     }
85
86     @Override
87     Registration registerBundle(final List<YangModuleInfo> moduleInfos,
88             final List<YangFeatureProvider<?>> featureProviders) {
89         final var infoRegs = resolver.registerModuleInfos(moduleInfos);
90         final var featureRegs = featureProviders.stream()
91             .map(provider -> {
92                 @SuppressWarnings("unchecked")
93                 final var raw = (YangFeatureProvider<@NonNull DataRoot>) provider;
94                 return resolver.registerModuleFeatures(raw.boundModule(), raw.supportedFeatures());
95             })
96             .collect(ImmutableList.toImmutableList());
97
98         return new AbstractRegistration() {
99             @Override
100             protected void removeRegistration() {
101                 featureRegs.forEach(Registration::close);
102                 infoRegs.forEach(ObjectRegistration::close);
103             }
104         };
105     }
106
107     @Holding("this")
108     private void updateService() {
109         final ModuleInfoSnapshot newSnapshot;
110         try {
111             newSnapshot = resolver.takeSnapshot();
112         } catch (NoSuchElementException e) {
113             LOG.debug("No snapshot available", e);
114             return;
115         }
116         if (newSnapshot.equals(currentSnapshot)) {
117             LOG.debug("No update to snapshot");
118             return;
119         }
120
121         final ComponentInstance<OSGiModuleInfoSnapshotImpl> newInstance = contextFactory.newInstance(
122             OSGiModuleInfoSnapshotImpl.props(nextGeneration(), newSnapshot));
123         if (currentInstance != null) {
124             currentInstance.dispose();
125         }
126         currentInstance = newInstance;
127         currentSnapshot = newSnapshot;
128     }
129
130     @Holding("this")
131     private long nextGeneration() {
132         return generation == -1 ? -1 : ++generation;
133     }
134 }