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