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.osgi.OSGiBindingDOMCodecServices;
21 import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecFactory;
22 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
23 import org.opendaylight.mdsal.binding.runtime.osgi.OSGiBindingRuntimeContext;
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;
35 @Component(immediate = true)
36 public final class OSGiBindingDOMCodec {
37 // TODO: can we get rid of this complexity?
38 private abstract static class AbstractInstances {
40 abstract void add(OSGiBindingRuntimeContext runtimeContext);
42 abstract void remove(OSGiBindingRuntimeContext runtimeContext);
44 abstract @NonNull AbstractInstances toActive(BindingDOMCodecFactory codecFactory,
45 ComponentFactory<OSGiBindingDOMCodecServices> factory);
47 abstract @NonNull AbstractInstances toInactive();
50 private static final class InactiveInstances extends AbstractInstances {
51 private final Set<OSGiBindingRuntimeContext> instances = Collections.newSetFromMap(new IdentityHashMap<>());
57 InactiveInstances(final Set<OSGiBindingRuntimeContext> keySet) {
58 instances.addAll(keySet);
62 void add(final OSGiBindingRuntimeContext runtimeContext) {
63 verify(instances.add(runtimeContext), "Duplicate instance %s?!", runtimeContext);
67 void remove(final OSGiBindingRuntimeContext runtimeContext) {
68 instances.remove(runtimeContext);
72 AbstractInstances toActive(final BindingDOMCodecFactory codecFactory,
73 final ComponentFactory<OSGiBindingDOMCodecServices> factory) {
74 final ActiveInstances active = new ActiveInstances(codecFactory, factory);
76 .sorted(Comparator.comparing(OSGiBindingRuntimeContext::getGeneration).reversed())
77 .forEach(active::add);
82 AbstractInstances toInactive() {
83 throw new IllegalStateException("Attempted to deactivate inactive instances");
87 private static final class ActiveInstances extends AbstractInstances {
88 private final Map<OSGiBindingRuntimeContext, ComponentInstance<OSGiBindingDOMCodecServices>> instances =
89 new IdentityHashMap<>();
90 private final ComponentFactory<OSGiBindingDOMCodecServices> factory;
91 private final BindingDOMCodecFactory codecFactory;
93 ActiveInstances(final BindingDOMCodecFactory codecFactory,
94 final ComponentFactory<OSGiBindingDOMCodecServices> factory) {
95 this.codecFactory = requireNonNull(codecFactory);
96 this.factory = requireNonNull(factory);
100 void add(final OSGiBindingRuntimeContext runtimeContext) {
101 final BindingRuntimeContext context = runtimeContext.getService();
103 instances.put(runtimeContext, factory.newInstance(OSGiBindingDOMCodecServicesImpl.props(
104 runtimeContext.getGeneration(), runtimeContext.getServiceRanking(),
105 codecFactory.createBindingDOMCodec(context))));
109 void remove(final OSGiBindingRuntimeContext runtimeContext) {
110 final ComponentInstance<OSGiBindingDOMCodecServices> instance = instances.remove(runtimeContext);
111 if (instance != null) {
114 LOG.warn("Instance for generation {} not found", runtimeContext.getGeneration());
119 AbstractInstances toActive(final BindingDOMCodecFactory ignoreCodecFactory,
120 final ComponentFactory<OSGiBindingDOMCodecServices> ignoreFactory) {
121 throw new IllegalStateException("Attempted to activate active instances");
125 AbstractInstances toInactive() {
126 instances.values().forEach(ComponentInstance::dispose);
127 return new InactiveInstances(instances.keySet());
132 private static final Logger LOG = LoggerFactory.getLogger(OSGiBindingDOMCodec.class);
135 BindingDOMCodecFactory codecFactory = null;
137 @Reference(target = "(component.factory=" + OSGiBindingDOMCodecServicesImpl.FACTORY_NAME + ")")
138 ComponentFactory<OSGiBindingDOMCodecServices> contextFactory = null;
141 private AbstractInstances instances = new InactiveInstances();
143 @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
144 synchronized void addModuleInfoSnapshot(final OSGiBindingRuntimeContext runtimeContext) {
145 instances.add(runtimeContext);
148 synchronized void removeModuleInfoSnapshot(final OSGiBindingRuntimeContext runtimeContext) {
149 instances.remove(runtimeContext);
153 synchronized void activate() {
154 LOG.info("Binding/DOM Codec activating");
155 instances = instances.toActive(codecFactory, contextFactory);
156 LOG.info("Binding/DOM Codec activated");
160 synchronized void deactivate() {
161 LOG.info("Binding/DOM Codec deactivating");
162 instances = instances.toInactive();
163 LOG.info("Binding/DOM Codec deactivated");