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.BindingRuntimeTypes;
23 import org.opendaylight.mdsal.binding.runtime.api.DefaultBindingRuntimeContext;
24 import org.opendaylight.mdsal.binding.runtime.api.ModuleInfoSnapshot;
25 import org.opendaylight.mdsal.dom.schema.osgi.OSGiModuleInfoSnapshot;
26 import org.osgi.service.component.ComponentFactory;
27 import org.osgi.service.component.ComponentInstance;
28 import org.osgi.service.component.annotations.Activate;
29 import org.osgi.service.component.annotations.Component;
30 import org.osgi.service.component.annotations.Deactivate;
31 import org.osgi.service.component.annotations.Reference;
32 import org.osgi.service.component.annotations.ReferenceCardinality;
33 import org.osgi.service.component.annotations.ReferencePolicy;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 @Component(immediate = true)
39 public final class OSGiBindingRuntime {
40 // TODO: can we get rid of this complexity?
41 private abstract static class AbstractInstances {
43 abstract void add(OSGiModuleInfoSnapshot snapshot);
45 abstract void remove(OSGiModuleInfoSnapshot snapshot);
47 abstract @NonNull AbstractInstances toActive(BindingRuntimeGenerator generator,
48 ComponentFactory<OSGiBindingRuntimeContextImpl> factory);
50 abstract @NonNull AbstractInstances toInactive();
53 private static final class InactiveInstances extends AbstractInstances {
54 private final Set<OSGiModuleInfoSnapshot> instances = Collections.newSetFromMap(new IdentityHashMap<>());
60 InactiveInstances(final Set<OSGiModuleInfoSnapshot> keySet) {
61 instances.addAll(keySet);
65 void add(final OSGiModuleInfoSnapshot snapshot) {
66 verify(instances.add(snapshot), "Duplicate instance %s?!", snapshot);
70 void remove(final OSGiModuleInfoSnapshot snapshot) {
71 instances.remove(snapshot);
75 AbstractInstances toActive(final BindingRuntimeGenerator generator,
76 final ComponentFactory<OSGiBindingRuntimeContextImpl> factory) {
77 final ActiveInstances active = new ActiveInstances(generator, factory);
79 .sorted(Comparator.comparing(OSGiModuleInfoSnapshot::getGeneration).reversed())
80 .forEach(active::add);
85 AbstractInstances toInactive() {
86 throw new IllegalStateException("Attempted to deactivate inactive instances");
90 private static final class ActiveInstances extends AbstractInstances {
91 private final Map<OSGiModuleInfoSnapshot, ComponentInstance<OSGiBindingRuntimeContextImpl>> instances =
92 new IdentityHashMap<>();
93 private final BindingRuntimeGenerator generator;
94 private final ComponentFactory<OSGiBindingRuntimeContextImpl> factory;
96 ActiveInstances(final BindingRuntimeGenerator generator,
97 final ComponentFactory<OSGiBindingRuntimeContextImpl> factory) {
98 this.generator = requireNonNull(generator);
99 this.factory = requireNonNull(factory);
103 void add(final OSGiModuleInfoSnapshot snapshot) {
104 final ModuleInfoSnapshot context = snapshot.getService();
105 final BindingRuntimeTypes types = generator.generateTypeMapping(context.getEffectiveModelContext());
107 instances.put(snapshot, factory.newInstance(OSGiBindingRuntimeContextImpl.props(
108 snapshot.getGeneration(), snapshot.getServiceRanking(),
109 new DefaultBindingRuntimeContext(types, context))));
113 void remove(final OSGiModuleInfoSnapshot snapshot) {
114 final var instance = instances.remove(snapshot);
115 if (instance != null) {
118 LOG.warn("Instance for generation {} not found", snapshot.getGeneration());
123 AbstractInstances toActive(final BindingRuntimeGenerator ignoreGenerator,
124 final ComponentFactory<OSGiBindingRuntimeContextImpl> ignoreFactory) {
125 throw new IllegalStateException("Attempted to activate active instances");
129 AbstractInstances toInactive() {
130 instances.values().forEach(ComponentInstance::dispose);
131 return new InactiveInstances(instances.keySet());
135 private static final Logger LOG = LoggerFactory.getLogger(OSGiBindingRuntime.class);
138 BindingRuntimeGenerator generator = null;
140 @Reference(target = "(component.factory=" + OSGiBindingRuntimeContextImpl.FACTORY_NAME + ")")
141 ComponentFactory<OSGiBindingRuntimeContextImpl> contextFactory = null;
144 private AbstractInstances instances = new InactiveInstances();
146 @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
147 synchronized void addModuleInfoSnapshot(final OSGiModuleInfoSnapshot snapshot) {
148 instances.add(snapshot);
151 synchronized void removeModuleInfoSnapshot(final OSGiModuleInfoSnapshot snapshot) {
152 instances.remove(snapshot);
156 synchronized void activate() {
157 LOG.info("Binding Runtime activating");
158 instances = instances.toActive(generator, contextFactory);
159 LOG.info("Binding Runtime activated");
163 synchronized void deactivate() {
164 LOG.info("Binding Runtime deactivating");
165 instances = instances.toInactive();
166 LOG.info("Binding Runtime deactivated");