2 * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.binding.runtime.osgi.impl;
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.IdentityHashMap;
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;
36 @Component(immediate = true)
37 public final class OSGiBindingRuntime {
38 // TODO: can we get rid of this complexity?
39 private abstract static class AbstractInstances {
41 abstract void add(OSGiModuleInfoSnapshot snapshot);
43 abstract void remove(OSGiModuleInfoSnapshot snapshot);
45 abstract @NonNull AbstractInstances toActive(BindingRuntimeGenerator generator,
46 ComponentFactory<OSGiBindingRuntimeContextImpl> factory);
48 abstract @NonNull AbstractInstances toInactive();
51 private static final class InactiveInstances extends AbstractInstances {
52 private final Set<OSGiModuleInfoSnapshot> instances = Collections.newSetFromMap(new IdentityHashMap<>());
58 InactiveInstances(final Set<OSGiModuleInfoSnapshot> keySet) {
59 instances.addAll(keySet);
63 void add(final OSGiModuleInfoSnapshot snapshot) {
64 verify(instances.add(snapshot), "Duplicate instance %s?!", snapshot);
68 void remove(final OSGiModuleInfoSnapshot snapshot) {
69 instances.remove(snapshot);
73 AbstractInstances toActive(final BindingRuntimeGenerator generator,
74 final ComponentFactory<OSGiBindingRuntimeContextImpl> factory) {
75 final ActiveInstances active = new ActiveInstances(generator, factory);
77 .sorted(Comparator.comparing(OSGiModuleInfoSnapshot::getGeneration).reversed())
78 .forEach(active::add);
83 AbstractInstances toInactive() {
84 throw new IllegalStateException("Attempted to deactivate inactive instances");
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;
94 ActiveInstances(final BindingRuntimeGenerator generator,
95 final ComponentFactory<OSGiBindingRuntimeContextImpl> factory) {
96 this.generator = requireNonNull(generator);
97 this.factory = requireNonNull(factory);
101 void add(final OSGiModuleInfoSnapshot snapshot) {
102 final var infoSnapshot = snapshot.getService();
103 final var types = generator.generateTypeMapping(infoSnapshot.modelContext());
105 instances.put(snapshot, factory.newInstance(OSGiBindingRuntimeContextImpl.props(
106 snapshot.getGeneration(), snapshot.getServiceRanking(),
107 new DefaultBindingRuntimeContext(types, infoSnapshot))));
111 void remove(final OSGiModuleInfoSnapshot snapshot) {
112 final var instance = instances.remove(snapshot);
113 if (instance != null) {
116 LOG.warn("Instance for generation {} not found", snapshot.getGeneration());
121 AbstractInstances toActive(final BindingRuntimeGenerator ignoreGenerator,
122 final ComponentFactory<OSGiBindingRuntimeContextImpl> ignoreFactory) {
123 throw new IllegalStateException("Attempted to activate active instances");
127 AbstractInstances toInactive() {
128 instances.values().forEach(ComponentInstance::dispose);
129 return new InactiveInstances(instances.keySet());
133 private static final Logger LOG = LoggerFactory.getLogger(OSGiBindingRuntime.class);
136 BindingRuntimeGenerator generator = null;
138 @Reference(target = "(component.factory=" + OSGiBindingRuntimeContextImpl.FACTORY_NAME + ")")
139 ComponentFactory<OSGiBindingRuntimeContextImpl> contextFactory = null;
142 private AbstractInstances instances = new InactiveInstances();
144 @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
145 synchronized void addModuleInfoSnapshot(final OSGiModuleInfoSnapshot snapshot) {
146 instances.add(snapshot);
149 synchronized void removeModuleInfoSnapshot(final OSGiModuleInfoSnapshot snapshot) {
150 instances.remove(snapshot);
154 synchronized void activate() {
155 LOG.info("Binding Runtime activating");
156 instances = instances.toActive(generator, contextFactory);
157 LOG.info("Binding Runtime activated");
161 synchronized void deactivate() {
162 LOG.info("Binding Runtime deactivating");
163 instances = instances.toInactive();
164 LOG.info("Binding Runtime deactivated");