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.dom.codec.osgi.impl;
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
13 import java.util.Collections;
14 import java.util.Comparator;
15 import java.util.IdentityHashMap;
18 import org.checkerframework.checker.lock.qual.GuardedBy;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecFactory;
21 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
22 import org.opendaylight.mdsal.binding.runtime.osgi.OSGiBindingRuntimeContext;
23 import org.osgi.service.component.ComponentFactory;
24 import org.osgi.service.component.ComponentInstance;
25 import org.osgi.service.component.annotations.Activate;
26 import org.osgi.service.component.annotations.Component;
27 import org.osgi.service.component.annotations.Deactivate;
28 import org.osgi.service.component.annotations.Reference;
29 import org.osgi.service.component.annotations.ReferenceCardinality;
30 import org.osgi.service.component.annotations.ReferencePolicy;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 @Component(immediate = true)
35 public final class OSGiBindingDOMCodec {
36 // TODO: can we get rid of this complexity?
37 private abstract static class AbstractInstances {
39 abstract void add(OSGiBindingRuntimeContext runtimeContext);
41 abstract void remove(OSGiBindingRuntimeContext runtimeContext);
43 abstract @NonNull AbstractInstances toActive(BindingDOMCodecFactory codecFactory, ComponentFactory factory);
45 abstract @NonNull AbstractInstances toInactive();
48 private static final class InactiveInstances extends AbstractInstances {
49 private final Set<OSGiBindingRuntimeContext> instances = Collections.newSetFromMap(new IdentityHashMap<>());
55 InactiveInstances(final Set<OSGiBindingRuntimeContext> keySet) {
56 instances.addAll(keySet);
60 void add(final OSGiBindingRuntimeContext runtimeContext) {
61 verify(instances.add(runtimeContext), "Duplicate instance %s?!", runtimeContext);
65 void remove(final OSGiBindingRuntimeContext runtimeContext) {
66 instances.remove(runtimeContext);
70 AbstractInstances toActive(final BindingDOMCodecFactory codecFactory, final ComponentFactory factory) {
71 final ActiveInstances active = new ActiveInstances(codecFactory, factory);
73 .sorted(Comparator.comparing(OSGiBindingRuntimeContext::getGeneration).reversed())
74 .forEach(active::add);
79 AbstractInstances toInactive() {
80 throw new IllegalStateException("Attempted to deactivate inactive instances");
84 private static final class ActiveInstances extends AbstractInstances {
85 private final Map<OSGiBindingRuntimeContext, ComponentInstance> instances = new IdentityHashMap<>();
86 private final BindingDOMCodecFactory codecFactory;
87 private final ComponentFactory factory;
89 ActiveInstances(final BindingDOMCodecFactory codecFactory, final ComponentFactory factory) {
90 this.codecFactory = requireNonNull(codecFactory);
91 this.factory = requireNonNull(factory);
95 void add(final OSGiBindingRuntimeContext runtimeContext) {
96 final BindingRuntimeContext context = runtimeContext.getService();
98 instances.put(runtimeContext, factory.newInstance(OSGiBindingDOMCodecServicesImpl.props(
99 runtimeContext.getGeneration(), runtimeContext.getServiceRanking(),
100 codecFactory.createBindingDOMCodec(context))));
104 void remove(final OSGiBindingRuntimeContext runtimeContext) {
105 final ComponentInstance instance = instances.remove(runtimeContext);
106 if (instance != null) {
109 LOG.warn("Instance for generation {} not found", runtimeContext.getGeneration());
114 AbstractInstances toActive(final BindingDOMCodecFactory ignoreCodecFactory,
115 final ComponentFactory ignoreFactory) {
116 throw new IllegalStateException("Attempted to activate active instances");
120 AbstractInstances toInactive() {
121 instances.values().forEach(ComponentInstance::dispose);
122 return new InactiveInstances(instances.keySet());
127 private static final Logger LOG = LoggerFactory.getLogger(OSGiBindingDOMCodec.class);
130 BindingDOMCodecFactory codecFactory = null;
132 @Reference(target = "(component.factory=" + OSGiBindingDOMCodecServicesImpl.FACTORY_NAME + ")")
133 ComponentFactory contextFactory = null;
136 private AbstractInstances instances = new InactiveInstances();
138 @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
139 synchronized void addModuleInfoSnapshot(final OSGiBindingRuntimeContext runtimeContext) {
140 instances.add(runtimeContext);
143 synchronized void removeModuleInfoSnapshot(final OSGiBindingRuntimeContext runtimeContext) {
144 instances.remove(runtimeContext);
148 synchronized void activate() {
149 LOG.info("Binding/DOM Codec activating");
150 instances = instances.toActive(codecFactory, contextFactory);
151 LOG.info("Binding/DOM Codec activated");
155 synchronized void deactivate() {
156 LOG.info("Binding/DOM Codec deactivating");
157 instances = instances.toInactive();
158 LOG.info("Binding/DOM Codec deactivated");