Bump yangtools to 13.0.0
[mdsal.git] / binding / mdsal-binding-runtime-osgi / src / main / java / org / opendaylight / mdsal / binding / runtime / osgi / impl / OSGiBindingRuntime.java
1 /*
2  * Copyright (c) 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.binding.runtime.osgi.impl;
9
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.annotations.Beta;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.IdentityHashMap;
17 import java.util.Map;
18 import java.util.Set;
19 import org.checkerframework.checker.lock.qual.GuardedBy;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeGenerator;
22 import org.opendaylight.mdsal.binding.runtime.api.DefaultBindingRuntimeContext;
23 import org.opendaylight.mdsal.dom.schema.osgi.OSGiModuleInfoSnapshot;
24 import org.osgi.service.component.ComponentFactory;
25 import org.osgi.service.component.ComponentInstance;
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 import org.osgi.service.component.annotations.ReferenceCardinality;
31 import org.osgi.service.component.annotations.ReferencePolicy;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 @Beta
36 @Component(immediate = true)
37 public final class OSGiBindingRuntime {
38     // TODO: can we get rid of this complexity?
39     private abstract static class AbstractInstances {
40
41         abstract void add(OSGiModuleInfoSnapshot snapshot);
42
43         abstract void remove(OSGiModuleInfoSnapshot snapshot);
44
45         abstract @NonNull AbstractInstances toActive(BindingRuntimeGenerator generator,
46             ComponentFactory<OSGiBindingRuntimeContextImpl> factory);
47
48         abstract @NonNull AbstractInstances toInactive();
49     }
50
51     private static final class InactiveInstances extends AbstractInstances {
52         private final Set<OSGiModuleInfoSnapshot> instances = Collections.newSetFromMap(new IdentityHashMap<>());
53
54         InactiveInstances() {
55
56         }
57
58         InactiveInstances(final Set<OSGiModuleInfoSnapshot> keySet) {
59             instances.addAll(keySet);
60         }
61
62         @Override
63         void add(final OSGiModuleInfoSnapshot snapshot) {
64             verify(instances.add(snapshot), "Duplicate instance %s?!", snapshot);
65         }
66
67         @Override
68         void remove(final OSGiModuleInfoSnapshot snapshot) {
69             instances.remove(snapshot);
70         }
71
72         @Override
73         AbstractInstances toActive(final BindingRuntimeGenerator generator,
74                 final ComponentFactory<OSGiBindingRuntimeContextImpl> factory) {
75             final ActiveInstances active = new ActiveInstances(generator, factory);
76             instances.stream()
77                 .sorted(Comparator.comparing(OSGiModuleInfoSnapshot::getGeneration).reversed())
78                 .forEach(active::add);
79             return active;
80         }
81
82         @Override
83         AbstractInstances toInactive() {
84             throw new IllegalStateException("Attempted to deactivate inactive instances");
85         }
86     }
87
88     private static final class ActiveInstances extends AbstractInstances {
89         private final Map<OSGiModuleInfoSnapshot, ComponentInstance<OSGiBindingRuntimeContextImpl>> instances =
90             new IdentityHashMap<>();
91         private final BindingRuntimeGenerator generator;
92         private final ComponentFactory<OSGiBindingRuntimeContextImpl> factory;
93
94         ActiveInstances(final BindingRuntimeGenerator generator,
95                 final ComponentFactory<OSGiBindingRuntimeContextImpl> factory) {
96             this.generator = requireNonNull(generator);
97             this.factory = requireNonNull(factory);
98         }
99
100         @Override
101         void add(final OSGiModuleInfoSnapshot snapshot) {
102             final var infoSnapshot = snapshot.getService();
103             final var types = generator.generateTypeMapping(infoSnapshot.modelContext());
104
105             instances.put(snapshot, factory.newInstance(OSGiBindingRuntimeContextImpl.props(
106                 snapshot.getGeneration(), snapshot.getServiceRanking(),
107                 new DefaultBindingRuntimeContext(types, infoSnapshot))));
108         }
109
110         @Override
111         void remove(final OSGiModuleInfoSnapshot snapshot) {
112             final var instance = instances.remove(snapshot);
113             if (instance != null) {
114                 instance.dispose();
115             } else {
116                 LOG.warn("Instance for generation {} not found", snapshot.getGeneration());
117             }
118         }
119
120         @Override
121         AbstractInstances toActive(final BindingRuntimeGenerator ignoreGenerator,
122                 final ComponentFactory<OSGiBindingRuntimeContextImpl> ignoreFactory) {
123             throw new IllegalStateException("Attempted to activate active instances");
124         }
125
126         @Override
127         AbstractInstances toInactive() {
128             instances.values().forEach(ComponentInstance::dispose);
129             return new InactiveInstances(instances.keySet());
130         }
131     }
132
133     private static final Logger LOG = LoggerFactory.getLogger(OSGiBindingRuntime.class);
134
135     @Reference
136     BindingRuntimeGenerator generator = null;
137
138     @Reference(target = "(component.factory=" + OSGiBindingRuntimeContextImpl.FACTORY_NAME + ")")
139     ComponentFactory<OSGiBindingRuntimeContextImpl> contextFactory = null;
140
141     @GuardedBy("this")
142     private AbstractInstances instances = new InactiveInstances();
143
144     @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
145     synchronized void addModuleInfoSnapshot(final OSGiModuleInfoSnapshot snapshot) {
146         instances.add(snapshot);
147     }
148
149     synchronized void removeModuleInfoSnapshot(final OSGiModuleInfoSnapshot snapshot) {
150         instances.remove(snapshot);
151     }
152
153     @Activate
154     synchronized void activate() {
155         LOG.info("Binding Runtime activating");
156         instances = instances.toActive(generator, contextFactory);
157         LOG.info("Binding Runtime activated");
158     }
159
160     @Deactivate
161     synchronized void deactivate() {
162         LOG.info("Binding Runtime deactivating");
163         instances = instances.toInactive();
164         LOG.info("Binding Runtime deactivated");
165     }
166 }